diff -Nru a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt
--- a/Documentation/DMA-mapping.txt	Sat Dec 21 20:36:48 2002
+++ b/Documentation/DMA-mapping.txt	Thu May 29 22:42:44 2003
@@ -83,6 +83,15 @@
 to be increased.  And for a device with limitations, as discussed in
 the previous paragraph, it needs to be decreased.
 
+pci_alloc_consistent() by default will return 32-bit DMA addresses.
+PCI-X specification requires PCI-X devices to support 64-bit
+addressing (DAC) for all transactions. And at least one platform (SGI
+SN2) requires 64-bit consistent allocations to operate correctly when
+the IO bus is in PCI-X mode. Therefore, like with pci_set_dma_mask(),
+it's good practice to call pci_set_consistent_dma_mask() to set the
+appropriate mask even if your device only supports 32-bit DMA
+(default) and especially if it's a PCI-X device.
+
 For correct operation, you must interrogate the PCI layer in your
 device probe routine to see if the PCI controller on the machine can
 properly support the DMA addressing limitation your device has.  It is
@@ -94,6 +103,11 @@
 
 	int pci_set_dma_mask(struct pci_dev *pdev, u64 device_mask);
 
+The query for consistent allocations is performed via a a call to
+pci_set_consistent_dma_mask():
+
+	int pci_set_consistent_dma_mask(struct pci_dev *pdev, u64 device_mask);
+
 Here, pdev is a pointer to the PCI device struct of your device, and
 device_mask is a bit mask describing which bits of a PCI address your
 device supports.  It returns zero if your card can perform DMA
@@ -133,7 +147,7 @@
 Sparc64 is one platform which behaves in this way.
 
 Here is how you would handle a 64-bit capable device which can drive
-all 64-bits during a DAC cycle:
+all 64-bits when accessing streaming DMA:
 
 	int using_dac;
 
@@ -147,6 +161,30 @@
 		goto ignore_this_device;
 	}
 
+If a card is capable of using 64-bit consistent allocations as well,
+the case would look like this:
+
+	int using_dac, consistent_using_dac;
+
+	if (!pci_set_dma_mask(pdev, 0xffffffffffffffff)) {
+		using_dac = 1;
+	   	consistent_using_dac = 1;
+		pci_set_consistent_dma_mask(pdev, 0xffffffffffffffff)
+	} else if (!pci_set_dma_mask(pdev, 0xffffffff)) {
+		using_dac = 0;
+		consistent_using_dac = 0;
+		pci_set_consistent_dma_mask(pdev, 0xffffffff)
+	} else {
+		printk(KERN_WARNING
+		       "mydev: No suitable DMA available.\n");
+		goto ignore_this_device;
+	}
+
+pci_set_consistent_dma_mask() will always be able to set the same or a
+smaller mask as pci_set_dma_mask(). However for the rare case that a
+device driver only uses consistent allocations, one would have to
+check the return value from pci_set_consistent().
+
 If your 64-bit device is going to be an enormous consumer of DMA
 mappings, this can be problematic since the DMA mappings are a
 finite resource on many platforms.  Please see the "DAC Addressing
@@ -215,9 +253,10 @@
 
   Think of "consistent" as "synchronous" or "coherent".
 
-  Consistent DMA mappings are always SAC addressable.  That is
-  to say, consistent DMA addresses given to the driver will always
-  be in the low 32-bits of the PCI bus space.
+  The current default is to return consistent memory in the low 32
+  bits of the PCI bus space.  However, for future compatibility you
+  should set the consistent mask even if this default is fine for your
+  driver.
 
   Good examples of what to use consistent mappings for are:
 
@@ -287,15 +326,14 @@
 driver needs regions sized smaller than a page, you may prefer using
 the pci_pool interface, described below.
 
-The consistent DMA mapping interfaces, for non-NULL dev, will always
-return a DMA address which is SAC (Single Address Cycle) addressable.
-Even if the device indicates (via PCI dma mask) that it may address
-the upper 32-bits and thus perform DAC cycles, consistent allocation
-will still only return 32-bit PCI addresses for DMA.  This is true
-of the pci_pool interface as well.
-
-In fact, as mentioned above, all consistent memory provided by the
-kernel DMA APIs are always SAC addressable.
+The consistent DMA mapping interfaces, for non-NULL dev, will by
+default return a DMA address which is SAC (Single Address Cycle)
+addressable.  Even if the device indicates (via PCI dma mask) that it
+may address the upper 32-bits and thus perform DAC cycles, consistent
+allocation will only return > 32-bit PCI addresses for DMA if the
+consistent dma mask has been explicitly changed via
+pci_set_consistent_dma_mask().  This is true of the pci_pool interface
+as well.
 
 pci_alloc_consistent returns two values: the virtual address which you
 can use to access it from the CPU and dma_handle which you pass to the
diff -Nru a/Documentation/filesystems/fat_cvf.txt b/Documentation/filesystems/fat_cvf.txt
--- a/Documentation/filesystems/fat_cvf.txt	Mon Feb  4 23:49:25 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,210 +0,0 @@
-This is the main documentation for the CVF-FAT filesystem extension.  18Nov1998
-
-
-Table of Contents:
-
-1. The idea of CVF-FAT
-2. Restrictions
-3. Mount options
-4. Description of the CVF-FAT interface
-5. CVF Modules
-
-------------------------------------------------------------------------------
-
-
-1. The idea of CVF-FAT
-------------------------------------------------------------------------------
-
-CVF-FAT is a FAT filesystem extension that provides a generic interface for
-Compressed Volume Files in FAT partitions. Popular CVF software, for
-example, are Microsoft's Doublespace/Drivespace and Stac's Stacker.
-Using the CVF-FAT interface, it is possible to load a module that handles
-all the low-level disk access that has to do with on-the-fly compression
-and decompression. Any other part of FAT filesystem access is still handled
-by the FAT, MSDOS or VFAT or even UMSDOS driver.
-
-CVF access works by redirecting certain low-level routines from the FAT
-driver to a loadable, CVF-format specific module. This module must fake
-a normal FAT filesystem to the FAT driver while doing all the extra stuff
-like compression and decompression silently.
-
-
-2. Restrictions
-------------------------------------------------------------------------------
-
-- BMAP problems
-
-  CVF filesystems cannot do bmap. It's impossible in principle. Thus
-  all actions that require bmap do not work (swapping, writable mmapping).
-  Read-only mmapping works because the FAT driver has a hack for this
-  situation :) Well, writable mmapping should now work using the readpage
-  interface function which has been hacked into the FAT driver just for 
-  CVF-FAT :)
-  
-- attention, DOSEmu users 
-
-  You may have to unmount all CVF partitions before running DOSEmu depending 
-  on your configuration. If DOSEmu is configured to use wholedisk or 
-  partition access (this is often the case to let DOSEmu access 
-  compressed partitions) there's a risk of destroying your compressed 
-  partitions or crashing your system because of confused drivers.
-  
-  Note that it is always safe to redirect the compressed partitions with 
-  lredir or emufs.sys. Refer to the DOSEmu documentation for details.
-
-
-3. Mount options
-------------------------------------------------------------------------------
-
-The CVF-FAT extension currently adds the following options to the FAT
-driver's standard options:
-
-  cvf_format=xxx
-    Forces the driver to use the CVF module "xxx" instead of auto-detection.
-    Without this option, the CVF-FAT interface asks all currently loaded
-    CVF modules whether they recognize the CVF. Therefore, this option is
-    only necessary if the CVF format is not recognized correctly
-    because of bugs or incompatibilities in the CVF modules. (It skips
-    the detect_cvf call.) "xxx" may be the text "none" (without the quotes)
-    to inhibit using any of the loaded CVF modules, just in case a CVF
-    module insists on mounting plain FAT filesystems by misunderstanding.
-    "xxx" may also be the text "autoload", which has a special meaning for
-    a module loader, but does not skip auto-detection.
-
-    If the kernel supports kmod, the cvf_format=xxx option also controls
-    on-demand CVF module loading. Without this option, nothing is loaded
-    on demand. With cvf_format=xxx, a module "xxx" is requested automatically
-    before mounting the compressed filesystem (unless "xxx" is "none"). In 
-    case there is a difference between the CVF format name and the module 
-    name, setup aliases in your modules configuration. If the string "xxx" 
-    is "autoload", a non-existent module "cvf_autoload" is requested which 
-    can be used together with a special modules configuration (alias and 
-    pre-install statements) in order to load more than one CVF module, let 
-    them detect automatically which kind of CVF is to be mounted, and only 
-    keep the "right" module in memory. For examples please refer to the 
-    dmsdos documentation (ftp and http addresses see below).
-
-  cvf_options=yyy
-    Option string passed to the CVF module. I.e. only the "yyy" is passed
-    (without the quotes). The documentation for each CVF module should 
-    explain it since it is interpreted only by the CVF module. Note that 
-    the string must not contain a comma (",") - this would lead to 
-    misinterpretation by the FAT driver, which would recognize the text 
-    after a comma as a FAT driver option and might get confused or print 
-    strange error messages. The documentation for the CVF module should 
-    offer a different separation symbol, for example the dot "." or the
-    plus sign "+", which is only valid inside the string "yyy".
-
-
-4. Description of the CVF-FAT interface
-------------------------------------------------------------------------------
-
-Assuming you want to write your own CVF module, you need to write a lot of
-interface functions. Most of them are covered in the kernel documentation
-you can find on the net, and thus won't be described here. They have been
-marked with "[...]" :-) Take a look at include/linux/fat_cvf.h.
-
-struct cvf_format
-{ int cvf_version;
-  char* cvf_version_text;
-  unsigned long int flags;
-  int (*detect_cvf) (struct super_block*sb);
-  int (*mount_cvf) (struct super_block*sb,char*options);
-  int (*unmount_cvf) (struct super_block*sb);
-  [...]
-  void (*zero_out_cluster) (struct inode*, int clusternr);
-}
-
-This structure defines the capabilities of a CVF module. It must be filled
-out completely by a CVF module. Consider it as a kind of form that is used
-to introduce the module to the FAT/CVF-FAT driver.
-
-It contains...
-  - cvf_version:
-      A version id which must be unique. Choose one.
-  - cvf_version_text:
-      A human readable version string that should be one short word 
-      describing the CVF format the module implements. This text is used
-      for the cvf_format option. This name must also be unique.
-  - flags:
-      Bit coded flags, currently only used for a readpage/mmap hack that 
-      provides both mmap and readpage functionality. If CVF_USE_READPAGE
-      is set, mmap is set to generic_file_mmap and readpage is caught
-      and redirected to the cvf_readpage function. If it is not set,
-      readpage is set to generic_readpage and mmap is caught and redirected
-      to cvf_mmap. (If you want writable mmap use the readpage interface.)
-  - detect_cvf:
-      A function that is called to decide whether the filesystem is a CVF of
-      the type the module supports. The detect_cvf function must return 0
-      for "NO, I DON'T KNOW THIS GARBAGE" or anything >0 for "YES, THIS IS
-      THE KIND OF CVF I SUPPORT". The function must maintain the module
-      usage counters for safety, i.e. do MOD_INC_USE_COUNT at the beginning
-      and MOD_DEC_USE_COUNT at the end. The function *must not* assume that
-      successful recognition would lead to a call of the mount_cvf function
-      later. 
-  - mount_cvf:
-      A function that sets up some values or initializes something additional
-      to what has to be done when a CVF is mounted. This is called at the
-      end of fat_read_super and must return 0 on success. Definitely, this
-      function must increment the module usage counter by MOD_INC_USE_COUNT.
-      This mount_cvf function is also responsible for interpreting a CVF
-      module specific option string (the "yyy" from the FAT mount option
-      "cvf_options=yyy") which cannot contain a comma (use for example the
-      dot "." as option separator symbol).
-  - unmount_cvf:
-      A function that is called when the filesystem is unmounted. Most likely
-      it only frees up some memory and calls MOD_DEC_USE_COUNT. The return
-      value might be ignored (it currently is ignored).
-  - [...]:
-      All other interface functions are "caught" FAT driver functions, i.e.
-      are executed by the FAT driver *instead* of the original FAT driver
-      functions. NULL means use the original FAT driver functions instead.
-      If you really want "no action", write a function that does nothing and 
-      hang it in instead.
-  - zero_out_cluster:
-      The zero_out_cluster function is called when the fat driver wants to
-      zero out a (new) cluster. This is important for directories (mkdir).
-      If it is NULL, the FAT driver defaults to overwriting the whole
-      cluster with zeros. Note that clusternr is absolute, not relative
-      to the provided inode.
-
-Notes:
-  1. The cvf_bmap function should be ignored. It really should never
-     get called from somewhere. I recommend redirecting it to a panic
-     or fatal error message so bugs show up immediately.
-  2. The cvf_writepage function is ignored. This is because the fat
-     driver doesn't support it. This might change in future. I recommend
-     setting it to NULL (i.e use default).
-
-int register_cvf_format(struct cvf_format*cvf_format);
-  If you have just set up a variable containing the above structure,
-  call this function to introduce your CVF format to the FAT/CVF-FAT
-  driver. This is usually done in init_module. Be sure to check the
-  return value. Zero means success, everything else causes a kernel
-  message printed in the syslog describing the error that occurred.
-  Typical errors are:
-    - a module with the same version id is already registered or 
-    - too many CVF formats. Hack fs/fat/cvf.c if you need more.
-
-int unregister_cvf_format(struct cvf_format*cvf_format);
-  This is usually called in cleanup_module. Return value =0 means
-  success. An error only occurs if you try to unregister a CVF format
-  that has not been previously registered. The code uses the version id
-  to distinguish the modules, so be sure to keep it unique.
-
-5. CVF Modules
-------------------------------------------------------------------------------
-
-Refer to the dmsdos module (the successor of the dmsdos filesystem) for a
-sample implementation.  It can currently be found at
-
-  ftp://fb9nt.uni-duisburg.de/pub/linux/dmsdos/dmsdos-x.y.z.tgz
-  ftp://sunsite.unc.edu/pub/Linux/system/Filesystems/dosfs/dmsdos-x.y.z.tgz
-  ftp://ftp.uni-stuttgart.de/pub/systems/linux/local/system/dmsdos-x.y.z.tgz
-
-(where x.y.z is to be replaced with the actual version number). Full
-documentation about dmsdos is included in the dmsdos package, but can also
-be found at
-
-  http://fb9nt.uni-duisburg.de/mitarbeiter/gockel/software/dmsdos/index.html
-  http://www.yk.rim.or.jp/~takafumi/dmsdos/index.html (in Japanese).
diff -Nru a/Documentation/scsi/aic7xxx.txt b/Documentation/scsi/aic7xxx.txt
--- a/Documentation/scsi/aic7xxx.txt	Thu May  1 10:04:05 2003
+++ b/Documentation/scsi/aic7xxx.txt	Wed May 14 15:22:44 2003
@@ -132,6 +132,11 @@
 
 2. Version History
 
+        6.2.34 - Fix locking regression instroduced in 6.2.29 that
+                 could cuase a lock order reversal between the io_request_lock
+                 and our per-softc lock.  This was only possible on RH9,
+                 SuSE, and kernel.org 2.4.X kernels.
+
         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
diff -Nru a/Documentation/scsi/dc395x.txt b/Documentation/scsi/dc395x.txt
--- a/Documentation/scsi/dc395x.txt	Sat Apr 26 14:17:46 2003
+++ b/Documentation/scsi/dc395x.txt	Fri May 23 15:57:18 2003
@@ -23,40 +23,70 @@
 Both can be overriden by command line parameters (module or kernel
 parameters).
 
-The syntax is as follows:
- dc395x = AdapterID, SpeedIdx, DevMode, AdaptMode, Tags, DelayReset
+The following parameters are available:
 
-AdapterID : Host Adapter SCSI ID
-SpeedIdx  : 0,1,...7 = 20,13.3,10,8,6.7,5.8,5,4 MHz               [ 7]
-DevMode   : Bitmap for Dev Cfg                                    [63]
-AdaptMode : Bitmap for Adapter Cfg                                [47]
-Tags      : The number of tags is 1<<x, if x has been specified   [ 4]
-DelayReset: The seconds to not accept commands after a SCSI Reset [ 1]
-
-DevMode bit definition:
-   Bit Val(hex) Val(dec)  Meaning
-   *0	 0x01	    1	  Parity check
-   *1	 0x02	    2	  Synchronous Negotiation
-   *2	 0x04	    4	  Disconnection
-   *3	 0x08	    8	  Send Start command on startup. (Not used)
-   *4	 0x10	   16	  Tagged Command Queueing
-   *5	 0x20	   32	  Wide Negotiation
-
-AdaptMode bit definition
-   Bit Val(hex) Val(dec)  Meaning
-   *0	 0x01	    1	  Support more than two drives. (Not used)
-   *1	 0x02	    2	  Use DOS compatible mapping for HDs greater than 1GB.
-   *2	 0x04	    4	  Reset SCSI Bus on startup.
-   *3	 0x08	    8	  Active Negation: Improves SCSI Bus noise immunity.
-    4	 0x10	   16	  Immediate return on BIOS seek command. (Not used)
- (*)5	 0x20	   32	  Check for LUNs >= 1.
-
-If you set AdapterID to -1, the adapter will use conservative
-("safe") default settings instead; more precisely, dc395x=-1 is a
-shortcut for dc395x=7,4,9,15,2,10
+ - safe
+   Default: 0, Acceptable values: 0 or 1
+
+   If safe is set to 1 then the adapter will use conservative
+   ("safe") default settings. This sets:
+
+		shortcut for dc395x=7,4,9,15,2,10
+
+ - adapter_id
+   Default: 7, Acceptable values: 0 to 15
+
+   Sets the host adapter SCSI ID.
+
+ - max_speed
+   Default: 1, Acceptable value: 0 to 7
+   0 = 20   Mhz
+   1 = 12.2 Mhz
+   2 = 10   Mhz
+   3 = 8    Mhz
+   4 = 6.7  Mhz
+   5 = 5.8  Hhz
+   6 = 5    Mhz
+   7 = 4    Mhz
+
+ - dev_mode
+   Bitmap for device configuration
+
+   DevMode bit definition:
+      Bit Val(hex) Val(dec)  Meaning
+      *0    0x01       1     Parity check
+      *1    0x02       2     Synchronous Negotiation
+      *2    0x04       4     Disconnection
+      *3    0x08       8     Send Start command on startup. (Not used)
+      *4    0x10      16     Tagged Command Queueing
+      *5    0x20      32     Wide Negotiation
+
+ - adapter_mode
+   Bitmap for adapter configuration
+
+   AdaptMode bit definition
+      Bit Val(hex) Val(dec)  Meaning
+      *0    0x01       1     Support more than two drives. (Not used)
+      *1    0x02       2     Use DOS compatible mapping for HDs greater than 1GB.
+      *2    0x04       4     Reset SCSI Bus on startup.
+      *3    0x08       8     Active Negation: Improves SCSI Bus noise immunity.
+       4    0x10      16     Immediate return on BIOS seek command. (Not used)
+    (*)5    0x20      32     Check for LUNs >= 1.
+
+ - tags
+   Default: 3, Acceptable values: 0-5
+   
+   The number of tags is 1<<x, if x has been specified
+
+ - reset_delay
+   Default: 1, Acceptable values: 0-180
+
+   The seconds to not accept commands after a SCSI Reset
+
+
+For the built  in driver the parameters should be prefixed with
+dc395x. (eg "dc395x.safe=1")
 
-If you specify -2 for a value, it will be ignored. You don't need to
-specify all six parameters.
 
 Copyright
 ---------
diff -Nru a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt
--- a/Documentation/scsi/scsi_mid_low_api.txt	Mon Apr 21 07:42:33 2003
+++ b/Documentation/scsi/scsi_mid_low_api.txt	Mon Apr 28 16:34:05 2003
@@ -22,7 +22,10 @@
 a SCSI host and a PCI device is common but not required (e.g. with
 ISA or MCA adapters).]
 
-This version of the document roughly matches linux kernel version 2.5.67 .
+This version of the document roughly matches linux kernel version 2.5.68 .
+This document can be found in the Linux kernel source Documentation/scsi
+directory and is called scsi_mid_low_api.txt . A more recent copy may
+be found at http://www.torque.net/scsi/scsi_mid_low_api.txt.gz .
 
 Documentation
 =============
@@ -142,13 +145,14 @@
                     slave_configure() -->  scsi_adjust_queue_depth()
 			 |
 		    slave_alloc()
-                    slave_configure() -->  scsi_adjust_queue_depth()
+                    slave_configure()
 			 |
 		    slave_alloc()   **
                     slave_destroy() **
 
-The invocation of scsi_adjust_queue_depth() by the LLD is required
-if slave_configure() is supplied.
+If the LLD wants to adjust the default queue settings, it can invoke
+scsi_adjust_queue_depth() in its slave_configure() routine.
+
 ** For scsi devices that the mid level tries to scan but do not
    respond, a slave_alloc(), slave_destroy() pair is called.
 
@@ -179,7 +183,7 @@
 scsi_add_device()  ------+
                          |
 		    slave_alloc()
-                    slave_configure() -->  scsi_adjust_queue_depth()
+                    slave_configure()   [--> scsi_adjust_queue_depth()]
 
 [DEVICE unplug]
 LLD                      mid level                 LLD
@@ -228,13 +232,14 @@
 		      slave_destroy() **
                             |
 		      slave_alloc()
-                      slave_configure()  -->  scsi_adjust_queue_depth()
+                      slave_configure()
 		      slave_alloc()   **
 		      slave_destroy() **
 
-If the LLD does not supply a slave_configure() then the mid level invokes
-scsi_adjust_queue_depth() itself with tagged queuing off and "cmd_per_lun"
-for that host as the queue length.
+The mid level invokes scsi_adjust_queue_depth() with tagged queuing off and
+"cmd_per_lun" for that host as the queue length. These settings can be
+overridden by a slave_configure() supplied by the LLD.
+
 ** For scsi devices that the mid level tries to scan but do not
    respond, a slave_alloc(), slave_destroy() pair is called.
 
@@ -1093,11 +1098,6 @@
  *      Notes: Allows the driver to inspect the response to the initial
  *	INQUIRY done by the scanning code and take appropriate action.
  *	For more details see the hosts.h file.
- *	If this function is not supplied, the mid level will call
- *	scsi_adjust_queue_depth() with the struct Scsi_Host::cmd_per_lun
- *	value on behalf of the given device. If this function is
- *	supplied then its implementation must call
- *	scsi_adjust_queue_depth(). 	
  *
  *	Defined in: LLD
  **/
@@ -1277,8 +1277,9 @@
         Patrick Mansfield <patmans@us.ibm.com> 
 	Christoph Hellwig <hch@infradead.org>
 	Doug Ledford <dledford@redhat.com>
+        Andries Brouwer <Andries.Brouwer@cwi.nl>
 
 
 Douglas Gilbert
 dgilbert@interlog.com
-19th April 2003
+29th April 2003
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Mon May 26 17:57:52 2003
+++ b/Makefile	Fri May 30 04:31:16 2003
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 70
-EXTRAVERSION =
+EXTRAVERSION = -bk4
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
diff -Nru a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
--- a/arch/alpha/kernel/pci.c	Fri Apr  4 12:06:45 2003
+++ b/arch/alpha/kernel/pci.c	Wed May 21 08:28:01 2003
@@ -102,7 +102,7 @@
 {
 	unsigned int class = dev->class >> 8;
 
-	if (class == PCI_CLASS_BRIDGE_ISA || class == PCI_CLASS_BRIDGE_ISA) {
+	if (class == PCI_CLASS_BRIDGE_ISA || class == PCI_CLASS_BRIDGE_EISA) {
 		dev->dma_mask = MAX_ISA_DMA_ADDRESS - 1;
 		isa_bridge = dev;
 	}
diff -Nru a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
--- a/arch/alpha/kernel/ptrace.c	Tue May 20 10:47:24 2003
+++ b/arch/alpha/kernel/ptrace.c	Wed May 21 10:51:52 2003
@@ -366,8 +366,8 @@
 		ret = -EIO;
 		if ((unsigned long) data > _NSIG)
 			break;
-		/* Set single stepping.  */
-		ptrace_set_bpt(child);
+		/* Mark single stepping.  */
+		child->thread_info->bpt_nsaved = -1;
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		wake_up_process(child);
 		child->exit_code = data;
diff -Nru a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
--- a/arch/alpha/kernel/signal.c	Mon Feb 17 00:17:26 2003
+++ b/arch/alpha/kernel/signal.c	Wed May 21 11:17:01 2003
@@ -619,7 +619,10 @@
 	if (!oldset)
 		oldset = &current->blocked;
 
+	/* This lets the debugger run, ... */
 	signr = get_signal_to_deliver(&info, regs, NULL);
+	/* ... so re-check the single stepping. */
+	single_stepping |= ptrace_cancel_bpt(current);
 
 	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
diff -Nru a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
--- a/arch/alpha/kernel/smp.c	Tue May 20 11:25:56 2003
+++ b/arch/alpha/kernel/smp.c	Wed May 21 08:27:23 2003
@@ -417,12 +417,7 @@
 	/* Don't care about the contents of regs since we'll never
 	   reschedule the forked task. */
 	struct pt_regs regs;
-	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);
+	return copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
 }
 
 /*
@@ -441,8 +436,10 @@
 	   wish.  We can't use kernel_thread since we must avoid
 	   rescheduling the child.  */
 	idle = fork_by_hand();
-	if (!idle)
+	if (IS_ERR(idle))
 		panic("failed fork for CPU %d", cpuid);
+
+	wake_up_forked_process(idle);
 
 	init_idle(idle, cpuid);
 	unhash_process(idle);
diff -Nru a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S
--- a/arch/arm/lib/putuser.S	Sat Feb 16 11:00:42 2002
+++ b/arch/arm/lib/putuser.S	Wed May 28 06:17:24 2003
@@ -31,11 +31,11 @@
 
 	.global	__put_user_1
 __put_user_1:
-	bic	r2, sp, #0x1f00
-	bic	r2, r2, #0x00ff
-	ldr	r2, [r2, #TI_ADDR_LIMIT]
-	sub	r2, r2, #1
-	cmp	r0, r2
+	bic	ip, sp, #0x1f00
+	bic	ip, ip, #0x00ff
+	ldr	ip, [ip, #TI_ADDR_LIMIT]
+	sub	ip, ip, #1
+	cmp	r0, ip
 1:	strlsbt	r1, [r0]
 	movls	r0, #0
 	movls	pc, lr
@@ -43,17 +43,17 @@
 
 	.global	__put_user_2
 __put_user_2:
-	bic	r2, sp, #0x1f00
-	bic	r2, r2, #0x00ff
-	ldr	r2, [r2, #TI_ADDR_LIMIT]
-	sub	r2, r2, #2
-	cmp	r0, r2
-	movls	r2, r1, lsr #8
+	bic	ip, sp, #0x1f00
+	bic	ip, ip, #0x00ff
+	ldr	ip, [ip, #TI_ADDR_LIMIT]
+	sub	ip, ip, #2
+	cmp	r0, ip
+	movls	ip, r1, lsr #8
 #ifndef __ARMEB__
 2:	strlsbt	r1, [r0], #1
-3:	strlsbt	r2, [r0]
+3:	strlsbt	ip, [r0]
 #else
-2:	strlsbt	r2, [r0], #1
+2:	strlsbt	ip, [r0], #1
 3:	strlsbt	r1, [r0]
 #endif
 	movls	r0, #0
@@ -62,11 +62,11 @@
 
 	.global	__put_user_4
 __put_user_4:
-	bic	r2, sp, #0x1f00
-	bic	r2, r2, #0x00ff
-	ldr	r2, [r2, #TI_ADDR_LIMIT]
-	sub	r2, r2, #4
-	cmp	r0, r2
+	bic	ip, sp, #0x1f00
+	bic	ip, ip, #0x00ff
+	ldr	ip, [ip, #TI_ADDR_LIMIT]
+	sub	ip, ip, #4
+	cmp	r0, ip
 4:	strlst	r1, [r0]
 	movls	r0, #0
 	movls	pc, lr
diff -Nru a/arch/arm/mm/init.c b/arch/arm/mm/init.c
--- a/arch/arm/mm/init.c	Sun Apr 20 09:14:40 2003
+++ b/arch/arm/mm/init.c	Wed May 28 06:36:31 2003
@@ -47,7 +47,7 @@
 
 #define TABLE_SIZE	((TABLE_OFFSET + PTRS_PER_PTE) * sizeof(pte_t))
 
-struct mmu_gather mmu_gathers[NR_CPUS];
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 extern char _stext, _text, _etext, _end, __init_begin, __init_end;
diff -Nru a/arch/cris/drivers/serial.c b/arch/cris/drivers/serial.c
--- a/arch/cris/drivers/serial.c	Mon Apr 21 20:58:41 2003
+++ b/arch/cris/drivers/serial.c	Mon May 26 15:29:21 2003
@@ -335,13 +335,12 @@
 
 static DECLARE_TASK_QUEUE(tq_serial);
 
-struct tty_driver serial_driver, callout_driver;
+struct tty_driver serial_driver;
 static int serial_refcount;
 
 /* serial subtype definitions */
 #ifndef SERIAL_TYPE_NORMAL
 #define SERIAL_TYPE_NORMAL	1
-#define SERIAL_TYPE_CALLOUT	2
 #endif
 
 /* number of characters left in xmit buffer before we ask for more */
@@ -3017,8 +3016,6 @@
 	 */
 	if (info->flags & ASYNC_NORMAL_ACTIVE)
 		info->normal_termios = *tty->termios;
-	if (info->flags & ASYNC_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -3063,8 +3060,7 @@
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	restore_flags(flags);
 
@@ -3128,7 +3124,7 @@
 	shutdown(info);
 	info->event = 0;
 	info->count = 0;
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -3166,44 +3162,18 @@
 	}
   
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-			return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-			return -EBUSY;
-		info->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-	
-	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 	
-	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -3228,11 +3198,9 @@
 	while (1) {
 		save_flags(flags);
 		cli();
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE)) {
-			/* assert RTS and DTR */
-			e100_rts(info, 1);
-			e100_dtr(info, 1);
-		}
+		/* assert RTS and DTR */
+		e100_rts(info, 1);
+		e100_dtr(info, 1);
 		restore_flags(flags);
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) ||
@@ -3247,8 +3215,7 @@
 #endif
 			break;
 		}
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(info->flags & ASYNC_CLOSING) && do_clocal)
+		if (!(info->flags & ASYNC_CLOSING) && do_clocal)
 			/* && (do_clocal || DCD_IS_ASSERTED) */
 			break;
 		if (signal_pending(current)) {
@@ -3358,16 +3325,10 @@
 	}
 
 	if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->normal_termios;
-		else 
-			*tty->termios = info->callout_termios;
+		*tty->termios = info->normal_termios;
 		change_speed(info);
 	}
 
-	info->session = current->session;
-	info->pgrp = current->pgrp;
-  
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_open ttyS%d successful...\n", info->line);
 #endif
@@ -3538,23 +3499,8 @@
 	serial_driver.read_proc = rs_read_proc;
 #endif
 	  
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	callout_driver = serial_driver;
-	callout_driver.name = "cua";
-	callout_driver.major = TTYAUX_MAJOR;
-	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-#if (LINUX_VERSION_CODE >= 131343)
-	callout_driver.read_proc = 0;
-	callout_driver.proc_entry = 0;
-#endif
-  
 	if (tty_register_driver(&serial_driver))
 		panic("Couldn't register serial driver\n");
-	if (tty_register_driver(&callout_driver))
-		panic("Couldn't register callout driver\n");
   
 	/* do some initializing for the separate ports */
   
@@ -3574,7 +3520,6 @@
 		info->blocked_open = 0;
 		info->tqueue.routine = do_softint;
 		info->tqueue.data = info;
-		info->callout_termios = callout_driver.init_termios;
 		info->normal_termios = serial_driver.init_termios;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
diff -Nru a/arch/cris/drivers/serial.h b/arch/cris/drivers/serial.h
--- a/arch/cris/drivers/serial.h	Tue Feb  5 07:24:37 2002
+++ b/arch/cris/drivers/serial.h	Mon May 26 15:29:21 2003
@@ -78,8 +78,6 @@
 	int			type;  /* PORT_ETRAX */
 	int			count;	    /* # of fd on device */
 	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
 	struct circ_buf		xmit;
 	struct circ_buf		recv;
 	unsigned char		*flag_buf;
@@ -87,7 +85,6 @@
 	struct tq_struct	tqueue;
 	struct async_icount	icount;   /* error-statistics etc.*/
 	struct termios		normal_termios;
-	struct termios		callout_termios;
 #ifdef DECLARE_WAITQUEUE
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
--- a/arch/i386/kernel/io_apic.c	Wed May 14 23:43:55 2003
+++ b/arch/i386/kernel/io_apic.c	Thu May 29 22:42:38 2003
@@ -352,10 +352,16 @@
 	unsigned long allowed_mask;
 	unsigned int new_cpu;
 		
-	if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH && NO_BALANCE_IRQ)
-		return;
-	else if (irqbalance_disabled) 
+	if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH)
+		irqbalance_disabled = NO_BALANCE_IRQ;
+	if (irqbalance_disabled) { 
+		static int warned;
+		if (warned == 0) {
+			printk("irqbalance disabled\n");
+			warned = 1;
+		} 
 		return; 
+	} 
 
 	allowed_mask = cpu_online_map & irq_affinity[irq];
 	new_cpu = move(cpu, allowed_mask, now, 1);
diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
--- a/arch/i386/kernel/setup.c	Mon May 19 11:26:52 2003
+++ b/arch/i386/kernel/setup.c	Thu May 29 22:42:35 2003
@@ -35,6 +35,7 @@
 #include <linux/console.h>
 #include <linux/root_dev.h>
 #include <linux/highmem.h>
+#include <linux/module.h>
 #include <video/edid.h>
 #include <asm/e820.h>
 #include <asm/mpspec.h>
@@ -58,6 +59,7 @@
 struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
 
 unsigned long mmu_cr4_features;
+EXPORT_SYMBOL_GPL(mmu_cr4_features);
 
 int acpi_disabled __initdata = 0;
 
diff -Nru a/arch/i386/kernel/suspend.c b/arch/i386/kernel/suspend.c
--- a/arch/i386/kernel/suspend.c	Sat May 17 14:09:37 2003
+++ b/arch/i386/kernel/suspend.c	Thu May 29 22:42:34 2003
@@ -114,7 +114,7 @@
         cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff;
 
 	load_TR_desc();				/* This does ltr */
-	load_LDT(&current->mm->context);	/* This does lldt */
+	load_LDT(&current->active_mm->context);	/* This does lldt */
 
 	/*
 	 * Now maybe reload the debug registers
diff -Nru a/arch/i386/mach-visws/visws_apic.c b/arch/i386/mach-visws/visws_apic.c
--- a/arch/i386/mach-visws/visws_apic.c	Thu Mar 13 17:23:56 2003
+++ b/arch/i386/mach-visws/visws_apic.c	Thu May 29 22:42:35 2003
@@ -196,7 +196,7 @@
  * enable_irq gets the right irq. This 'master' irq is never directly
  * manipulated by any driver.
  */
-static void piix4_master_intr(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t piix4_master_intr(int irq, void *dev_id, struct pt_regs * regs)
 {
 	int realirq;
 	irq_desc_t *desc;
@@ -254,11 +254,11 @@
 	if (!(desc->status & IRQ_DISABLED))
 		enable_8259A_irq(realirq);
 
-	return;
+	return IRQ_HANDLED;
 
 out_unlock:
 	spin_unlock_irqrestore(&i8259A_lock, flags);
-	return;
+	return IRQ_NONE;
 }
 
 static struct irqaction master_action = {
diff -Nru a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
--- a/arch/ia64/hp/sim/simserial.c	Sat May 10 02:28:45 2003
+++ b/arch/ia64/hp/sim/simserial.c	Mon May 26 15:29:21 2003
@@ -104,7 +104,6 @@
 };
 
 struct tty_driver hp_simserial_driver;
-static struct tty_driver callout_driver;
 static int serial_refcount;
 
 static struct async_struct *IRQ_ports[NR_IRQS];
@@ -689,7 +688,7 @@
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	MOD_DEC_USE_COUNT;
 }
@@ -723,7 +722,7 @@
 
 	info->event = 0;
 	state->count = 0;
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -937,10 +936,7 @@
 
 	if ((info->state->count == 1) &&
 	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->state->normal_termios;
-		else
-			*tty->termios = info->state->callout_termios;
+		*tty->termios = info->state->normal_termios;
 	}
 
 	/*
@@ -952,9 +948,6 @@
 		console = console->next;
 	}
 
-	info->session = current->session;
-	info->pgrp = current->pgrp;
-
 #ifdef SIMSERIAL_DEBUG
 	printk("rs_open ttys%d successful\n", info->line);
 #endif
@@ -1084,22 +1077,9 @@
 		       state->port, state->irq,
 		       uart_config[state->type].name);
 	}
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	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_simserial_driver))
 		panic("Couldn't register simserial driver\n");
-
-	if (tty_register_driver(&callout_driver))
-		panic("Couldn't register callout driver\n");
 
 	return 0;
 }
diff -Nru a/arch/m68knommu/kernel/Makefile b/arch/m68knommu/kernel/Makefile
--- a/arch/m68knommu/kernel/Makefile	Mon Feb  3 14:19:35 2003
+++ b/arch/m68knommu/kernel/Makefile	Sun May 25 21:46:25 2003
@@ -2,7 +2,7 @@
 # Makefile for arch/m68knommu/kernel.
 #
 
-obj-y += entry.o init_task.o ints.o m68k_ksyms.o process.o ptrace.o \
+obj-y += entry.o init_task.o m68k_ksyms.o process.o ptrace.o \
 	 semaphore.o setup.o signal.o syscalltable.o sys_m68k.o time.o \
 	 traps.o
 
diff -Nru a/arch/m68knommu/kernel/ints.c b/arch/m68knommu/kernel/ints.c
--- a/arch/m68knommu/kernel/ints.c	Mon Feb 24 12:31:17 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,271 +0,0 @@
-/*
- * linux/arch/m68knommu/kernel/ints.c -- General interrupt handling code
- *
- * Copyright (C) 1999-2002  Greg Ungerer (gerg@snapgear.com)
- * Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
- *                     Kenneth Albanowski <kjahds@kjahds.com>,
- * Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
- *
- * Based on:
- *
- * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/errno.h>
-#include <linux/config.h>
-#include <linux/seq_file.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/traps.h>
-#include <asm/page.h>
-#include <asm/machdep.h>
-
-/*
- *	This table stores the address info for each vector handler.
- */
-irq_handler_t irq_list[SYS_IRQS];
-
-#define NUM_IRQ_NODES 16
-static irq_node_t nodes[NUM_IRQ_NODES];
-
-/* The number of spurious interrupts */
-volatile unsigned int num_spurious;
-
-unsigned int local_bh_count[NR_CPUS];
-unsigned int local_irq_count[NR_CPUS];
-
-static void default_irq_handler(int irq, void *ptr, struct pt_regs *regs)
-{
-#if 1
-	printk("%s(%d): default irq handler vec=%d [0x%x]\n",
-		__FILE__, __LINE__, irq, irq);
-#endif
-}
-
-/*
- * void init_IRQ(void)
- *
- * Parameters:	None
- *
- * Returns:	Nothing
- *
- * This function should be called during kernel startup to initialize
- * the IRQ handling routines.
- */
-
-void __init init_IRQ(void)
-{
-	int i;
-
-	for (i = 0; i < SYS_IRQS; i++) {
-		if (mach_default_handler)
-			irq_list[i].handler = (*mach_default_handler)[i];
-		else
-			irq_list[i].handler = default_irq_handler;
-		irq_list[i].flags   = IRQ_FLG_STD;
-		irq_list[i].dev_id  = NULL;
-		irq_list[i].devname = NULL;
-	}
-
-	for (i = 0; i < NUM_IRQ_NODES; i++)
-		nodes[i].handler = NULL;
-
-	if (mach_init_IRQ)
-		mach_init_IRQ();
-}
-
-irq_node_t *new_irq_node(void)
-{
-	irq_node_t *node;
-	short i;
-
-	for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
-		if (!node->handler)
-			return node;
-
-	printk("new_irq_node: out of nodes\n");
-	return NULL;
-}
-
-int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-                unsigned long flags, const char *devname, void *dev_id)
-{
-	if (irq < 0 || irq >= NR_IRQS) {
-		printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__,
-			irq, devname);
-		return -ENXIO;
-	}
-
-	if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
-		if (irq_list[irq].flags & IRQ_FLG_LOCK) {
-			printk("%s: IRQ %d from %s is not replaceable\n",
-			       __FUNCTION__, irq, irq_list[irq].devname);
-			return -EBUSY;
-		}
-		if (flags & IRQ_FLG_REPLACE) {
-			printk("%s: %s can't replace IRQ %d from %s\n",
-			       __FUNCTION__, devname, irq, irq_list[irq].devname);
-			return -EBUSY;
-		}
-	}
-
-#ifdef CONFIG_COLDFIRE
-	if (flags & IRQ_FLG_FAST) {
-		extern asmlinkage void fasthandler(void);
-		extern void set_evector(int vecnum, void (*handler)(void));
-		set_evector(irq, fasthandler);
-	}
-#endif
-
-	irq_list[irq].handler = handler;
-	irq_list[irq].flags   = flags;
-	irq_list[irq].dev_id  = dev_id;
-	irq_list[irq].devname = devname;
-	return 0;
-}
-
-void free_irq(unsigned int irq, void *dev_id)
-{
-	if (irq >= NR_IRQS) {
-		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
-		return;
-	}
-
-	if (irq_list[irq].dev_id != dev_id)
-		printk("%s: Removing probably wrong IRQ %d from %s\n",
-		       __FUNCTION__, irq, irq_list[irq].devname);
-
-#ifdef CONFIG_COLDFIRE
-	if (irq_list[irq].flags & IRQ_FLG_FAST) {
-		extern asmlinkage void inthandler(void);
-		extern void set_evector(int vecnum, void (*handler)(void));
-		set_evector(irq, inthandler);
-	}
-#endif
-
-	if (mach_default_handler)
-		irq_list[irq].handler = (*mach_default_handler)[irq];
-	else
-		irq_list[irq].handler = default_irq_handler;
-	irq_list[irq].flags   = IRQ_FLG_STD;
-	irq_list[irq].dev_id  = NULL;
-	irq_list[irq].devname = NULL;
-}
-
-
-int sys_request_irq(unsigned int irq, 
-                    void (*handler)(int, void *, struct pt_regs *), 
-                    unsigned long flags, const char *devname, void *dev_id)
-{
-	if (irq > IRQ7) {
-		printk("%s: Incorrect IRQ %d from %s\n",
-		       __FUNCTION__, irq, devname);
-		return -ENXIO;
-	}
-
-#if 0
-	if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
-		if (irq_list[irq].flags & IRQ_FLG_LOCK) {
-			printk("%s: IRQ %d from %s is not replaceable\n",
-			       __FUNCTION__, irq, irq_list[irq].devname);
-			return -EBUSY;
-		}
-		if (!(flags & IRQ_FLG_REPLACE)) {
-			printk("%s: %s can't replace IRQ %d from %s\n",
-			       __FUNCTION__, devname, irq, irq_list[irq].devname);
-			return -EBUSY;
-		}
-	}
-#endif
-
-	irq_list[irq].handler = handler;
-	irq_list[irq].flags   = flags;
-	irq_list[irq].dev_id  = dev_id;
-	irq_list[irq].devname = devname;
-	return 0;
-}
-
-void sys_free_irq(unsigned int irq, void *dev_id)
-{
-	if (irq > IRQ7) {
-		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
-		return;
-	}
-
-	if (irq_list[irq].dev_id != dev_id)
-		printk("%s: Removing probably wrong IRQ %d from %s\n",
-		       __FUNCTION__, irq, irq_list[irq].devname);
-
-	irq_list[irq].handler = (*mach_default_handler)[irq];
-	irq_list[irq].flags   = 0;
-	irq_list[irq].dev_id  = NULL;
-	irq_list[irq].devname = NULL;
-}
-
-/*
- * Do we need these probe functions on the m68k?
- *
- *  ... may be useful with ISA devices
- */
-unsigned long probe_irq_on (void)
-{
-	return 0;
-}
-
-int probe_irq_off (unsigned long irqs)
-{
-	return 0;
-}
-
-asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
-{
-	if (vec >= VEC_INT1 && vec <= VEC_INT7) {
-		vec -= VEC_SPUR;
-		kstat_cpu(0).irqs[vec]++;
-		irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
-	} else {
-		if (mach_process_int)
-			mach_process_int(vec, fp);
-		else
-			panic("Can't process interrupt vector %ld\n", vec);
-		return;
-	}
-}
-
-
-int show_interrupts(struct seq_file *p, void *v)
-{
-	int i;
-
-	for (i = 0; i < NR_IRQS; i++) {
-		if (irq_list[i].flags & IRQ_FLG_STD)
-			continue;
-
-		seq_printf(p, "%3d: %10u ", i,
-			(i ? kstat_cpu(0).irqs[i] : num_spurious));
-		if (irq_list[i].flags & IRQ_FLG_LOCK)
-			seq_printf(p, "L ");
-		else
-			seq_printf(p, "  ");
-		seq_printf(p, "%s\n", irq_list[i].devname);
-	}
-
-	if (mach_get_irq_list)
-		mach_get_irq_list(p, v);
-	return(0);
-}
-
-void init_irq_proc(void)
-{
-	/* Insert /proc/irq driver here */
-}
-
diff -Nru a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c
--- a/arch/m68knommu/kernel/process.c	Tue Dec 10 16:40:06 2002
+++ b/arch/m68knommu/kernel/process.c	Tue May 27 20:13:11 2003
@@ -167,24 +167,20 @@
 
 asmlinkage int m68k_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);
 }
 
 asmlinkage int m68k_clone(struct pt_regs *regs)
 {
 	unsigned long clone_flags;
 	unsigned long newsp;
-	struct task_struct *p;
 
 	/* syscall2 puts clone_flags in d1 and usp in d2 */
 	clone_flags = regs->d1;
 	newsp = regs->d2;
 	if (!newsp)
 		newsp = rdusp();
-        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);
 }
 
 int copy_thread(int nr, unsigned long clone_flags,
diff -Nru a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c
--- a/arch/m68knommu/kernel/setup.c	Thu May  8 15:47:40 2003
+++ b/arch/m68knommu/kernel/setup.c	Tue May 27 20:13:11 2003
@@ -225,10 +225,6 @@
 		(int) memory_end, (int) _ramend);
 #endif
 
-#ifdef CONFIG_BLK_DEV_BLKMEM
-	ROOT_DEV = MKDEV(BLKMEM_MAJOR, 0);
-#endif
-
 	/* Keep a copy of command line */
 	*cmdline_p = &command_line[0];
 	memcpy(saved_command_line, command_line, sizeof(saved_command_line));
diff -Nru a/arch/m68knommu/mm/memory.c b/arch/m68knommu/mm/memory.c
--- a/arch/m68knommu/mm/memory.c	Fri Nov  1 07:19:55 2002
+++ b/arch/m68knommu/mm/memory.c	Tue May 27 20:13:12 2003
@@ -114,51 +114,18 @@
 
 int is_in_rom(unsigned long addr)
 {
+	extern unsigned long _ramstart, _ramend;
 
-#ifdef CONFIG_COLDFIRE
-	{
-		extern unsigned long    _ramstart, _ramend;
-
-		/* Anything not in operational RAM is returned as in rom! */
-		if (addr < _ramstart || addr >= _ramend)
-			return(1);
-	}
-#endif
-
-#if defined(CONFIG_PILOT) || defined(CONFIG_UCSIMM)
-	if (addr >= 0x10c00000)
-		return 1;
-#endif
-
-#ifdef CONFIG_M68EZ328ADS
-	if ( 0x00200000 <= addr && addr < 0x00400000)
-		return 1;
-#endif
-
-#ifdef CONFIG_M68332
-	extern char _etext;
-	
- #ifdef SHGLCORE_ROM_BANK_0_ADDR
-	if ((addr >= SHGLCORE_ROM_BANK_0_ADDR) &&
-	    (addr < (SHGLCORE_ROM_BANK_0_ADDR+SHGLCORE_ROM_BANK_0_LENGTH)))
-		return 1;
- #endif
- #ifdef SHGLCORE_ROM_BANK_1_ADDR
-	else if ((addr >= SHGLCORE_ROM_BANK_1_ADDR) &&
-	    (addr < (SHGLCORE_ROM_BANK_1_ADDR+SHGLCORE_ROM_BANK_1_LENGTH)))
-		return 1;
- #endif
- #ifdef SHGLCORE_FLASH_BANK_0_ADDR
-	else if ((addr >= SHGLCORE_FLASH_BANK_0_ADDR) &&
-	    (addr < (SHGLCORE_FLASH_BANK_0_ADDR+SHGLCORE_FLASH_BANK_0_LENGTH)))
-		return 1;
- #endif
- #ifdef SHGLCORE_FLASH_BANK_1_ADDR
-	else if ((addr >= SHGLCORE_FLASH_BANK_1_ADDR) &&
-	    (addr < (SHGLCORE_FLASH_BANK_1_ADDR+SHGLCORE_FLASH_BANK_1_LENGTH)))
-		return 1;
- #endif
-#endif
+	/*
+	 *	What we are really trying to do is determine if addr is
+	 *	in an allocated kernel memory region. If not then assume
+	 *	we cannot free it or otherwise de-allocate it. Ideally
+	 *	we could restrict this to really being in a ROM or flash,
+	 *	but that would need to be done on a board by board basis,
+	 *	not globally.
+	 */
+	if ((addr < _ramstart) || (addr >= _ramend))
+		return(1);
 
 	/* Default case, not in ROM */
 	return(0);
diff -Nru a/arch/m68knommu/platform/5206/ARNEWSH/crt0_ram.S b/arch/m68knommu/platform/5206/ARNEWSH/crt0_ram.S
--- a/arch/m68knommu/platform/5206/ARNEWSH/crt0_ram.S	Fri Nov  1 07:19:55 2002
+++ b/arch/m68knommu/platform/5206/ARNEWSH/crt0_ram.S	Tue May 27 20:13:12 2003
@@ -157,6 +157,7 @@
 	movec	%d0, %CACR			/* Enable cache */
 
 
+#ifdef CONFIG_ROMFS_FS
 	/*
 	 *	Move ROM filesystem above bss :-)
 	 */
@@ -177,6 +178,12 @@
 	move.l	%d0, -(%a1)
 	cmp.l	%a0, %a2			/* Check if at end */
 	bne	_copy_romfs
+
+#else /* CONFIG_ROMFS_FS */
+	lea.l	_ebss, %a1
+	move.l	%a1, _ramstart
+#endif /* CONFIG_ROMFS_FS */
+
 
 	/*
 	 *	Zero out the bss region.
diff -Nru a/arch/m68knommu/platform/5206/config.c b/arch/m68knommu/platform/5206/config.c
--- a/arch/m68knommu/platform/5206/config.c	Thu May  8 15:47:41 2003
+++ b/arch/m68knommu/platform/5206/config.c	Tue May 27 20:13:12 2003
@@ -96,7 +96,13 @@
 void config_BSP(char *commandp, int size)
 {
 	mcf_setimr(MCFSIM_IMR_MASKALL);
+
+#if defined(CONFIG_BOOTPARAM)
+	strncpy(commandp, CONFIG_BOOTPARAM_STRING, size);
+	commandp[size-1] = 0;
+#else
 	memset(commandp, 0, size);
+#endif
 
 	mach_sched_init = coldfire_timer_init;
 	mach_tick = coldfire_tick;
diff -Nru a/arch/m68knommu/platform/5206e/config.c b/arch/m68knommu/platform/5206e/config.c
--- a/arch/m68knommu/platform/5206e/config.c	Thu May  8 15:47:41 2003
+++ b/arch/m68knommu/platform/5206e/config.c	Tue May 27 20:13:12 2003
@@ -97,7 +97,10 @@
 {
 	mcf_setimr(MCFSIM_IMR_MASKALL);
 
-#ifdef CONFIG_NETtel
+#if defined(CONFIG_BOOTPARAM)
+	strncpy(commandp, CONFIG_BOOTPARAM_STRING, size);
+	commandp[size-1] = 0;
+#elif defined(CONFIG_NETtel)
 	/* Copy command line from FLASH to local buffer... */
 	memcpy(commandp, (char *) 0xf0004000, size);
 	commandp[size-1] = 0;
diff -Nru a/arch/m68knommu/platform/5307/Makefile b/arch/m68knommu/platform/5307/Makefile
--- a/arch/m68knommu/platform/5307/Makefile	Thu May  8 15:47:43 2003
+++ b/arch/m68knommu/platform/5307/Makefile	Sun May 25 21:46:26 2003
@@ -16,7 +16,7 @@
 AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1
 endif
 
-obj-$(CONFIG_COLDFIRE)	+= entry.o vectors.o
+obj-$(CONFIG_COLDFIRE)	+= entry.o vectors.o ints.o
 obj-$(CONFIG_M5206)	+= timers.o
 obj-$(CONFIG_M5206e)	+= timers.o
 obj-$(CONFIG_M5249)	+= timers.o
diff -Nru a/arch/m68knommu/platform/5307/ints.c b/arch/m68knommu/platform/5307/ints.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/m68knommu/platform/5307/ints.c	Sun May 25 21:46:26 2003
@@ -0,0 +1,267 @@
+/*
+ * linux/arch/m68knommu/kernel/ints.c -- General interrupt handling code
+ *
+ * Copyright (C) 1999-2002  Greg Ungerer (gerg@snapgear.com)
+ * Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
+ *                     Kenneth Albanowski <kjahds@kjahds.com>,
+ * Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
+ *
+ * Based on:
+ *
+ * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/errno.h>
+#include <linux/config.h>
+#include <linux/seq_file.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/page.h>
+#include <asm/machdep.h>
+
+/*
+ *	This table stores the address info for each vector handler.
+ */
+irq_handler_t irq_list[SYS_IRQS];
+
+#define NUM_IRQ_NODES 16
+static irq_node_t nodes[NUM_IRQ_NODES];
+
+/* The number of spurious interrupts */
+volatile unsigned int num_spurious;
+
+unsigned int local_bh_count[NR_CPUS];
+unsigned int local_irq_count[NR_CPUS];
+
+static void default_irq_handler(int irq, void *ptr, struct pt_regs *regs)
+{
+#if 1
+	printk("%s(%d): default irq handler vec=%d [0x%x]\n",
+		__FILE__, __LINE__, irq, irq);
+#endif
+}
+
+/*
+ * void init_IRQ(void)
+ *
+ * Parameters:	None
+ *
+ * Returns:	Nothing
+ *
+ * This function should be called during kernel startup to initialize
+ * the IRQ handling routines.
+ */
+
+void __init init_IRQ(void)
+{
+	int i;
+
+	for (i = 0; i < SYS_IRQS; i++) {
+		if (mach_default_handler)
+			irq_list[i].handler = (*mach_default_handler)[i];
+		else
+			irq_list[i].handler = default_irq_handler;
+		irq_list[i].flags   = IRQ_FLG_STD;
+		irq_list[i].dev_id  = NULL;
+		irq_list[i].devname = NULL;
+	}
+
+	for (i = 0; i < NUM_IRQ_NODES; i++)
+		nodes[i].handler = NULL;
+
+	if (mach_init_IRQ)
+		mach_init_IRQ();
+}
+
+irq_node_t *new_irq_node(void)
+{
+	irq_node_t *node;
+	short i;
+
+	for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
+		if (!node->handler)
+			return node;
+
+	printk("new_irq_node: out of nodes\n");
+	return NULL;
+}
+
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+                unsigned long flags, const char *devname, void *dev_id)
+{
+	if (irq < 0 || irq >= NR_IRQS) {
+		printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__,
+			irq, devname);
+		return -ENXIO;
+	}
+
+	if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
+		if (irq_list[irq].flags & IRQ_FLG_LOCK) {
+			printk("%s: IRQ %d from %s is not replaceable\n",
+			       __FUNCTION__, irq, irq_list[irq].devname);
+			return -EBUSY;
+		}
+		if (flags & IRQ_FLG_REPLACE) {
+			printk("%s: %s can't replace IRQ %d from %s\n",
+			       __FUNCTION__, devname, irq, irq_list[irq].devname);
+			return -EBUSY;
+		}
+	}
+
+	if (flags & IRQ_FLG_FAST) {
+		extern asmlinkage void fasthandler(void);
+		extern void set_evector(int vecnum, void (*handler)(void));
+		set_evector(irq, fasthandler);
+	}
+
+	irq_list[irq].handler = handler;
+	irq_list[irq].flags   = flags;
+	irq_list[irq].dev_id  = dev_id;
+	irq_list[irq].devname = devname;
+	return 0;
+}
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+	if (irq >= NR_IRQS) {
+		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+		return;
+	}
+
+	if (irq_list[irq].dev_id != dev_id)
+		printk("%s: Removing probably wrong IRQ %d from %s\n",
+		       __FUNCTION__, irq, irq_list[irq].devname);
+
+	if (irq_list[irq].flags & IRQ_FLG_FAST) {
+		extern asmlinkage void inthandler(void);
+		extern void set_evector(int vecnum, void (*handler)(void));
+		set_evector(irq, inthandler);
+	}
+
+	if (mach_default_handler)
+		irq_list[irq].handler = (*mach_default_handler)[irq];
+	else
+		irq_list[irq].handler = default_irq_handler;
+	irq_list[irq].flags   = IRQ_FLG_STD;
+	irq_list[irq].dev_id  = NULL;
+	irq_list[irq].devname = NULL;
+}
+
+
+int sys_request_irq(unsigned int irq, 
+                    void (*handler)(int, void *, struct pt_regs *), 
+                    unsigned long flags, const char *devname, void *dev_id)
+{
+	if (irq > IRQ7) {
+		printk("%s: Incorrect IRQ %d from %s\n",
+		       __FUNCTION__, irq, devname);
+		return -ENXIO;
+	}
+
+#if 0
+	if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
+		if (irq_list[irq].flags & IRQ_FLG_LOCK) {
+			printk("%s: IRQ %d from %s is not replaceable\n",
+			       __FUNCTION__, irq, irq_list[irq].devname);
+			return -EBUSY;
+		}
+		if (!(flags & IRQ_FLG_REPLACE)) {
+			printk("%s: %s can't replace IRQ %d from %s\n",
+			       __FUNCTION__, devname, irq, irq_list[irq].devname);
+			return -EBUSY;
+		}
+	}
+#endif
+
+	irq_list[irq].handler = handler;
+	irq_list[irq].flags   = flags;
+	irq_list[irq].dev_id  = dev_id;
+	irq_list[irq].devname = devname;
+	return 0;
+}
+
+void sys_free_irq(unsigned int irq, void *dev_id)
+{
+	if (irq > IRQ7) {
+		printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
+		return;
+	}
+
+	if (irq_list[irq].dev_id != dev_id)
+		printk("%s: Removing probably wrong IRQ %d from %s\n",
+		       __FUNCTION__, irq, irq_list[irq].devname);
+
+	irq_list[irq].handler = (*mach_default_handler)[irq];
+	irq_list[irq].flags   = 0;
+	irq_list[irq].dev_id  = NULL;
+	irq_list[irq].devname = NULL;
+}
+
+/*
+ * Do we need these probe functions on the m68k?
+ *
+ *  ... may be useful with ISA devices
+ */
+unsigned long probe_irq_on (void)
+{
+	return 0;
+}
+
+int probe_irq_off (unsigned long irqs)
+{
+	return 0;
+}
+
+asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
+{
+	if (vec >= VEC_INT1 && vec <= VEC_INT7) {
+		vec -= VEC_SPUR;
+		kstat_cpu(0).irqs[vec]++;
+		irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
+	} else {
+		if (mach_process_int)
+			mach_process_int(vec, fp);
+		else
+			panic("Can't process interrupt vector %ld\n", vec);
+		return;
+	}
+}
+
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+	int i;
+
+	for (i = 0; i < NR_IRQS; i++) {
+		if (irq_list[i].flags & IRQ_FLG_STD)
+			continue;
+
+		seq_printf(p, "%3d: %10u ", i,
+			(i ? kstat_cpu(0).irqs[i] : num_spurious));
+		if (irq_list[i].flags & IRQ_FLG_LOCK)
+			seq_printf(p, "L ");
+		else
+			seq_printf(p, "  ");
+		seq_printf(p, "%s\n", irq_list[i].devname);
+	}
+
+	if (mach_get_irq_list)
+		mach_get_irq_list(p, v);
+	return(0);
+}
+
+void init_irq_proc(void)
+{
+	/* Insert /proc/irq driver here */
+}
+
diff -Nru a/arch/m68knommu/platform/68328/entry.S b/arch/m68knommu/platform/68328/entry.S
--- a/arch/m68knommu/platform/68328/entry.S	Mon Mar 10 16:25:35 2003
+++ b/arch/m68knommu/platform/68328/entry.S	Tue May 27 20:13:13 2003
@@ -76,7 +76,12 @@
 	jbsr    set_esp0
 	addql   #4,%sp
 
-	btst	#PF_TRACESYS_BIT,%a2@(TASK_FLAGS+PF_TRACESYS_OFF)
+	movel	%sp@(PT_ORIG_D0),%d0
+
+	movel	%sp,%d1			/* get thread_info pointer */
+	andl	#0xffffe000,%d1
+	movel	%d1,%a2
+	btst    #TIF_SYSCALL_TRACE,%a2@(TI_FLAGS)
 	jne	do_trace
 	cmpl	#NR_syscalls,%d0
 	jcc	badsys
diff -Nru a/arch/m68knommu/platform/68328/pilot/crt0_rom.S b/arch/m68knommu/platform/68328/pilot/crt0_rom.S
--- a/arch/m68knommu/platform/68328/pilot/crt0_rom.S	Tue Feb 18 02:27:40 2003
+++ b/arch/m68knommu/platform/68328/pilot/crt0_rom.S	Tue May 27 20:13:13 2003
@@ -136,10 +136,10 @@
 	cmpal	%a1, %a2
 	bhi	L2
 
-	/* Copy data segment from ROM to RAM */
+	/* Copy data+init segment from ROM to RAM */
 	moveal	#_etext, %a0
 	moveal	#_sdata, %a1
-	moveal	#_edata, %a2
+	moveal	#__init_end, %a2
 
 	DBG_PUTC('D')
 
diff -Nru a/arch/m68knommu/platform/68VZ328/de2/config.c b/arch/m68knommu/platform/68VZ328/de2/config.c
--- a/arch/m68knommu/platform/68VZ328/de2/config.c	Sun May 25 21:46:27 2003
+++ b/arch/m68knommu/platform/68VZ328/de2/config.c	Tue May 27 06:56:10 2003
@@ -118,7 +118,7 @@
 
 static void init_hardware(void)
 {
-#if CONFIG_DIRECT_IO_ACCESS
+#ifdef CONFIG_DIRECT_IO_ACCESS
 	SCR = 0x10;					/* allow user access to internal registers */
 #endif
 
diff -Nru a/arch/m68knommu/vmlinux.lds.S b/arch/m68knommu/vmlinux.lds.S
--- a/arch/m68knommu/vmlinux.lds.S	Thu May  8 15:47:40 2003
+++ b/arch/m68knommu/vmlinux.lds.S	Tue May 27 20:13:11 2003
@@ -27,6 +27,7 @@
 #define	RAM_START	0x10000400
 #define	RAM_LENGTH	0xffc00
 #define	RAM_END		0x10100000
+#define _ramend	_ram_end_notused
 #define	DATA_ADDR	RAM_START
 #endif
 
@@ -276,6 +277,9 @@
 		__con_initcall_start = .;
 		*(.con_initcall.init)
 		__con_initcall_end = .;
+		__security_initcall_start = .;
+		*(.security_initcall.init)
+		__security_initcall_end = .;
 		. = ALIGN(4);
 		__initramfs_start = .;
 		*(.init.ramfs)
diff -Nru a/arch/mips/au1000/common/serial.c b/arch/mips/au1000/common/serial.c
--- a/arch/mips/au1000/common/serial.c	Wed May  7 15:51:55 2003
+++ b/arch/mips/au1000/common/serial.c	Mon May 26 15:29:21 2003
@@ -126,7 +126,7 @@
 
 static DECLARE_TASK_QUEUE(tq_serial);
 
-static struct tty_driver serial_driver, callout_driver;
+static struct tty_driver serial_driver;
 static int serial_refcount;
 
 static struct timer_list serial_timer;
@@ -136,7 +136,6 @@
 /* serial subtype definitions */
 #ifndef SERIAL_TYPE_NORMAL
 #define SERIAL_TYPE_NORMAL	1
-#define SERIAL_TYPE_CALLOUT	2
 #endif
 
 /* number of characters left in xmit buffer before we ask for more */
@@ -529,8 +528,7 @@
 #endif		
 		if (status & UART_MSR_DCD)
 			wake_up_interruptible(&info->open_wait);
-		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-			   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+		else {
 #ifdef SERIAL_DEBUG_OPEN
 			printk("doing serial hangup...");
 #endif
@@ -1935,8 +1933,6 @@
 	 */
 	if (info->flags & ASYNC_NORMAL_ACTIVE)
 		info->state->normal_termios = *tty->termios;
-	if (info->flags & ASYNC_CALLOUT_ACTIVE)
-		info->state->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -1976,8 +1972,7 @@
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	MOD_DEC_USE_COUNT;
 }
@@ -2066,7 +2061,7 @@
 	shutdown(info);
 	info->event = 0;
 	state->count = 0;
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -2102,44 +2097,18 @@
 	}
 
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-	
-	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (state->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -2162,8 +2131,7 @@
 	info->blocked_open++;
 	while (1) {
 		save_flags(flags); cli();
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (tty->termios->c_cflag & CBAUD))
+		if (tty->termios->c_cflag & CBAUD)
 			serial_out(info, UART_MCR,
 				   serial_inp(info, UART_MCR) |
 				   (UART_MCR_DTR | UART_MCR_RTS));
@@ -2181,8 +2149,7 @@
 #endif
 			break;
 		}
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(info->flags & ASYNC_CLOSING) &&
+		if (!(info->flags & ASYNC_CLOSING) &&
 		    (do_clocal || (serial_in(info, UART_MSR) &
 				   UART_MSR_DCD)))
 			break;
@@ -2335,10 +2302,7 @@
 
 	if ((info->state->count == 1) &&
 	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->state->normal_termios;
-		else 
-			*tty->termios = info->state->callout_termios;
+		*tty->termios = info->state->normal_termios;
 		change_speed(info, 0);
 	}
 #ifdef CONFIG_AU1000_SERIAL_CONSOLE
@@ -2348,8 +2312,6 @@
 		change_speed(info, 0);
 	}
 #endif
-	info->session = current->session;
-	info->pgrp = current->pgrp;
 
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_open %s successful...", tty->name);
@@ -2626,26 +2588,9 @@
 	serial_driver.wait_until_sent = rs_wait_until_sent;
 	serial_driver.read_proc = rs_read_proc;
 	
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	callout_driver = serial_driver;
-#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
-	callout_driver.name = "cua/";
-#else
-	callout_driver.name = "cua";
-#endif
-	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(&serial_driver))
 		panic("Couldn't register serial driver\n");
-	if (tty_register_driver(&callout_driver))
-		panic("Couldn't register callout driver\n");
-	
+
 	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
 		state->baud_base = get_au1000_uart_baud();
 		state->magic = SSTATE_MAGIC;
@@ -2654,7 +2599,6 @@
 		state->custom_divisor = 0;
 		state->close_delay = 5*HZ/10;
 		state->closing_wait = 30*HZ;
-		state->callout_termios = callout_driver.init_termios;
 		state->normal_termios = serial_driver.init_termios;
 		state->icount.cts = state->icount.dsr = 
 			state->icount.rng = state->icount.dcd = 0;
@@ -2682,7 +2626,6 @@
 		       state->port, state->irq,
 		       uart_config[state->type].name);
 		tty_register_device(&serial_driver, state->line, NULL);
-		tty_register_device(&callout_driver, state->line, NULL);
 	}
 	return 0;
 }
@@ -2770,7 +2713,6 @@
 	      state->iomem_base ? (unsigned long)state->iomem_base :
 	      state->port, state->irq, uart_config[state->type].name);
 	tty_register_device(&serial_driver, state->line, NULL); 
-	tty_register_device(&callout_driver, state->line, NULL);
 	return state->line + SERIAL_DEV_OFFSET;
 }
 
@@ -2815,9 +2757,6 @@
 	if ((e1 = tty_unregister_driver(&serial_driver)))
 		printk("serial: failed to unregister serial driver (%d)\n",
 		       e1);
-	if ((e2 = tty_unregister_driver(&callout_driver)))
-		printk("serial: failed to unregister callout driver (%d)\n", 
-		       e2);
 	restore_flags(flags);
 
 	for (i = 0; i < NR_PORTS; i++) {
diff -Nru a/arch/mips/baget/vacserial.c b/arch/mips/baget/vacserial.c
--- a/arch/mips/baget/vacserial.c	Mon May 26 17:51:43 2003
+++ b/arch/mips/baget/vacserial.c	Mon May 26 15:29:20 2003
@@ -95,7 +95,7 @@
 
 static DECLARE_TASK_QUEUE(tq_serial);
 
-static struct tty_driver serial_driver, callout_driver;
+static struct tty_driver serial_driver;
 static int serial_refcount;
 
 /* number of characters left in xmit buffer before we ask for more */
@@ -1690,8 +1690,6 @@
 	 */
 	if (info->flags & ASYNC_NORMAL_ACTIVE)
 		info->state->normal_termios = *tty->termios;
-	if (info->flags & ASYNC_CALLOUT_ACTIVE)
-		info->state->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -1731,8 +1729,7 @@
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	MOD_DEC_USE_COUNT;
 	restore_flags(flags);
@@ -1811,7 +1808,7 @@
 	shutdown(info);
 	info->event = 0;
 	state->count = 0;
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -1847,44 +1844,18 @@
 	}
 
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-	
-	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (state->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -1919,8 +1890,7 @@
 #endif
 			break;
 		}
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(info->flags & ASYNC_CLOSING))
+		if (!(info->flags & ASYNC_CLOSING))
 			break;
 		if (signal_pending(current)) {
 			retval = -ERESTARTSYS;
@@ -2070,10 +2040,7 @@
 
 	if ((info->state->count == 1) &&
 	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->state->normal_termios;
-		else 
-			*tty->termios = info->state->callout_termios;
+		*tty->termios = info->state->normal_termios;
 		change_speed(info);
 	}
 #ifdef CONFIG_SERIAL_CONSOLE
@@ -2083,8 +2050,6 @@
 		change_speed(info);
 	}
 #endif
-	info->session = current->session;
-	info->pgrp = current->pgrp;
 
 #ifdef SERIAL_DEBUG_OPEN
 	baget_printk("rs_open %s successful...", tty->name);
@@ -2393,21 +2358,8 @@
 	serial_driver.wait_until_sent = rs_wait_until_sent;
 	serial_driver.read_proc = rs_read_proc;
 	
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	callout_driver = serial_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(&serial_driver))
 		panic("Couldn't register serial driver\n");
-	if (tty_register_driver(&callout_driver))
-		panic("Couldn't register callout driver\n");
 	
 	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
 		state->magic = SSTATE_MAGIC;
@@ -2416,7 +2368,6 @@
 		state->custom_divisor = 0;
 		state->close_delay = 5*HZ/10;
 		state->closing_wait = 30*HZ;
-		state->callout_termios = callout_driver.init_termios;
 		state->normal_termios = serial_driver.init_termios;
 		state->icount.cts = state->icount.dsr = 
 			state->icount.rng = state->icount.dcd = 0;
@@ -2533,9 +2484,6 @@
 	if ((e1 = tty_unregister_driver(&serial_driver)))
 		printk("SERIAL: failed to unregister serial driver (%d)\n",
 		       e1);
-	if ((e2 = tty_unregister_driver(&callout_driver)))
-		printk("SERIAL: failed to unregister callout driver (%d)\n", 
-		       e2);
 	restore_flags(flags);
 
 	for (i = 0; i < NR_PORTS; i++) {
diff -Nru a/arch/ppc/4xx_io/serial_sicc.c b/arch/ppc/4xx_io/serial_sicc.c
--- a/arch/ppc/4xx_io/serial_sicc.c	Sun Apr 27 04:56:50 2003
+++ b/arch/ppc/4xx_io/serial_sicc.c	Mon May 26 15:29:20 2003
@@ -183,11 +183,6 @@
 #define SERIAL_SICC_MINOR   1
 #define SERIAL_SICC_NR      1
 
-#define CALLOUT_SICC_NAME   "cuasicc"
-#define CALLOUT_SICC_MAJOR  151
-#define CALLOUT_SICC_MINOR  1
-#define CALLOUT_SICC_NR     SERIAL_SICC_NR
-
 #ifndef TRUE
 #define TRUE 1
 #endif
@@ -202,7 +197,7 @@
 /*
  * Things needed by tty driver
  */
-static struct tty_driver siccnormal_driver, sicccallout_driver;
+static struct tty_driver siccnormal_driver;
 static int siccuart_refcount;
 static struct tty_struct *siccuart_table[SERIAL_SICC_NR];
 static struct termios *siccuart_termios[SERIAL_SICC_NR];
@@ -275,8 +270,6 @@
     unsigned int        custom_divisor;
     unsigned int        flags;
     struct termios      normal_termios;
-    struct termios      callout_termios;
-
     int         count;
     struct SICC_info    *info;
 };
@@ -304,8 +297,6 @@
     unsigned int        lcr_h;
     unsigned int        mctrl;
     int         blocked_open;
-    pid_t           session;
-    pid_t           pgrp;
 
     struct tasklet_struct   tlet;
 
@@ -1487,8 +1478,6 @@
      */
     if (info->flags & ASYNC_NORMAL_ACTIVE)
         info->state->normal_termios = *tty->termios;
-    if (info->flags & ASYNC_CALLOUT_ACTIVE)
-        info->state->callout_termios = *tty->termios;
     /*
      * Now we wait for the transmit buffer to clear; and we notify
      * the line discipline to only process XON/XOFF characters.
@@ -1524,8 +1513,7 @@
         }
         wake_up_interruptible(&info->open_wait);
     }
-    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-             ASYNC_CLOSING);
+    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
     wake_up_interruptible(&info->close_wait);
     MOD_DEC_USE_COUNT;
 }
@@ -1594,7 +1582,7 @@
     siccuart_shutdown(info);
     info->event = 0;
     state->count = 0;
-    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+    info->flags &= ~ASYNC_NORMAL_ACTIVE;
     info->tty = NULL;
     wake_up_interruptible(&info->open_wait);
 }
@@ -1620,43 +1608,17 @@
     }
 
     /*
-     * If this is a callout device, then just make sure the normal
-     * device isn't being used.
-     */
-    if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-        if (info->flags & ASYNC_NORMAL_ACTIVE)
-            return -EBUSY;
-        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-            (info->flags & ASYNC_SESSION_LOCKOUT) &&
-            (info->session != current->session))
-            return -EBUSY;
-        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-            (info->flags & ASYNC_PGRP_LOCKOUT) &&
-            (info->pgrp != current->pgrp))
-            return -EBUSY;
-        info->flags |= ASYNC_CALLOUT_ACTIVE;
-        return 0;
-    }
-
-    /*
      * If non-blocking mode is set, or the port is not enabled,
      * then make the check up front and then exit.
      */
     if ((filp->f_flags & O_NONBLOCK) ||
         (tty->flags & (1 << TTY_IO_ERROR))) {
-        if (info->flags & ASYNC_CALLOUT_ACTIVE)
-            return -EBUSY;
         info->flags |= ASYNC_NORMAL_ACTIVE;
         return 0;
     }
 
-    if (info->flags & ASYNC_CALLOUT_ACTIVE) {
-        if (state->normal_termios.c_cflag & CLOCAL)
-            do_clocal = 1;
-    } else {
-        if (tty->termios->c_cflag & CLOCAL)
-            do_clocal = 1;
-    }
+    if (tty->termios->c_cflag & CLOCAL)
+	do_clocal = 1;
 
     /*
      * Block waiting for the carrier detect and the line to become
@@ -1676,8 +1638,7 @@
     info->blocked_open++;
     while (1) {
         save_flags(flags); cli();
-        if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-            (tty->termios->c_cflag & CBAUD)) {
+        if (tty->termios->c_cflag & CBAUD) {
             info->mctrl = TIOCM_DTR | TIOCM_RTS;
             info->port->set_mctrl(info->port, info->mctrl);
         }
@@ -1691,8 +1652,7 @@
                 retval = -ERESTARTSYS;
             break;
         }
-        if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-            !(info->flags & ASYNC_CLOSING) &&
+        if (!(info->flags & ASYNC_CLOSING) &&
             (do_clocal /*|| (UART_GET_FR(info->port) & SICC_UARTFR_DCD)*/))
             break;
         if (signal_pending(current)) {
@@ -1803,12 +1763,7 @@
 
     if ((info->state->count == 1) &&
         (info->flags & ASYNC_SPLIT_TERMIOS)) {
-        if (tty->driver->subtype == SERIAL_TYPE_NORMAL) {
-            *tty->termios = info->state->normal_termios;
-        }
-        else  {
-            *tty->termios = info->state->callout_termios;
-        }
+	*tty->termios = info->state->normal_termios;
     }
 #ifdef CONFIG_SERIAL_SICC_CONSOLE
     if (siccuart_cons.cflag && siccuart_cons.index == line) {
@@ -1817,8 +1772,6 @@
         siccuart_change_speed(info, NULL);
     }
 #endif
-    info->session = current->session;
-    info->pgrp = current->pgrp;
     return 0;
 }
 
@@ -1862,28 +1815,14 @@
     siccnormal_driver.wait_until_sent = siccuart_wait_until_sent;
     siccnormal_driver.read_proc = NULL;
 
-    /*
-     * The callout device is just like the normal device except for
-     * the major number and the subtype code.
-     */
-    sicccallout_driver = siccnormal_driver;
-    sicccallout_driver.name = CALLOUT_SICC_NAME;
-    sicccallout_driver.major = CALLOUT_SICC_MAJOR;
-    sicccallout_driver.subtype = SERIAL_TYPE_CALLOUT;
-    sicccallout_driver.read_proc = NULL;
-    sicccallout_driver.proc_entry = NULL;
-
     if (tty_register_driver(&siccnormal_driver))
         panic("Couldn't register SICC serial driver\n");
-    if (tty_register_driver(&sicccallout_driver))
-        panic("Couldn't register SICC callout driver\n");
 
     for (i = 0; i < SERIAL_SICC_NR; i++) {
         struct SICC_state *state = sicc_state + i;
         state->line     = i;
         state->close_delay  = 5 * HZ / 10;
         state->closing_wait = 30 * HZ;
-        state->callout_termios  = sicccallout_driver.init_termios;
         state->normal_termios   = siccnormal_driver.init_termios;
     }
 
diff -Nru a/arch/ppc/8260_io/uart.c b/arch/ppc/8260_io/uart.c
--- a/arch/ppc/8260_io/uart.c	Sun Apr 27 04:56:50 2003
+++ b/arch/ppc/8260_io/uart.c	Mon May 26 15:29:20 2003
@@ -74,7 +74,7 @@
 static char *serial_name = "CPM UART driver";
 static char *serial_version = "0.02";
 
-static struct tty_driver serial_driver, callout_driver;
+static struct tty_driver serial_driver;
 static int serial_refcount;
 static int serial_console_setup(struct console *co, char *options);
 
@@ -200,8 +200,6 @@
 	unsigned long		event;
 	unsigned long		last_active;
 	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
 	struct work_struct	tqueue;
 	struct work_struct	tqueue_hangup;
 	wait_queue_head_t	open_wait;
@@ -531,8 +529,7 @@
 #endif		
 		if (status & UART_MSR_DCD)
 			wake_up_interruptible(&info->open_wait);
-		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-			   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+		else {
 #ifdef SERIAL_DEBUG_OPEN
 			printk("scheduling hangup...");
 #endif
@@ -1667,8 +1664,6 @@
 	 */
 	if (info->flags & ASYNC_NORMAL_ACTIVE)
 		info->state->normal_termios = *tty->termios;
-	if (info->flags & ASYNC_CALLOUT_ACTIVE)
-		info->state->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -1716,8 +1711,7 @@
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	MOD_DEC_USE_COUNT;
 	restore_flags(flags);
@@ -1799,7 +1793,7 @@
 	shutdown(info);
 	info->event = 0;
 	state->count = 0;
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -1838,25 +1832,6 @@
 	}
 
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-	
-	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 * If this is an SMC port, we don't have modem control to wait
@@ -1865,20 +1840,13 @@
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR)) ||
 	    (info->state->smc_scc_num < SCC_NUM_BASE)) {
-		if (info->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (state->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -1900,8 +1868,7 @@
 	info->blocked_open++;
 	while (1) {
 		cli();
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (tty->termios->c_cflag & CBAUD))
+		if (tty->termios->c_cflag & CBAUD)
 			serial_out(info, UART_MCR,
 				   serial_inp(info, UART_MCR) |
 				   (UART_MCR_DTR | UART_MCR_RTS));
@@ -1919,8 +1886,7 @@
 #endif
 			break;
 		}
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(info->flags & ASYNC_CLOSING) &&
+		if (!(info->flags & ASYNC_CLOSING) &&
 		    (do_clocal || (serial_in(info, UART_MSR) &
 				   UART_MSR_DCD)))
 			break;
@@ -2010,16 +1976,10 @@
 
 	if ((info->state->count == 1) &&
 	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->state->normal_termios;
-		else 
-			*tty->termios = info->state->callout_termios;
+		*tty->termios = info->state->normal_termios;
 		change_speed(info);
 	}
 
-	info->session = current->session;
-	info->pgrp = current->pgrp;
-
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_open %s successful...", line);
 #endif
@@ -2544,26 +2504,9 @@
 	serial_driver.wait_until_sent = rs_8xx_wait_until_sent;
 	serial_driver.read_proc = rs_8xx_read_proc;
 	
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	callout_driver = serial_driver;
-#ifdef CONFIG_DEVFS_FS
-	callout_driver.name = "cua/";
-#else
-	callout_driver.name = "cua";
-#endif
-	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(&serial_driver))
 		panic("Couldn't register serial driver\n");
-	if (tty_register_driver(&callout_driver))
-		panic("Couldn't register callout driver\n");
-	
+
 	immap = immr;
 	cp = &immap->im_cpm;
 	io = &immap->im_ioport;
@@ -2644,7 +2587,6 @@
 		state->custom_divisor = 0;
 		state->close_delay = 5*HZ/10;
 		state->closing_wait = 30*HZ;
-		state->callout_termios = callout_driver.init_termios;
 		state->normal_termios = serial_driver.init_termios;
 		state->icount.cts = state->icount.dsr = 
 			state->icount.rng = state->icount.dcd = 0;
diff -Nru a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c
--- a/arch/ppc/8xx_io/uart.c	Thu Apr 24 03:30:40 2003
+++ b/arch/ppc/8xx_io/uart.c	Mon May 26 15:29:19 2003
@@ -85,7 +85,7 @@
 
 static DECLARE_TASK_QUEUE(tq_serial);
 
-static struct tty_driver serial_driver, callout_driver;
+static struct tty_driver serial_driver;
 static int serial_refcount;
 static int serial_console_setup(struct console *co, char *options);
 
@@ -199,8 +199,6 @@
 	unsigned long		event;
 	unsigned long		last_active;
 	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
 	struct tq_struct	tqueue;
 	struct tq_struct	tqueue_hangup;
 	wait_queue_head_t	open_wait;
@@ -590,8 +588,7 @@
 #endif		
 		if (status & UART_MSR_DCD)
 			wake_up_interruptible(&info->open_wait);
-		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-			   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+		else {
 #ifdef SERIAL_DEBUG_OPEN
 			printk("scheduling hangup...");
 #endif
@@ -1714,8 +1711,6 @@
 	 */
 	if (info->flags & ASYNC_NORMAL_ACTIVE)
 		info->state->normal_termios = *tty->termios;
-	if (info->flags & ASYNC_CALLOUT_ACTIVE)
-		info->state->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -1764,8 +1759,7 @@
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	MOD_DEC_USE_COUNT;
 	restore_flags(flags);
@@ -1858,7 +1852,7 @@
 	shutdown(info);
 	info->event = 0;
 	state->count = 0;
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -1897,25 +1891,6 @@
 	}
 
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-	
-	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 * If this is an SMC port, we don't have modem control to wait
@@ -1924,20 +1899,13 @@
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR)) ||
 	    !(info->state->smc_scc_num & NUM_IS_SCC)) {
-		if (info->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (state->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -1959,8 +1927,7 @@
 	info->blocked_open++;
 	while (1) {
 		cli();
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (tty->termios->c_cflag & CBAUD))
+		if ((tty->termios->c_cflag & CBAUD))
 			serial_out(info, UART_MCR,
 				   serial_inp(info, UART_MCR) |
 				   (UART_MCR_DTR | UART_MCR_RTS));
@@ -1978,8 +1945,7 @@
 #endif
 			break;
 		}
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(info->flags & ASYNC_CLOSING) &&
+		if (!(info->flags & ASYNC_CLOSING) &&
 		    (do_clocal || (serial_in(info, UART_MSR) &
 				   UART_MSR_DCD)))
 			break;
@@ -2070,16 +2036,10 @@
 
 	if ((info->state->count == 1) &&
 	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->state->normal_termios;
-		else 
-			*tty->termios = info->state->callout_termios;
+		*tty->termios = info->state->normal_termios;
 		change_speed(info);
 	}
 
-	info->session = current->session;
-	info->pgrp = current->pgrp;
-
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_open %s successful...", tty->name);
 #endif
@@ -2597,25 +2557,8 @@
 	serial_driver.wait_until_sent = rs_8xx_wait_until_sent;
 	serial_driver.read_proc = rs_8xx_read_proc;
 	
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	callout_driver = serial_driver;
-#ifdef CONFIG_DEVFS_FS
-	callout_driver.name = "cua/";
-#else
-	callout_driver.name = "cua";
-#endif
-	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(&serial_driver))
 		panic("Couldn't register serial driver\n");
-	if (tty_register_driver(&callout_driver))
-		panic("Couldn't register callout driver\n");
 	
 	cp = cpmp;	/* Get pointer to Communication Processor */
 	immap = (immap_t *)IMAP_ADDR;	/* and to internal registers */
@@ -2675,7 +2618,6 @@
 		state->custom_divisor = 0;
 		state->close_delay = 5*HZ/10;
 		state->closing_wait = 30*HZ;
-		state->callout_termios = callout_driver.init_termios;
 		state->normal_termios = serial_driver.init_termios;
 		state->icount.cts = state->icount.dsr = 
 			state->icount.rng = state->icount.dcd = 0;
diff -Nru a/arch/ppc/boot/ld.script b/arch/ppc/boot/ld.script
--- a/arch/ppc/boot/ld.script	Wed Jan 15 19:52:46 2003
+++ b/arch/ppc/boot/ld.script	Mon May 26 03:50:56 2003
@@ -1,7 +1,4 @@
 OUTPUT_ARCH(powerpc)
-SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
-/* Do we need any of these for elf?
-   __DYNAMIC = 0;    */
 SECTIONS
 {
   /* Read-only sections, merged into text segment: */
@@ -80,4 +77,10 @@
   }
   _end = . ;
   PROVIDE (end = .);
+
+  /DISCARD/ : {
+    *(__ksymtab)
+    *(__ksymtab_strings)
+  }
+
 }
diff -Nru a/arch/ppc/boot/lib/zlib.c b/arch/ppc/boot/lib/zlib.c
--- a/arch/ppc/boot/lib/zlib.c	Sun Sep 15 21:51:57 2002
+++ b/arch/ppc/boot/lib/zlib.c	Wed May 28 05:23:42 2003
@@ -299,8 +299,9 @@
 };
 
 
-int inflateReset(z)
-z_stream *z;
+int inflateReset(
+	z_stream *z
+)
 {
   uLong c;
 
@@ -387,9 +388,10 @@
 #define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
 #define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
 
-int inflate(z, f)
-z_stream *z;
-int f;
+int inflate(
+	z_stream *z,
+	int f	
+)
 {
   int r;
   uInt b;
@@ -504,8 +506,9 @@
  * will have been updated if need be.
  */
 
-int inflateIncomp(z)
-z_stream *z;
+int inflateIncomp(
+	z_stream *z
+)
 {
     if (z->state->mode != BLOCKS)
 	return Z_DATA_ERROR;
@@ -513,8 +516,9 @@
 }
 
 
-int inflateSync(z)
-z_stream *z;
+int inflateSync(
+	z_stream *z
+)
 {
   uInt n;       /* number of bytes to look at */
   Bytef *p;     /* pointer to bytes */
@@ -737,10 +741,11 @@
  */
 
 
-local void inflate_blocks_reset(s, z, c)
-inflate_blocks_statef *s;
-z_stream *z;
-uLongf *c;
+local void inflate_blocks_reset(
+	inflate_blocks_statef *s,
+	z_stream *z,
+	uLongf *c
+)
 {
   if (s->checkfn != Z_NULL)
     *c = s->check;
@@ -762,10 +767,11 @@
 }
 
 
-local inflate_blocks_statef *inflate_blocks_new(z, c, w)
-z_stream *z;
-check_func c;
-uInt w;
+local inflate_blocks_statef *inflate_blocks_new(
+	z_stream *z,
+	check_func c,
+	uInt w
+)
 {
   inflate_blocks_statef *s;
 
@@ -786,10 +792,11 @@
 }
 
 
-local int inflate_blocks(s, z, r)
-inflate_blocks_statef *s;
-z_stream *z;
-int r;
+local int inflate_blocks(
+	inflate_blocks_statef *s,
+	z_stream *z,
+	int r
+)
 {
   uInt t;               /* temporary storage */
   uLong b;              /* bit buffer */
@@ -1049,10 +1056,11 @@
 }
 
 
-local int inflate_blocks_free(s, z, c)
-inflate_blocks_statef *s;
-z_stream *z;
-uLongf *c;
+local int inflate_blocks_free(
+	inflate_blocks_statef *s,
+	z_stream *z,
+	uLongf *c
+)
 {
   inflate_blocks_reset(s, z, c);
   ZFREE(z, s->window, s->end - s->window);
@@ -1069,9 +1077,10 @@
  * BLOCKS).  On exit, the output will also be caught up, and the checksum
  * will have been updated if need be.
  */
-local int inflate_addhistory(s, z)
-inflate_blocks_statef *s;
-z_stream *z;
+local int inflate_addhistory(
+	inflate_blocks_statef *s,
+	z_stream *z
+)
 {
     uLong b;              /* bit buffer */  /* NOT USED HERE */
     uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
@@ -1220,15 +1229,16 @@
   uInt inflate_hufts;
 #endif
 
-local int huft_build(b, n, s, d, e, t, m, zs)
-uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
-uInt n;                 /* number of codes (assumed <= N_MAX) */
-uInt s;                 /* number of simple-valued codes (0..s-1) */
-uIntf *d;               /* list of base values for non-simple codes */
-uIntf *e;               /* list of extra bits for non-simple codes */  
-inflate_huft * FAR *t;  /* result: starting table */
-uIntf *m;               /* maximum lookup bits, returns actual */
-z_stream *zs;           /* for zalloc function */
+local int huft_build(
+	uIntf *b,               /* code lengths in bits (all assumed <= BMAX) */
+	uInt n,                 /* number of codes (assumed <= N_MAX) */
+	uInt s,                 /* number of simple-valued codes (0..s-1) */
+	uIntf *d,               /* list of base values for non-simple codes */
+	uIntf *e,               /* list of extra bits for non-simple codes */
+	inflate_huft * FAR *t,  /* result: starting table */
+	uIntf *m,               /* maximum lookup bits, returns actual */
+	z_stream *zs            /* for zalloc function */
+)
 /* Given a list of code lengths and a maximum table size, make a set of
    tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
    if the given code set is incomplete (the tables are still built in this
@@ -1423,11 +1433,12 @@
 }
 
 
-local int inflate_trees_bits(c, bb, tb, z)
-uIntf *c;               /* 19 code lengths */
-uIntf *bb;              /* bits tree desired/actual depth */
-inflate_huft * FAR *tb; /* bits tree result */
-z_stream *z;            /* for zfree function */
+local int inflate_trees_bits(
+	uIntf *c,               /* 19 code lengths */
+	uIntf *bb,              /* bits tree desired/actual depth */
+	inflate_huft * FAR *tb, /* bits tree result */
+	z_stream *z             /* for zfree function */
+)
 {
   int r;
 
@@ -1444,15 +1455,16 @@
 }
 
 
-local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
-uInt nl;                /* number of literal/length codes */
-uInt nd;                /* number of distance codes */
-uIntf *c;               /* that many (total) code lengths */
-uIntf *bl;              /* literal desired/actual bit depth */
-uIntf *bd;              /* distance desired/actual bit depth */
-inflate_huft * FAR *tl; /* literal/length tree result */
-inflate_huft * FAR *td; /* distance tree result */
-z_stream *z;            /* for zfree function */
+local int inflate_trees_dynamic(
+	uInt nl,                /* number of literal/length codes */
+	uInt nd,                /* number of distance codes */
+	uIntf *c,               /* that many (total) code lengths */
+	uIntf *bl,              /* literal desired/actual bit depth */
+	uIntf *bd,              /* distance desired/actual bit depth */
+	inflate_huft * FAR *tl, /* literal/length tree result */
+	inflate_huft * FAR *td, /* distance tree result */
+	z_stream *z             /* for zfree function */
+)
 {
   int r;
 
@@ -1529,11 +1541,12 @@
 }
 
 
-local int inflate_trees_fixed(bl, bd, tl, td)
-uIntf *bl;               /* literal desired/actual bit depth */
-uIntf *bd;               /* distance desired/actual bit depth */
-inflate_huft * FAR *tl;  /* literal/length tree result */
-inflate_huft * FAR *td;  /* distance tree result */
+local int inflate_trees_fixed(
+	uIntf *bl,               /* literal desired/actual bit depth */
+	uIntf *bd,               /* distance desired/actual bit depth */
+	inflate_huft * FAR *tl,  /* literal/length tree result */
+	inflate_huft * FAR *td   /* distance tree result */
+)
 {
   /* build fixed tables if not built already--lock out other instances */
   while (++fixed_lock > 1)
@@ -1651,10 +1664,13 @@
 };
 
 
-local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
-uInt bl, bd;
-inflate_huft *tl, *td;
-z_stream *z;
+local inflate_codes_statef *inflate_codes_new(
+	uInt bl,
+	uInt bd,
+	inflate_huft *tl,
+	inflate_huft *td,
+	z_stream *z
+)
 {
   inflate_codes_statef *c;
 
@@ -1672,10 +1688,11 @@
 }
 
 
-local int inflate_codes(s, z, r)
-inflate_blocks_statef *s;
-z_stream *z;
-int r;
+local int inflate_codes(
+	inflate_blocks_statef *s,
+	z_stream *z,
+	int r
+)
 {
   uInt j;               /* temporary storage */
   inflate_huft *t;      /* temporary pointer */
@@ -1832,9 +1849,10 @@
 }
 
 
-local void inflate_codes_free(c, z)
-inflate_codes_statef *c;
-z_stream *z;
+local void inflate_codes_free(
+	inflate_codes_statef *c,
+	z_stream *z
+)
 {
   ZFREE(z, c, sizeof(struct inflate_codes_state));
   Tracev((stderr, "inflate:       codes free\n"));
@@ -1847,10 +1865,11 @@
  */
 
 /* copy as much as possible from the sliding window to the output area */
-local int inflate_flush(s, z, r)
-inflate_blocks_statef *s;
-z_stream *z;
-int r;
+local int inflate_flush(
+	inflate_blocks_statef *s,
+	z_stream *z,
+	int r
+)
 {
   uInt n;
   Bytef *p, *q;
@@ -1934,11 +1953,14 @@
    at least ten.  The ten bytes are six bytes for the longest length/
    distance pair plus four bytes for overloading the bit buffer. */
 
-local int inflate_fast(bl, bd, tl, td, s, z)
-uInt bl, bd;
-inflate_huft *tl, *td;
-inflate_blocks_statef *s;
-z_stream *z;
+local int inflate_fast(
+	uInt bl,
+	uInt bd,
+	inflate_huft *tl,
+	inflate_huft *td,
+	inflate_blocks_statef *s,
+	z_stream *z
+)
 {
   inflate_huft *t;      /* temporary pointer */
   uInt e;               /* extra bits or operation */
diff -Nru a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
--- a/arch/ppc/kernel/entry.S	Sat May 24 02:44:42 2003
+++ b/arch/ppc/kernel/entry.S	Mon May 26 03:49:34 2003
@@ -507,7 +507,7 @@
 	MTMSRD(r10)		/* disable interrupts */
 
 	lwz	r3,_MSR(r1)	/* Returning to user mode? */
-	andi.	r3,r3,MSR_PR
+	andi.	r0,r3,MSR_PR
 	beq	resume_kernel
 
 user_exc_return:		/* r10 contains MSR_KERNEL here */
@@ -528,6 +528,7 @@
 #ifdef CONFIG_PREEMPT
 	b	restore
 
+/* N.B. the only way to get here is from the beq following ret_from_except. */
 resume_kernel:
 	/* check current_thread_info->preempt_count */
 	rlwinm	r9,r1,0,0,18
@@ -549,8 +550,10 @@
 	SYNC
 	MTMSRD(r10)		/* disable interrupts */
 	rlwinm	r9,r1,0,0,18
-	lwz	r0,TI_FLAGS(r9)
-	andi.	r0,r0,_TIF_NEED_RESCHED
+	li	r0,0
+	stw	r0,TI_PREEMPT(r9)
+	lwz	r3,TI_FLAGS(r9)
+	andi.	r0,r3,_TIF_NEED_RESCHED
 	bne-	1b
 #else
 resume_kernel:
diff -Nru a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S
--- a/arch/ppc/kernel/head_4xx.S	Wed Jan 29 11:32:39 2003
+++ b/arch/ppc/kernel/head_4xx.S	Mon May 26 04:49:39 2003
@@ -447,7 +447,12 @@
 	EXC_XFER_EE(0x600, AlignmentException)
 
 /* 0x0700 - Program Exception */
-	EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_EE)
+	START_EXCEPTION(0x0700, ProgramCheck)
+	NORMAL_EXCEPTION_PROLOG
+	mfspr	r4,SPRN_ESR		/* Grab the ESR and save it */
+	stw	r4,_ESR(r11)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_EE(0x700, ProgramCheckException)
 
 	EXCEPTION(0x0800, Trap_08, UnknownException, EXC_XFER_EE)
 	EXCEPTION(0x0900, Trap_09, UnknownException, EXC_XFER_EE)
@@ -469,7 +474,7 @@
 	lis	r0,TSR_PIS@h
 	mtspr	SPRN_TSR,r0		/* Clear the PIT exception */
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	EXC_XFER_EE(0x1000, timer_interrupt)
+	EXC_XFER_LITE(0x1000, timer_interrupt)
 
 #if 0
 /* NOTE:
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S	Tue May 20 22:17:33 2003
+++ b/arch/ppc/kernel/misc.S	Sun May 25 05:07:20 2003
@@ -1227,7 +1227,7 @@
 	.long sys_ni_syscall			/* old profil syscall holder */
 	.long sys_statfs
 	.long sys_fstatfs	/* 100 */
-	.long sys_ioperm
+	.long sys_ni_syscall
 	.long sys_socketcall
 	.long sys_syslog
 	.long sys_setitimer
@@ -1236,10 +1236,10 @@
 	.long sys_newlstat
 	.long sys_newfstat
 	.long sys_uname
-	.long sys_iopl		/* 110 */
+	.long sys_ni_syscall	/* 110 */
 	.long sys_vhangup
 	.long sys_ni_syscall	/* old 'idle' syscall */
-	.long sys_vm86
+	.long sys_ni_syscall
 	.long sys_wait4
 	.long sys_swapoff	/* 115 */
 	.long sys_sysinfo
@@ -1249,7 +1249,7 @@
 	.long ppc_clone		/* 120 */
 	.long sys_setdomainname
 	.long sys_newuname
-	.long sys_modify_ldt
+	.long sys_ni_syscall
 	.long sys_adjtimex
 	.long sys_mprotect	/* 125 */
 	.long sys_sigprocmask
diff -Nru a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
--- a/arch/ppc/kernel/pci.c	Wed Mar 19 18:45:17 2003
+++ b/arch/ppc/kernel/pci.c	Mon May 26 04:41:14 2003
@@ -44,6 +44,7 @@
 static void fixup_broken_pcnet32(struct pci_dev* dev);
 static int reparent_resources(struct resource *parent, struct resource *res);
 static void fixup_rev1_53c810(struct pci_dev* dev);
+static void fixup_cpc710_pci64(struct pci_dev* dev);
 #ifdef CONFIG_ALL_PPC
 static void pcibios_fixup_cardbus(struct pci_dev* dev);
 static u8* pci_to_OF_bus_map;
@@ -62,6 +63,7 @@
 struct pci_fixup pcibios_fixups[] = {
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_TRIDENT,	PCI_ANY_ID,			fixup_broken_pcnet32 },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_NCR,	PCI_DEVICE_ID_NCR_53C810,	fixup_rev1_53c810 },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_IBM,	PCI_DEVICE_ID_IBM_CPC710_PCI64,	fixup_cpc710_pci64},
 	{ PCI_FIXUP_HEADER,	PCI_ANY_ID,		PCI_ANY_ID,			pcibios_fixup_resources },
 #ifdef CONFIG_ALL_PPC
 	/* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */
@@ -94,6 +96,18 @@
 }
 
 static void
+fixup_cpc710_pci64(struct pci_dev* dev)
+{
+	/* Hide the PCI64 BARs from the kernel as their content doesn't
+	 * fit well in the resource management
+	 */
+	dev->resource[0].start = dev->resource[0].end = 0;
+	dev->resource[0].flags = 0;
+	dev->resource[1].start = dev->resource[1].end = 0;
+	dev->resource[1].flags = 0;
+}
+
+static void
 pcibios_fixup_resources(struct pci_dev *dev)
 {
 	struct pci_controller* hose = (struct pci_controller *)dev->sysdata;
@@ -1012,6 +1026,215 @@
 		prom_add_property(find_path_device("/"), of_prop);
 	}
 }
+
+/*
+ * This set of routines checks for PCI<->PCI bridges that have closed
+ * IO resources and have child devices. It tries to re-open an IO
+ * window on them. 
+ * 
+ * This is a _temporary_ fix to workaround a problem with Apple's OF
+ * closing IO windows on P2P bridges when the OF drivers of cards
+ * below this bridge don't claim any IO range (typically ATI or
+ * Adaptec).
+ * 
+ * A more complete fix would be to use drivers/pci/setup-bus.c, which
+ * involves a working pcibios_fixup_pbus_ranges(), some more care about
+ * ordering when creating the host bus resources, and maybe a few more
+ * minor tweaks
+ */
+
+/* Initialize bridges with base/limit values we have collected */
+static void __init
+do_update_p2p_io_resource(struct pci_bus *bus, int enable_vga)
+{
+	struct pci_dev *bridge = bus->self;
+	struct pci_controller* hose = (struct pci_controller *)bridge->sysdata;
+	u32 l;
+	u16 w;
+	struct resource res;
+	
+ 	res = *(bus->resource[0]);
+
+	DBG("Remapping Bus %d, bridge: %s\n", bus->number, bridge->name);
+	res.start -= ((unsigned long) hose->io_base_virt - isa_io_base);
+	res.end -= ((unsigned long) hose->io_base_virt - isa_io_base);
+	DBG("  IO window: %08lx-%08lx\n", res.start, res.end);
+
+	/* Set up the top and bottom of the PCI I/O segment for this bus. */
+	pci_read_config_dword(bridge, PCI_IO_BASE, &l);
+	l &= 0xffff000f;
+	l |= (res.start >> 8) & 0x00f0;
+	l |= res.end & 0xf000;
+	pci_write_config_dword(bridge, PCI_IO_BASE, l);
+
+	if ((l & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
+		l = (res.start >> 16) | (res.end & 0xffff0000);
+		pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, l);
+	}
+
+	pci_read_config_word(bridge, PCI_COMMAND, &w);
+	w |= PCI_COMMAND_IO;
+	pci_write_config_word(bridge, PCI_COMMAND, w);
+
+#if 0 /* Enabling this causes XFree 4.2.0 to hang during PCI probe */
+	if (enable_vga) {
+		pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &w);
+		w |= PCI_BRIDGE_CTL_VGA;
+		pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, w);
+	}
+#endif
+}
+
+/* This function is pretty basic and actually quite broken for the
+ * general case, it's enough for us right now though. It's supposed
+ * to tell us if we need to open an IO range at all or not and what
+ * size.
+ */
+static int __init
+check_for_io_childs(struct pci_bus *bus, struct resource* res, int *found_vga)
+{
+	struct list_head *ln;
+	int	i;
+	int	rc = 0;
+
+#define push_end(res, size) do { unsigned long __sz = (size) ; \
+	res->end = ((res->end + __sz) / (__sz + 1)) * (__sz + 1) + __sz; \
+    } while (0)
+
+	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+		struct pci_dev *dev = pci_dev_b(ln);
+		u16 class = dev->class >> 8;
+
+		if (class == PCI_CLASS_DISPLAY_VGA ||
+		    class == PCI_CLASS_NOT_DEFINED_VGA)
+			*found_vga = 1;
+		if (class >> 8 == PCI_BASE_CLASS_BRIDGE && dev->subordinate)
+			rc |= check_for_io_childs(dev->subordinate, res, found_vga);
+		if (class == PCI_CLASS_BRIDGE_CARDBUS)
+			push_end(res, 0xfff);
+
+		for (i=0; i<PCI_NUM_RESOURCES; i++) {
+			struct resource *r;
+			unsigned long r_size;
+
+			if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI
+			    && i >= PCI_BRIDGE_RESOURCES)
+				continue;
+			r = &dev->resource[i];
+			r_size = r->end - r->start;
+			if (r_size < 0xfff)
+				r_size = 0xfff;
+			if (r->flags & IORESOURCE_IO && (r_size) != 0) {
+				rc = 1;
+				push_end(res, r_size);
+			}
+		}
+	}
+
+	return rc;
+}
+
+/* Here we scan all P2P bridges of a given level that have a closed
+ * IO window. Note that the test for the presence of a VGA card should
+ * be improved to take into account already configured P2P bridges,
+ * currently, we don't see them and might end up configuring 2 bridges
+ * with VGA pass through enabled
+ */
+static void __init
+do_fixup_p2p_level(struct pci_bus *bus)
+{
+	struct list_head *ln;
+	int i, parent_io;
+	int has_vga = 0;
+
+	for (parent_io=0; parent_io<4; parent_io++)
+		if (bus->resource[parent_io]->flags & IORESOURCE_IO)
+			break;
+	if (parent_io >= 4)
+		return;
+	
+	for (ln=bus->children.next; ln != &bus->children; ln=ln->next) {
+		struct pci_bus *b = pci_bus_b(ln);
+		struct pci_dev *d = b->self;
+		struct pci_controller* hose = (struct pci_controller *)d->sysdata;
+		struct resource *res = b->resource[0];
+		struct resource tmp_res;
+		unsigned long max;
+		int found_vga = 0;
+
+		memset(&tmp_res, 0, sizeof(tmp_res));
+		tmp_res.start = bus->resource[parent_io]->start;
+
+		/* We don't let low addresses go through that closed P2P bridge, well,
+		 * that may not be necessary but I feel safer that way
+		 */
+		if (tmp_res.start == 0)
+			tmp_res.start = 0x1000;
+		
+		if (!list_empty(&b->devices) && res && res->flags == 0 &&
+		    res != bus->resource[parent_io] &&
+		    (d->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
+		    check_for_io_childs(b, &tmp_res, &found_vga)) {
+			u8 io_base_lo;
+
+			printk(KERN_INFO "Fixing up IO bus %s\n", b->name);
+
+			if (found_vga) {
+				if (has_vga) {
+					printk(KERN_WARNING "Skipping VGA, already active"
+					    " on bus segment\n");
+					found_vga = 0;
+				} else
+					has_vga = 1;
+			}
+			pci_read_config_byte(d, PCI_IO_BASE, &io_base_lo);
+
+			if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32)
+				max = ((unsigned long) hose->io_base_virt
+					- isa_io_base) + 0xffffffff;
+			else
+				max = ((unsigned long) hose->io_base_virt
+					- isa_io_base) + 0xffff;
+
+			*res = tmp_res;
+			res->flags = IORESOURCE_IO;
+			res->name = b->name;
+			
+			/* Find a resource in the parent where we can allocate */
+			for (i = 0 ; i < 4; i++) {
+				struct resource *r = bus->resource[i];
+				if (!r)
+					continue;
+				if ((r->flags & IORESOURCE_IO) == 0)
+					continue;
+				DBG("Trying to allocate from %08lx, size %08lx from parent"
+				    " res %d: %08lx -> %08lx\n",
+					res->start, res->end, i, r->start, r->end);
+				
+				if (allocate_resource(r, res, res->end + 1, res->start, max,
+				    res->end + 1, NULL, NULL) < 0) {
+					DBG("Failed !\n");
+					continue;
+				}
+				do_update_p2p_io_resource(b, found_vga);
+				break;
+			}
+		}
+		do_fixup_p2p_level(b);
+	}
+}
+
+static void
+pcibios_fixup_p2p_bridges(void)
+{
+	struct list_head *ln;
+
+	for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next) {
+		struct pci_bus *b = pci_bus_b(ln);
+		do_fixup_p2p_level(b);
+	}
+}
+
 #endif /* CONFIG_ALL_PPC */
 
 static int __init
@@ -1054,6 +1277,9 @@
 	pcibios_allocate_bus_resources(&pci_root_buses);
 	pcibios_allocate_resources(0);
 	pcibios_allocate_resources(1);
+#ifdef CONFIG_ALL_PPC
+	pcibios_fixup_p2p_bridges();
+#endif /* CONFIG_ALL_PPC */
 	pcibios_assign_resources();
 
 	/* Call machine dependent post-init code */
diff -Nru a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c
--- a/arch/ppc/kernel/syscalls.c	Sun Sep 15 21:51:59 2002
+++ b/arch/ppc/kernel/syscalls.c	Sun May 25 05:07:20 2003
@@ -35,6 +35,7 @@
 #include <linux/ipc.h>
 #include <linux/utsname.h>
 #include <linux/file.h>
+#include <linux/unistd.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
@@ -45,30 +46,6 @@
 {
 }
 
-int sys_ioperm(unsigned long from, unsigned long num, int on)
-{
-	printk(KERN_ERR "sys_ioperm()\n");
-	return -EIO;
-}
-
-int sys_iopl(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
-int sys_vm86(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
-int sys_modify_ldt(int a1, int a2, int a3, int a4)
-{
-	printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
-	return (-ENOSYS);
-}
-
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
@@ -291,12 +268,6 @@
 	return error;
 }
 
-#ifndef CONFIG_PCI
-/*
- * Those are normally defined in arch/ppc/kernel/pci.c. But when CONFIG_PCI is
- * not defined, this file is not linked at all, so here are the "empty" versions
- */
-int sys_pciconfig_read(void) { return -ENOSYS; }
-int sys_pciconfig_write(void) { return -ENOSYS; }
-long sys_pciconfig_iobase(void) { return -ENOSYS; }
-#endif
+cond_syscall(sys_pciconfig_read);
+cond_syscall(sys_pciconfig_write);
+cond_syscall(sys_pciconfig_iobase);
diff -Nru a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
--- a/arch/ppc/kernel/traps.c	Wed Apr 30 05:41:43 2003
+++ b/arch/ppc/kernel/traps.c	Mon May 26 04:49:39 2003
@@ -302,7 +302,7 @@
 	int errcode;
 
 #if defined(CONFIG_4xx)
-	unsigned int esr = mfspr(SPRN_ESR);
+	unsigned int esr = regs->dsisr;
 	int isbpt = esr & ESR_PTR;
 	extern int do_mathemu(struct pt_regs *regs);
 
diff -Nru a/arch/ppc64/boot/zlib.c b/arch/ppc64/boot/zlib.c
--- a/arch/ppc64/boot/zlib.c	Fri Apr 12 00:45:30 2002
+++ b/arch/ppc64/boot/zlib.c	Wed May 28 05:26:13 2003
@@ -322,8 +322,9 @@
 };
 
 
-int inflateReset(z)
-z_stream *z;
+int inflateReset(
+	z_stream *z
+)
 {
   uLong c;
 
@@ -410,9 +411,10 @@
 #define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
 #define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
 
-int inflate(z, f)
-z_stream *z;
-int f;
+int inflate(
+	z_stream *z,
+	int f	
+)
 {
   int r;
   uInt b;
@@ -527,8 +529,9 @@
  * will have been updated if need be.
  */
 
-int inflateIncomp(z)
-z_stream *z;
+int inflateIncomp(
+	z_stream *z
+)
 {
     if (z->state->mode != BLOCKS)
 	return Z_DATA_ERROR;
@@ -536,8 +539,9 @@
 }
 
 
-int inflateSync(z)
-z_stream *z;
+int inflateSync(
+	z_stream *z
+)
 {
   uInt n;       /* number of bytes to look at */
   Bytef *p;     /* pointer to bytes */
@@ -760,10 +764,11 @@
  */
 
 
-local void inflate_blocks_reset(s, z, c)
-inflate_blocks_statef *s;
-z_stream *z;
-uLongf *c;
+local void inflate_blocks_reset(
+	inflate_blocks_statef *s,
+	z_stream *z,
+	uLongf *c
+)
 {
   if (s->checkfn != Z_NULL)
     *c = s->check;
@@ -785,10 +790,11 @@
 }
 
 
-local inflate_blocks_statef *inflate_blocks_new(z, c, w)
-z_stream *z;
-check_func c;
-uInt w;
+local inflate_blocks_statef *inflate_blocks_new(
+	z_stream *z,
+	check_func c,
+	uInt w
+)
 {
   inflate_blocks_statef *s;
 
@@ -809,10 +815,11 @@
 }
 
 
-local int inflate_blocks(s, z, r)
-inflate_blocks_statef *s;
-z_stream *z;
-int r;
+local int inflate_blocks(
+	inflate_blocks_statef *s,
+	z_stream *z,
+	int r
+)
 {
   uInt t;               /* temporary storage */
   uLong b;              /* bit buffer */
@@ -1072,10 +1079,11 @@
 }
 
 
-local int inflate_blocks_free(s, z, c)
-inflate_blocks_statef *s;
-z_stream *z;
-uLongf *c;
+local int inflate_blocks_free(
+	inflate_blocks_statef *s,
+	z_stream *z,
+	uLongf *c
+)
 {
   inflate_blocks_reset(s, z, c);
   ZFREE(z, s->window, s->end - s->window);
@@ -1092,9 +1100,10 @@
  * BLOCKS).  On exit, the output will also be caught up, and the checksum
  * will have been updated if need be.
  */
-local int inflate_addhistory(s, z)
-inflate_blocks_statef *s;
-z_stream *z;
+local int inflate_addhistory(
+	inflate_blocks_statef *s,
+	z_stream *z
+)
 {
     uLong b;              /* bit buffer */  /* NOT USED HERE */
     uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
@@ -1243,15 +1252,16 @@
   uInt inflate_hufts;
 #endif
 
-local int huft_build(b, n, s, d, e, t, m, zs)
-uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
-uInt n;                 /* number of codes (assumed <= N_MAX) */
-uInt s;                 /* number of simple-valued codes (0..s-1) */
-uIntf *d;               /* list of base values for non-simple codes */
-uIntf *e;               /* list of extra bits for non-simple codes */  
-inflate_huft * FAR *t;  /* result: starting table */
-uIntf *m;               /* maximum lookup bits, returns actual */
-z_stream *zs;           /* for zalloc function */
+local int huft_build(
+	uIntf *b,               /* code lengths in bits (all assumed <= BMAX) */
+	uInt n,                 /* number of codes (assumed <= N_MAX) */
+	uInt s,                 /* number of simple-valued codes (0..s-1) */
+	uIntf *d,               /* list of base values for non-simple codes */
+	uIntf *e,               /* list of extra bits for non-simple codes */
+	inflate_huft * FAR *t,  /* result: starting table */
+	uIntf *m,               /* maximum lookup bits, returns actual */
+	z_stream *zs            /* for zalloc function */
+)
 /* Given a list of code lengths and a maximum table size, make a set of
    tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
    if the given code set is incomplete (the tables are still built in this
@@ -1446,11 +1456,12 @@
 }
 
 
-local int inflate_trees_bits(c, bb, tb, z)
-uIntf *c;               /* 19 code lengths */
-uIntf *bb;              /* bits tree desired/actual depth */
-inflate_huft * FAR *tb; /* bits tree result */
-z_stream *z;            /* for zfree function */
+local int inflate_trees_bits(
+	uIntf *c,               /* 19 code lengths */
+	uIntf *bb,              /* bits tree desired/actual depth */
+	inflate_huft * FAR *tb, /* bits tree result */
+	z_stream *z             /* for zfree function */
+)
 {
   int r;
 
@@ -1467,15 +1478,16 @@
 }
 
 
-local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
-uInt nl;                /* number of literal/length codes */
-uInt nd;                /* number of distance codes */
-uIntf *c;               /* that many (total) code lengths */
-uIntf *bl;              /* literal desired/actual bit depth */
-uIntf *bd;              /* distance desired/actual bit depth */
-inflate_huft * FAR *tl; /* literal/length tree result */
-inflate_huft * FAR *td; /* distance tree result */
-z_stream *z;            /* for zfree function */
+local int inflate_trees_dynamic(
+	uInt nl,                /* number of literal/length codes */
+	uInt nd,                /* number of distance codes */
+	uIntf *c,               /* that many (total) code lengths */
+	uIntf *bl,              /* literal desired/actual bit depth */
+	uIntf *bd,              /* distance desired/actual bit depth */
+	inflate_huft * FAR *tl, /* literal/length tree result */
+	inflate_huft * FAR *td, /* distance tree result */
+	z_stream *z             /* for zfree function */
+)
 {
   int r;
 
@@ -1552,11 +1564,12 @@
 }
 
 
-local int inflate_trees_fixed(bl, bd, tl, td)
-uIntf *bl;               /* literal desired/actual bit depth */
-uIntf *bd;               /* distance desired/actual bit depth */
-inflate_huft * FAR *tl;  /* literal/length tree result */
-inflate_huft * FAR *td;  /* distance tree result */
+local int inflate_trees_fixed(
+	uIntf *bl,               /* literal desired/actual bit depth */
+	uIntf *bd,               /* distance desired/actual bit depth */
+	inflate_huft * FAR *tl,  /* literal/length tree result */
+	inflate_huft * FAR *td   /* distance tree result */
+)
 {
   /* build fixed tables if not built already--lock out other instances */
   while (++fixed_lock > 1)
@@ -1674,10 +1687,13 @@
 };
 
 
-local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
-uInt bl, bd;
-inflate_huft *tl, *td;
-z_stream *z;
+local inflate_codes_statef *inflate_codes_new(
+	uInt bl,
+	uInt bd,
+	inflate_huft *tl,
+	inflate_huft *td,
+	z_stream *z
+)
 {
   inflate_codes_statef *c;
 
@@ -1695,10 +1711,11 @@
 }
 
 
-local int inflate_codes(s, z, r)
-inflate_blocks_statef *s;
-z_stream *z;
-int r;
+local int inflate_codes(
+	inflate_blocks_statef *s,
+	z_stream *z,
+	int r
+)
 {
   uInt j;               /* temporary storage */
   inflate_huft *t;      /* temporary pointer */
@@ -1855,9 +1872,10 @@
 }
 
 
-local void inflate_codes_free(c, z)
-inflate_codes_statef *c;
-z_stream *z;
+local void inflate_codes_free(
+	inflate_codes_statef *c,
+	z_stream *z
+)
 {
   ZFREE(z, c, sizeof(struct inflate_codes_state));
   Tracev((stderr, "inflate:       codes free\n"));
@@ -1870,10 +1888,11 @@
  */
 
 /* copy as much as possible from the sliding window to the output area */
-local int inflate_flush(s, z, r)
-inflate_blocks_statef *s;
-z_stream *z;
-int r;
+local int inflate_flush(
+	inflate_blocks_statef *s,
+	z_stream *z,
+	int r
+)
 {
   uInt n;
   Bytef *p, *q;
@@ -1957,11 +1976,14 @@
    at least ten.  The ten bytes are six bytes for the longest length/
    distance pair plus four bytes for overloading the bit buffer. */
 
-local int inflate_fast(bl, bd, tl, td, s, z)
-uInt bl, bd;
-inflate_huft *tl, *td;
-inflate_blocks_statef *s;
-z_stream *z;
+local int inflate_fast(
+	uInt bl,
+	uInt bd,
+	inflate_huft *tl,
+	inflate_huft *td,
+	inflate_blocks_statef *s,
+	z_stream *z
+)
 {
   inflate_huft *t;      /* temporary pointer */
   uInt e;               /* extra bits or operation */
diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
--- a/arch/sparc64/kernel/sparc64_ksyms.c	Mon May 12 18:59:21 2003
+++ b/arch/sparc64/kernel/sparc64_ksyms.c	Thu May 29 02:51:26 2003
@@ -94,8 +94,6 @@
 extern int compat_sys_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
 extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
 extern long sparc32_open(const char * filename, int flags, int mode);
-extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
-extern int unregister_ioctl32_conversion(unsigned int cmd);
 extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space);
                 
 extern int __ashrdi3(int, int);
@@ -233,10 +231,6 @@
 EXPORT_SYMBOL(pci_dma_sync_sg);
 EXPORT_SYMBOL(pci_dma_supported);
 #endif
-
-/* IOCTL32 emulation hooks. */
-EXPORT_SYMBOL(register_ioctl32_conversion);
-EXPORT_SYMBOL(unregister_ioctl32_conversion);
 
 /* I/O device mmaping on Sparc64. */
 EXPORT_SYMBOL(io_remap_page_range);
diff -Nru a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
--- a/arch/sparc64/kernel/sys_sparc.c	Wed Apr  9 21:09:00 2003
+++ b/arch/sparc64/kernel/sys_sparc.c	Thu May 29 03:03:01 2003
@@ -442,12 +442,6 @@
 	return err;
 }
 
-/* only AP+ systems have sys_aplib */
-asmlinkage int sys_aplib(void)
-{
-	return -ENOSYS;
-}
-
 asmlinkage int solaris_syscall(struct pt_regs *regs)
 {
 	static int count;
diff -Nru a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
--- a/arch/sparc64/kernel/systbls.S	Wed Apr 30 08:47:42 2003
+++ b/arch/sparc64/kernel/systbls.S	Thu May 29 03:03:01 2003
@@ -70,7 +70,7 @@
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep
 /*250*/	.word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
-	.word sys_aplib
+	.word sys_ni_syscall
 
 	/* Now the 64-bit native Linux syscall table. */
 
@@ -132,7 +132,7 @@
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
 /*250*/	.word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-	.word sys_aplib
+	.word sys_ni_syscall
 
 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
     defined(CONFIG_SOLARIS_EMUL_MODULE)
@@ -227,6 +227,6 @@
 	.word sunos_nosys, sunos_nosys, sunos_nosys
 	.word sunos_nosys, sunos_nosys
 /*250*/	.word sunos_nosys, sunos_nosys, sunos_nosys
-	.word sunos_nosys, sunos_nosys, sys_aplib
+	.word sunos_nosys, sunos_nosys, sys_ni_syscall
 
 #endif
diff -Nru a/arch/v850/as85ep1-rom.ld b/arch/v850/as85ep1-rom.ld
--- a/arch/v850/as85ep1-rom.ld	Fri Dec 20 22:18:52 2002
+++ b/arch/v850/as85ep1-rom.ld	Tue May 27 00:09:43 2003
@@ -1,9 +1,6 @@
 /* Linker script for the NEC AS85EP1 V850E evaluation board
    (CONFIG_V850E_AS85EP1), with kernel in ROM (CONFIG_ROM_KERNEL).  */
 
-/* Note, all symbols are prefixed with an extra `_' for compatibility with
-   the existing linux sources.  */
-
 MEMORY {
 	/* 4MB of flash ROM.  */
 	ROM   : ORIGIN = 0,          LENGTH = 0x00400000
@@ -12,7 +9,7 @@
 	SRAM  : ORIGIN = 0x00400000, LENGTH = 0x00100000
 
 	/* About 58MB of DRAM.  This can actually be at one of two
-	   positions, determined by jump JP3; we have to use the first
+	   positions, determined by jumper JP3; we have to use the first
 	   position because the second is partially out of processor
 	   instruction addressing range (though in the second position
 	   there's actually 64MB available).  */
diff -Nru a/arch/v850/kernel/entry.S b/arch/v850/kernel/entry.S
--- a/arch/v850/kernel/entry.S	Thu Apr  3 14:58:04 2003
+++ b/arch/v850/kernel/entry.S	Tue May 27 00:53:39 2003
@@ -29,28 +29,28 @@
 #define CSYM	C_SYMBOL_NAME
 
 
-/* The offset of the struct pt_regs in a `state save frame' on the stack.  */
+/* The offset of the struct pt_regs in a state-save-frame on the stack.  */
 #define PTO	STATE_SAVE_PT_OFFSET
 
 
-/* Save argument registers to the struct pt_regs pointed to by EP.  */
+/* Save argument registers to the state-save-frame pointed to by EP.  */
 #define SAVE_ARG_REGS							      \
 	sst.w	r6, PTO+PT_GPR(6)[ep];					      \
 	sst.w	r7, PTO+PT_GPR(7)[ep];					      \
 	sst.w	r8, PTO+PT_GPR(8)[ep];					      \
 	sst.w	r9, PTO+PT_GPR(9)[ep]
-/* Restore argument registers from the struct pt_regs pointed to by EP.  */
+/* Restore argument registers from the state-save-frame pointed to by EP.  */
 #define RESTORE_ARG_REGS						      \
 	sld.w	PTO+PT_GPR(6)[ep], r6;					      \
 	sld.w	PTO+PT_GPR(7)[ep], r7;					      \
 	sld.w	PTO+PT_GPR(8)[ep], r8;					      \
 	sld.w	PTO+PT_GPR(9)[ep], r9
 
-/* Save value return registers to the struct pt_regs pointed to by EP.  */
+/* Save value return registers to the state-save-frame pointed to by EP.  */
 #define SAVE_RVAL_REGS							      \
 	sst.w	r10, PTO+PT_GPR(10)[ep];				      \
 	sst.w	r11, PTO+PT_GPR(11)[ep]
-/* Restore value return registers from the struct pt_regs pointed to by EP.  */
+/* Restore value return registers from the state-save-frame pointed to by EP.  */
 #define RESTORE_RVAL_REGS						      \
 	sld.w	PTO+PT_GPR(10)[ep], r10;				      \
 	sld.w	PTO+PT_GPR(11)[ep], r11
@@ -81,13 +81,13 @@
 	sld.w	PTO+PT_GPR(18)[ep], r18;				      \
 	sld.w	PTO+PT_GPR(19)[ep], r19
 
-/* Save `call clobbered' registers to the struct pt_regs pointed to by EP.  */
+/* Save `call clobbered' registers to the state-save-frame pointed to by EP.  */
 #define SAVE_CALL_CLOBBERED_REGS					      \
 	SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS;				      \
 	SAVE_ARG_REGS;							      \
 	SAVE_RVAL_REGS;							      \
 	SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL
-/* Restore `call clobbered' registers from the struct pt_regs pointed to
+/* Restore `call clobbered' registers from the state-save-frame pointed to
    by EP.  */
 #define RESTORE_CALL_CLOBBERED_REGS					      \
 	RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS;			      \
@@ -96,19 +96,19 @@
 	RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL
 
 /* Save `call clobbered' registers except for the return-value registers
-   to the struct pt_regs pointed to by EP.  */
+   to the state-save-frame pointed to by EP.  */
 #define SAVE_CALL_CLOBBERED_REGS_NO_RVAL				      \
 	SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS;				      \
 	SAVE_ARG_REGS;							      \
 	SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL
 /* Restore `call clobbered' registers except for the return-value registers
-   from the struct pt_regs pointed to by EP.  */
+   from the state-save-frame pointed to by EP.  */
 #define RESTORE_CALL_CLOBBERED_REGS_NO_RVAL				      \
 	RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS;			      \
 	RESTORE_ARG_REGS;						      \
 	RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL
 
-/* Save `call saved' registers to the struct pt_regs pointed to by EP.  */
+/* Save `call saved' registers to the state-save-frame pointed to by EP.  */
 #define SAVE_CALL_SAVED_REGS						      \
 	sst.w	r2, PTO+PT_GPR(2)[ep];					      \
 	sst.w	r20, PTO+PT_GPR(20)[ep];				      \
@@ -121,7 +121,7 @@
 	sst.w	r27, PTO+PT_GPR(27)[ep];				      \
 	sst.w	r28, PTO+PT_GPR(28)[ep];				      \
 	sst.w	r29, PTO+PT_GPR(29)[ep]
-/* Restore `call saved' registers from the struct pt_regs pointed to by EP.  */
+/* Restore `call saved' registers from the state-save-frame pointed to by EP.  */
 #define RESTORE_CALL_SAVED_REGS						      \
 	sld.w	PTO+PT_GPR(2)[ep], r2;					      \
 	sld.w	PTO+PT_GPR(20)[ep], r20;				      \
@@ -136,12 +136,12 @@
 	sld.w	PTO+PT_GPR(29)[ep], r29
 
 
-/* Save the PC stored in the special register SAVEREG to the struct pt_regs
+/* Save the PC stored in the special register SAVEREG to the state-save-frame
    pointed to by EP.  r19 is clobbered.  */
 #define SAVE_PC(savereg)						      \
 	stsr	SR_ ## savereg, r19;					      \
 	sst.w	r19, PTO+PT_PC[ep]
-/* Restore the PC from the struct pt_regs pointed to by EP, to the special
+/* Restore the PC from the state-save-frame pointed to by EP, to the special
    register SAVEREG.  LP is clobbered (it is used as a scratch register
    because the POP_STATE macro restores it, and this macro is usually used
    inside POP_STATE).  */
@@ -149,11 +149,11 @@
 	sld.w	PTO+PT_PC[ep], lp;					      \
 	ldsr	lp, SR_ ## savereg
 /* Save the PSW register stored in the special register SAVREG to the
-   struct pt_regs pointed to by EP r19 is clobbered.  */
+   state-save-frame pointed to by EP.  r19 is clobbered.  */
 #define SAVE_PSW(savereg)						      \
 	stsr	SR_ ## savereg, r19;					      \
 	sst.w	r19, PTO+PT_PSW[ep]
-/* Restore the PSW register from the struct pt_regs pointed to by EP, to
+/* Restore the PSW register from the state-save-frame pointed to by EP, to
    the special register SAVEREG.  LP is clobbered (it is used as a scratch
    register because the POP_STATE macro restores it, and this macro is
    usually used inside POP_STATE).  */
@@ -161,7 +161,7 @@
 	sld.w	PTO+PT_PSW[ep], lp;					      \
 	ldsr	lp, SR_ ## savereg
 
-/* Save CTPC/CTPSW/CTBP registers to the struct pt_regs pointed to by REG.  
+/* Save CTPC/CTPSW/CTBP registers to the state-save-frame pointed to by REG.
    r19 is clobbered.  */
 #define SAVE_CT_REGS							      \
 	stsr	SR_CTPC, r19;						      \
@@ -170,7 +170,7 @@
 	sst.w	r19, PTO+PT_CTPSW[ep];					      \
 	stsr	SR_CTBP, r19;						      \
 	sst.w	r19, PTO+PT_CTBP[ep]
-/* Restore CTPC/CTPSW/CTBP registers from the struct pt_regs pointed to by EP.
+/* Restore CTPC/CTPSW/CTBP registers from the state-save-frame pointed to by EP.
    LP is clobbered (it is used as a scratch register because the POP_STATE
    macro restores it, and this macro is usually used inside POP_STATE).  */
 #define RESTORE_CT_REGS							      \
@@ -182,10 +182,11 @@
 	ldsr	lp, SR_CTBP
 
 
-/* Push register state, except for the stack pointer, on the stack in the form
-   of a struct pt_regs, in preparation for a system call.  This macro makes
-   sure that `special' registers, system registers; TYPE identifies the set of
-   extra registers to be saved as well.  EP is clobbered.  */
+/* Push register state, except for the stack pointer, on the stack in the
+   form of a state-save-frame (plus some extra padding), in preparation for
+   a system call.  This macro makes sure that the EP, GP, and LP
+   registers are saved, and TYPE identifies the set of extra registers to
+   be saved as well.  Also copies (the new value of) SP to EP.  */
 #define PUSH_STATE(type)						      \
 	addi	-STATE_SAVE_SIZE, sp, sp; /* Make room on the stack.  */      \
 	st.w	ep, PTO+PT_GPR(GPR_EP)[sp];				      \
@@ -193,8 +194,8 @@
 	sst.w	gp, PTO+PT_GPR(GPR_GP)[ep];				      \
 	sst.w	lp, PTO+PT_GPR(GPR_LP)[ep];				      \
 	type ## _STATE_SAVER
-/* Pop a register state, except for the stack pointer, from the struct pt_regs
-   on the stack.  */
+/* Pop a register state pushed by PUSH_STATE, except for the stack pointer,
+   from the the stack.  */
 #define POP_STATE(type)							      \
 	mov	sp, ep;							      \
 	type ## _STATE_RESTORER;					      \
@@ -205,7 +206,7 @@
 
 
 /* Switch to the kernel stack if necessary, and push register state on the
-   stack in the form of a struct pt_regs.  Also load the current task
+   stack in the form of a state-save-frame.  Also load the current task
    pointer if switching from user mode.  The stack-pointer (r3) should have
    already been saved to the memory location SP_SAVE_LOC (the reason for
    this is that the interrupt vectors may be beyond a 22-bit signed offset
@@ -234,25 +235,30 @@
 	sst.w	syscall_num, PTO+PT_CUR_SYSCALL[ep]
 
 
-/* Save register state not normally saved by PUSH_STATE for TYPE.  */
+/* Save register state not normally saved by PUSH_STATE for TYPE, to the
+   state-save-frame on the stack; also copies SP to EP.  r19 may be trashed. */
 #define SAVE_EXTRA_STATE(type)						      \
-        mov	sp, ep;							      \
+	mov	sp, ep;							      \
 	type ## _EXTRA_STATE_SAVER
-/* Restore register state not normally restored by POP_STATE for TYPE.  */
+/* Restore register state not normally restored by POP_STATE for TYPE,
+   from the state-save-frame on the stack; also copies SP to EP.
+   r19 may be trashed.  */
 #define RESTORE_EXTRA_STATE(type)					      \
-        mov	sp, ep;							      \
+	mov	sp, ep;							      \
 	type ## _EXTRA_STATE_RESTORER
 
-/* Save any call-clobbered registers not normally saved by PUSH_STATE
-   for TYPE.  */
-#define SAVE_EXTRA_STATE_FOR_FUNCALL(type)				      \
-        mov	sp, ep;							      \
-	type ## _FUNCALL_EXTRA_STATE_SAVER
-/* Restore any call-clobbered registers not normally restored by POP_STATE for
-   TYPE.  */
-#define RESTORE_EXTRA_STATE_FOR_FUNCALL(type)				      \
-        mov	sp, ep;							      \
-	type ## _FUNCALL_EXTRA_STATE_RESTORER
+/* Save any call-clobbered registers not normally saved by PUSH_STATE for
+   TYPE, to the state-save-frame on the stack.
+   EP may be trashed, but is not guaranteed to contain a copy of SP
+   (unlike after most SAVE_... macros).  r19 may be trashed.  */
+#define SAVE_EXTRA_STATE_FOR_SCHEDULE(type)				      \
+	type ## _SCHEDULE_EXTRA_STATE_SAVER
+/* Restore any call-clobbered registers not normally restored by
+   POP_STATE for TYPE, to the state-save-frame on the stack.
+   EP may be trashed, but is not guaranteed to contain a copy of SP
+   (unlike after most RESTORE_... macros).  r19 may be trashed.  */
+#define RESTORE_EXTRA_STATE_FOR_SCHEDULE(type)				      \
+	type ## _SCHEDULE_EXTRA_STATE_RESTORER
 
 
 /* These are extra_state_saver/restorer values for a user trap.  Note
@@ -263,36 +269,48 @@
    caller of the syscall function should have saved them.  */
 
 #define TRAP_RET reti
-/* Traps don't save call-clobbered registers (but do still save arg regs).  */
+/* Traps don't save call-clobbered registers (but do still save arg regs).
+   We preserve PSw to keep long-term state, namely interrupt status (for traps
+   from kernel-mode), and the single-step flag (for user traps).  */
 #define TRAP_STATE_SAVER						      \
 	SAVE_ARG_REGS;							      \
-	SAVE_PC(EIPC)
+	SAVE_PC(EIPC);							      \
+	SAVE_PSW(EIPSW)
 /* When traps return, they just leave call-clobbered registers (except for arg
-   regs) with whatever value they have from the kernel.  */
+   regs) with whatever value they have from the kernel.  Traps don't preserve
+   the PSW, but we zero EIPSW to ensure it doesn't contain anything dangerous
+   (in particular, the single-step flag).  */
 #define TRAP_STATE_RESTORER						      \
 	RESTORE_ARG_REGS;						      \
-	RESTORE_PC(EIPC)
+	RESTORE_PC(EIPC);						      \
+	RESTORE_PSW(EIPSW)
 /* Save registers not normally saved by traps.  We need to save r12, even
    though it's nominally call-clobbered, because it's used when restarting
    a system call (the signal-handling path uses SAVE_EXTRA_STATE, and
-   expects r12 to be restored when the trap returns).  Similarly, we must
-   save the PSW, so that it's at least in a known state in the the pt_regs
-   structure.  */
+   expects r12 to be restored when the trap returns).  */
 #define TRAP_EXTRA_STATE_SAVER						      \
 	SAVE_RVAL_REGS;							      \
 	sst.w	r12, PTO+PT_GPR(12)[ep];				      \
 	SAVE_CALL_SAVED_REGS;						      \
-	SAVE_PSW(EIPSW);						      \
 	SAVE_CT_REGS
 #define TRAP_EXTRA_STATE_RESTORER					      \
 	RESTORE_RVAL_REGS;						      \
 	sld.w	PTO+PT_GPR(12)[ep], r12;				      \
 	RESTORE_CALL_SAVED_REGS;					      \
-	RESTORE_PSW(EIPSW);						      \
 	RESTORE_CT_REGS
-#define TRAP_FUNCALL_EXTRA_STATE_SAVER					      \
+/* Save registers prior to calling scheduler (just before trap returns).
+   We have to save the return-value registers to preserve the trap's return
+   value.  Note that ..._SCHEDULE_EXTRA_STATE_SAVER, unlike most ..._SAVER
+   macros, is required to setup EP itself if EP is needed (this is because
+   in many cases, the macro is empty).  */
+#define TRAP_SCHEDULE_EXTRA_STATE_SAVER					      \
+	mov sp, ep;							      \
 	SAVE_RVAL_REGS
-#define TRAP_FUNCALL_EXTRA_STATE_RESTORER				      \
+/* Note that ..._SCHEDULE_EXTRA_STATE_RESTORER, unlike most ..._RESTORER
+   macros, is required to setup EP itself if EP is needed (this is because
+   in many cases, the macro is empty).  */
+#define TRAP_SCHEDULE_EXTRA_STATE_RESTORER				      \
+	mov sp, ep;							      \
 	RESTORE_RVAL_REGS
 
 /* Register saving/restoring for maskable interrupts.  */
@@ -311,8 +329,8 @@
 #define IRQ_EXTRA_STATE_RESTORER					      \
 	RESTORE_CALL_SAVED_REGS;					      \
 	RESTORE_CT_REGS
-#define IRQ_FUNCALL_EXTRA_STATE_SAVER       /* nothing */
-#define IRQ_FUNCALL_EXTRA_STATE_RESTORER    /* nothing */
+#define IRQ_SCHEDULE_EXTRA_STATE_SAVER	     /* nothing */
+#define IRQ_SCHEDULE_EXTRA_STATE_RESTORER    /* nothing */
 
 /* Register saving/restoring for non-maskable interrupts.  */
 #define NMI_RET reti
@@ -330,8 +348,8 @@
 #define NMI_EXTRA_STATE_RESTORER					      \
 	RESTORE_CALL_SAVED_REGS;					      \
 	RESTORE_CT_REGS
-#define NMI_FUNCALL_EXTRA_STATE_SAVER       /* nothing */
-#define NMI_FUNCALL_EXTRA_STATE_RESTORER    /* nothing */
+#define NMI_SCHEDULE_EXTRA_STATE_SAVER	     /* nothing */
+#define NMI_SCHEDULE_EXTRA_STATE_RESTORER    /* nothing */
 
 /* Register saving/restoring for debug traps.  */
 #define DBTRAP_RET .long 0x014607E0 /* `dbret', but gas doesn't support it. */
@@ -349,8 +367,8 @@
 #define DBTRAP_EXTRA_STATE_RESTORER					      \
 	RESTORE_CALL_SAVED_REGS;					      \
 	RESTORE_CT_REGS
-#define DBTRAP_FUNCALL_EXTRA_STATE_SAVER       /* nothing */
-#define DBTRAP_FUNCALL_EXTRA_STATE_RESTORER    /* nothing */
+#define DBTRAP_SCHEDULE_EXTRA_STATE_SAVER	/* nothing */
+#define DBTRAP_SCHEDULE_EXTRA_STATE_RESTORER	/* nothing */
 
 /* Register saving/restoring for a context switch.  We don't need to save
    too many registers, because context-switching looks like a function call
@@ -372,14 +390,14 @@
 	RESTORE_CT_REGS
 
 
-/* Restore register state from the struct pt_regs on the stack, switch back
+/* Restore register state from the state-save-frame on the stack, switch back
    to the user stack if necessary, and return from the trap/interrupt.
    EXTRA_STATE_RESTORER is a sequence of assembly language statements to
    restore anything not restored by this macro.  Only registers not saved by
    the C compiler are restored (that is, R3(sp), R4(gp), R31(lp), and
    anything restored by EXTRA_STATE_RESTORER).  */
 #define RETURN(type)							      \
-        ld.b	PTO+PT_KERNEL_MODE[sp], r19;				      \
+	ld.b	PTO+PT_KERNEL_MODE[sp], r19;				      \
 	di;				/* Disable interrupts */	      \
 	cmp	r19, r0;		/* See if returning to kernel mode, */\
 	bne	2f;			/* ... if so, skip resched &c.  */    \
@@ -390,33 +408,34 @@
 	ld.w	TI_FLAGS[r18], r19;					      \
 	andi	_TIF_NEED_RESCHED, r19, r0;				      \
 	bnz	3f;			/* Call the scheduler.  */	      \
-	andi	_TIF_SIGPENDING, r19, r0;				      \
-	bnz	4f;			/* Signals to handle, handle them */  \
+5:	andi	_TIF_SIGPENDING, r19, r18;				      \
+	ld.w	TASK_PTRACE[CURRENT_TASK], r19; /* ptrace flags */	      \
+	or	r18, r19;		/* see if either is non-zero */	      \
+	bnz	4f;			/* if so, handle them */	      \
 									      \
-/* Return to user state.  */					   	      \
+/* Return to user state.  */						      \
 1:	st.b	r0, KM;			/* Now officially in user state. */   \
 									      \
 /* Final return.  The stack-pointer fiddling is not needed when returning     \
    to kernel-mode, but they don't hurt, and this way we can share the	      \
-   (somtimes rather lengthy) POP_STATE macro.  */			      \
+   (sometimes rather lengthy) POP_STATE macro.  */			      \
 2:	POP_STATE(type);						      \
 	st.w	sp, KSP;		/* Save the kernel stack pointer. */  \
-	ld.w    PT_GPR(GPR_SP)-PT_SIZE[sp], sp; /* Restore stack pointer. */  \
+	ld.w	PT_GPR(GPR_SP)-PT_SIZE[sp], sp; /* Restore stack pointer. */  \
 	type ## _RET;			/* Return from the trap/interrupt. */ \
 									      \
 /* Call the scheduler before returning from a syscall/trap. */		      \
-3:	SAVE_EXTRA_STATE_FOR_FUNCALL(type); /* Prepare for funcall. */	      \
-	jarl	CSYM(schedule), lp;	/* Call scheduler */		      \
+3:	SAVE_EXTRA_STATE_FOR_SCHEDULE(type); /* Prepare to call scheduler. */ \
+	jarl	call_scheduler, lp;	/* Call scheduler */		      \
 	di;				/* The scheduler enables interrupts */\
-	RESTORE_EXTRA_STATE_FOR_FUNCALL(type);				      \
+	RESTORE_EXTRA_STATE_FOR_SCHEDULE(type);				      \
 	GET_CURRENT_THREAD(r18);					      \
 	ld.w	TI_FLAGS[r18], r19;					      \
-	andi	_TIF_SIGPENDING, r19, r0;				      \
-	bz	1b;			/* No signals, return.  */	      \
-	/* Signals to handle, fall through to handle them.  */		      \
+	br	5b;			/* Continue with return path. */      \
 									      \
-/* Handle a signal return.  */						      \
-4:      /* Not all registers are saved by the normal trap/interrupt entry     \
+/* Handle a signal or ptraced process return.				      \
+   r18 should be non-zero if there are pending signals.  */		      \
+4:	/* Not all registers are saved by the normal trap/interrupt entry     \
 	   points (for instance, call-saved registers (because the normal     \
 	   C-compiler calling sequence in the kernel makes sure they're	      \
 	   preserved), and call-clobbered registers in the case of	      \
@@ -424,12 +443,9 @@
 	   complete register state.  Here we save anything not saved by	      \
 	   the normal entry sequence, so that it may be safely restored	      \
 	   (in a possibly modified form) after do_signal returns.  */	      \
-        SAVE_EXTRA_STATE(type);		/* Save state not saved by entry. */  \
-	movea	PTO, sp, r6;		/* Arg 1: struct pt_regs *regs */     \
-	mov	r0, r7;			/* Arg 2: sigset_t *oldset */	      \
-	jarl	CSYM(do_signal), lp;	/* Handle any signals */	      \
-	di;				/* sig handling enables interrupts */ \
-        RESTORE_EXTRA_STATE(type);	/* Restore extra regs.  */	      \
+	SAVE_EXTRA_STATE(type);		/* Save state not saved by entry. */  \
+	jarl	handle_signal_or_ptrace_return, lp;			      \
+	RESTORE_EXTRA_STATE(type);	/* Restore extra regs.  */	      \
 	br	1b
 
 
@@ -471,7 +487,7 @@
  *   Return value in r10
  */
 G_ENTRY(trap):
-	SAVE_STATE (TRAP, r12, ENTRY_SP) // Save registers. 
+	SAVE_STATE (TRAP, r12, ENTRY_SP) // Save registers.
 	stsr	SR_ECR, r19		// Find out which trap it was.
 	ei				// Enable interrupts.
 	mov	hilo(ret_from_trap), lp	// where the trap should return
@@ -481,12 +497,12 @@
 	// numbers into the (0-31) << 2 range we want, (3) set the flags.
 	shl	27, r19			// chop off all high bits
 	shr	25, r19			// scale back down and then << 2
-	bnz	2f			// See if not trap 0. 
+	bnz	2f			// See if not trap 0.
 
-	// Trap 0 is a `short' system call, skip general trap table. 
-	MAKE_SYS_CALL			// Jump to the syscall function. 
+	// Trap 0 is a `short' system call, skip general trap table.
+	MAKE_SYS_CALL			// Jump to the syscall function.
 
-2:	// For other traps, use a table lookup. 
+2:	// For other traps, use a table lookup.
 	mov	hilo(CSYM(trap_table)), r18
 	add	r19, r18
 	ld.w	0[r18], r18
@@ -505,6 +521,7 @@
 	RETURN(TRAP)
 END(ret_from_trap)
 
+
 /* This the initial entry point for a new child thread, with an appropriate
    stack in place that makes it look the the child is in the middle of an
    syscall.  This function is actually `returned to' from switch_thread
@@ -538,7 +555,7 @@
 	mov	hilo(ret_from_long_syscall), lp
 
 	MAKE_SYS_CALL			// Jump to the syscall function.
-END(syscall_long)	
+END(syscall_long)
 
 /* Entry point used to return from a long syscall.  Only needed to restore
    r13/r14 if the general trap mechanism doesnt' do so.  */
@@ -554,11 +571,14 @@
 
 L_ENTRY(sys_fork_wrapper):
 #ifdef CONFIG_MMU
-	addi	SIGCHLD, r0, r6		// Arg 0: flags
+	addi	SIGCHLD, r0, r6		   // Arg 0: flags
 	ld.w	PTO+PT_GPR(GPR_SP)[sp], r7 // Arg 1: child SP (use parent's)
-	movea	PTO, sp, r8		// Arg 2: parent context
-	mov	hilo(CSYM(fork_common)), r18// Where the real work gets done
-	br	save_extra_state_tramp	// Save state and go there
+	movea	PTO, sp, r8		   // Arg 2: parent context
+	mov	r0, r9			   // Arg 3/4/5: 0
+	st.w	r0, 16[sp]
+	st.w	r0, 20[sp]
+	mov	hilo(CSYM(do_fork)), r18   // Where the real work gets done
+	br	save_extra_state_tramp	   // Save state and go there
 #else
 	// fork almost works, enough to trick you into looking elsewhere :-(
 	addi	-EINVAL, r0, r10
@@ -569,18 +589,24 @@
 L_ENTRY(sys_vfork_wrapper):
 	addi	CLONE_VFORK | CLONE_VM | SIGCHLD, r0, r6 // Arg 0: flags
 	ld.w	PTO+PT_GPR(GPR_SP)[sp], r7 // Arg 1: child SP (use parent's)
-	movea	PTO, sp, r8		// Arg 2: parent context
-	mov	hilo(CSYM(fork_common)), r18// Where the real work gets done
-	br	save_extra_state_tramp	// Save state and go there
+	movea	PTO, sp, r8		   // Arg 2: parent context
+	mov	r0, r9			   // Arg 3/4/5: 0
+	st.w	r0, 16[sp]
+	st.w	r0, 20[sp]
+	mov	hilo(CSYM(do_fork)), r18   // Where the real work gets done
+	br	save_extra_state_tramp	   // Save state and go there
 END(sys_vfork_wrapper)
 
 L_ENTRY(sys_clone_wrapper):
-	ld.w	PTO+PT_GPR(GPR_SP)[sp], r19 // parent's stack pointer
-        cmp	r7, r0			// See if child SP arg (arg 1) is 0.
-	cmov	z, r19, r7, r7		// ... and use the parent's if so. 
-	movea	PTO, sp, r8		// Arg 2: parent context
-	mov	hilo(CSYM(fork_common)), r18// Where the real work gets done
-	br	save_extra_state_tramp	// Save state and go there
+	ld.w	PTO+PT_GPR(GPR_SP)[sp], r19// parent's stack pointer
+	cmp	r7, r0			   // See if child SP arg (arg 1) is 0.
+	cmov	z, r19, r7, r7		   // ... and use the parent's if so.
+	movea	PTO, sp, r8		   // Arg 2: parent context
+	mov	r0, r9			   // Arg 3/4/5: 0
+	st.w	r0, 16[sp]
+	st.w	r0, 20[sp]
+	mov	hilo(CSYM(do_fork)), r18   // Where the real work gets done
+	br	save_extra_state_tramp	   // Save state and go there
 END(sys_clone_wrapper)
 
 
@@ -598,8 +624,8 @@
 END(sys_sigsuspend_wrapper)
 L_ENTRY(sys_rt_sigsuspend_wrapper):
 	movea	PTO, sp, r8		// add user context as 3rd arg
-	mov	hilo(CSYM(sys_rt_sigsuspend)), r18	// syscall function
-	jarl	save_extra_state_tramp, lp	// Save state and do it
+	mov	hilo(CSYM(sys_rt_sigsuspend)), r18 // syscall function
+	jarl	save_extra_state_tramp, lp	   // Save state and do it
 	br	restore_extra_regs_and_ret_from_trap
 END(sys_rt_sigsuspend_wrapper)
 
@@ -610,10 +636,9 @@
 	br	restore_extra_regs_and_ret_from_trap
 END(sys_sigreturn_wrapper)
 L_ENTRY(sys_rt_sigreturn_wrapper):
-        SAVE_EXTRA_STATE(TRAP)		// Save state not saved by entry.
 	movea	PTO, sp, r6		// add user context as 1st arg
-	mov	hilo(CSYM(sys_rt_sigreturn)), r18	// syscall function
-	jarl	save_extra_state_tramp, lp	// Save state and do it
+	mov	hilo(CSYM(sys_rt_sigreturn)), r18// syscall function
+	jarl	save_extra_state_tramp, lp	 // Save state and do it
 	br	restore_extra_regs_and_ret_from_trap
 END(sys_rt_sigreturn_wrapper)
 
@@ -637,7 +662,7 @@
  * indirect jump).
  */
 G_ENTRY(irq):
-	SAVE_STATE (IRQ, r0, ENTRY_SP)	// Save registers. 
+	SAVE_STATE (IRQ, r0, ENTRY_SP)	// Save registers.
 
 	stsr	SR_ECR, r6		// Find out which interrupt it was.
 	movea	PTO, sp, r7		// User regs are arg2
@@ -657,7 +682,7 @@
 	RETURN(IRQ)
 END(irq)
 
-	
+
 /*
  * Debug trap / illegal-instruction exception
  *
@@ -668,22 +693,50 @@
  * indirect jump).
  */
 G_ENTRY(dbtrap):
-	SAVE_STATE (DBTRAP, r0, ENTRY_SP)// Save registers. 
+	SAVE_STATE (DBTRAP, r0, ENTRY_SP)// Save registers.
+
+	/* First see if we came from kernel mode; if so, the dbtrap
+	   instruction has a special meaning, to set the DIR (`debug
+	   information register') register.  This is because the DIR register
+	   can _only_ be manipulated/read while in `debug mode,' and debug
+	   mode is only active while we're inside the dbtrap handler.  The
+	   exact functionality is:  { DIR = (DIR | r6) & ~r7; return DIR; }. */
+	ld.b	PTO+PT_KERNEL_MODE[sp], r19
+	cmp	r19, r0
+	bz	1f
+
+	stsr	SR_DIR, r10
+	or	r6, r10
+	not	r7, r7
+	and	r7, r10
+	ldsr	r10, SR_DIR
+	stsr	SR_DIR, r10		// Confirm the value we set
+	st.w	r10, PTO+PT_GPR(10)[sp]	// return it
+	br	3f
+
+1:	ei				// Enable interrupts.
+
+	/* The default signal type we raise.  */
+	mov	SIGTRAP, r6
+
+	/* See if it's a single-step trap.  */
+	stsr	SR_DBPSW, r19
+	andi	0x0800, r19, r19
+	bnz	2f
 
 	/* Look to see if the preceding instruction was is a dbtrap or not,
 	   to decide which signal we should use.  */
 	stsr	SR_DBPC, r19		// PC following trapping insn
 	ld.hu	-2[r19], r19
-	mov	SIGTRAP, r6
 	ori	0xf840, r0, r20		// DBTRAP insn
 	cmp	r19, r20		// Was this trap caused by DBTRAP?
 	cmov	ne, SIGILL, r6, r6	// Choose signal appropriately
 
 	/* Raise the desired signal.  */
-	mov	CURRENT_TASK, r7	// Arg 1: task
-	jarl	CSYM(force_sig), lp	// tail call
+2:	mov	CURRENT_TASK, r7	// Arg 1: task
+	jarl	CSYM(send_sig), lp	// tail call
 
-	RETURN(DBTRAP)
+3:	RETURN(DBTRAP)
 END(dbtrap)
 
 
@@ -725,9 +778,93 @@
 
 
 /*
+ * Invoke the scheduler, called from the trap/irq kernel exit path.
+ *
+ * This basically just calls `schedule', but also arranges for extra
+ * registers to be saved for ptrace'd processes, so ptrace can modify them.
+ */
+L_ENTRY(call_scheduler):
+	ld.w	TASK_PTRACE[CURRENT_TASK], r19	// See if task is ptrace'd
+	cmp	r19, r0
+	bnz	1f			// ... yes, do special stuff
+	jr	CSYM(schedule)		// ... no, just tail-call scheduler
+
+	// Save extra regs for ptrace'd task.  We want to save anything
+	// that would otherwise only be `implicitly' saved by the normal
+	// compiler calling-convention.
+1:	mov	sp, ep			// Setup EP for SAVE_CALL_SAVED_REGS
+	SAVE_CALL_SAVED_REGS		// Save call-saved registers to stack
+	mov	lp, r20			// Save LP in a callee-saved register
+
+	jarl	CSYM(schedule), lp	// Call scheduler
+
+	mov	r20, lp
+	mov	sp, ep			// We can't rely on EP after return
+	RESTORE_CALL_SAVED_REGS		// Restore (possibly modified) regs
+	jmp	[lp]			// Return to the return path
+END(call_scheduler)
+
+
+/*
+ * This is an out-of-line handler for two special cases during the kernel
+ * trap/irq exit sequence:
+ *
+ *  (1) If r18 is non-zero then a signal needs to be handled, which is
+ *	done, and then the caller returned to.
+ *
+ *  (2) If r18 is non-zero then we're returning to a ptraced process, which
+ *	has several special cases -- single-stepping and trap tracing, both
+ *	of which require using the `dbret' instruction to exit the kernel
+ *	instead of the normal `reti' (this is because the CPU not correctly
+ *	single-step after a reti).  In this case, of course, this handler
+ *	never returns to the caller.
+ *
+ * In either case, all registers should have been saved to the current
+ * state-save-frame on the stack, except for callee-saved registers.
+ *
+ * [These two different cases are combined merely to avoid bloating the
+ * macro-inlined code, not because they really make much sense together!]
+ */
+L_ENTRY(handle_signal_or_ptrace_return):
+	cmp	r18, r0			// See if handling a signal
+	bz	1f			// ... nope, go do ptrace return
+
+	// Handle a signal
+	mov	lp, r20			// Save link-pointer
+	mov	r10, r21		// Save return-values (for trap)
+	mov	r11, r22
+
+	movea	PTO, sp, r6		// Arg 1: struct pt_regs *regs
+	mov	r0, r7			// Arg 2: sigset_t *oldset
+	jarl	CSYM(do_signal), lp	// Handle the signal
+	di				// sig handling enables interrupts
+
+	mov	r20, lp			// Restore link-pointer
+	mov	r21, r10		// Restore return-values (for trap)
+	mov	r22, r11
+	ld.w	TASK_PTRACE[CURRENT_TASK], r19  // check ptrace flags too
+	cmp	r19, r0
+	bnz	1f			// ... some set, so look more
+2:	jmp	[lp]			// ... none set, so return normally
+
+	// ptrace return
+1:	ld.w	PTO+PT_PSW[sp], r19	// Look at user-processes's flags
+	andi	0x0800, r19, r19	// See if single-step flag is set
+	bz	2b			// ... nope, return normally
+
+	// Return as if from a dbtrap insn
+	st.b	r0, KM			// Now officially in user state.
+	POP_STATE(DBTRAP)		// Restore regs
+	st.w	sp, KSP			// Save the kernel stack pointer.
+	ld.w	PT_GPR(GPR_SP)-PT_SIZE[sp], sp // Restore user stack pointer.
+	DBTRAP_RET			// Return from the trap/interrupt.
+END(handle_signal_or_ptrace_return)
+
+
+/*
  * This is where we switch between two threads.  The arguments are:
  *   r6 -- pointer to the struct thread for the `current' process
- *   r7 -- pointer to the struct thread for the `new' process.  
+ *   r7 -- pointer to the struct thread for the `new' process.
  * when this function returns, it will return to the new thread.
  */
 C_ENTRY(switch_thread):
@@ -754,8 +891,8 @@
 
 	.align 4
 C_DATA(trap_table):
-	.long bad_trap_wrapper		// trap 0, doesn't use trap table. 
-	.long syscall_long		// trap 1, `long' syscall. 
+	.long bad_trap_wrapper		// trap 0, doesn't use trap table.
+	.long syscall_long		// trap 1, `long' syscall.
 	.long bad_trap_wrapper
 	.long bad_trap_wrapper
 	.long bad_trap_wrapper
@@ -774,7 +911,7 @@
 
 
 	.section .rodata
-	
+
 	.align 4
 C_DATA(sys_call_table):
 	.long CSYM(sys_restart_syscall)	// 0
@@ -835,7 +972,7 @@
 	.long CSYM(sys_fcntl)		// 55
 	.long CSYM(sys_ni_syscall)	// was: mpx
 	.long CSYM(sys_setpgid)
-	.long CSYM(sys_ni_syscall) 	// was: ulimit
+	.long CSYM(sys_ni_syscall)	// was: ulimit
 	.long CSYM(sys_ni_syscall)
 	.long CSYM(sys_umask)		// 60
 	.long CSYM(sys_chroot)
@@ -875,7 +1012,7 @@
 	.long CSYM(sys_fchown)		// 95
 	.long CSYM(sys_getpriority)
 	.long CSYM(sys_setpriority)
-	.long CSYM(sys_ni_syscall) 	// was: profil
+	.long CSYM(sys_ni_syscall)	// was: profil
 	.long CSYM(sys_statfs)
 	.long CSYM(sys_fstatfs)		// 100
 	.long CSYM(sys_ni_syscall)	// i386: ioperm
@@ -900,7 +1037,7 @@
 	.long sys_clone_wrapper		// 120
 	.long CSYM(sys_setdomainname)
 	.long CSYM(sys_newuname)
-	.long CSYM(sys_ni_syscall)	// i386: modify_ldt, m68k: cacheflush 
+	.long CSYM(sys_ni_syscall)	// i386: modify_ldt, m68k: cacheflush
 	.long CSYM(sys_adjtimex)
 	.long CSYM(sys_ni_syscall)	// 125 - sys_mprotect
 	.long CSYM(sys_sigprocmask)
@@ -937,7 +1074,7 @@
 	.long CSYM(sys_sched_getscheduler)
 	.long CSYM(sys_sched_yield)
 	.long CSYM(sys_sched_get_priority_max)
-	.long CSYM(sys_sched_get_priority_min)  // 160
+	.long CSYM(sys_sched_get_priority_min)	// 160
 	.long CSYM(sys_sched_rr_get_interval)
 	.long CSYM(sys_nanosleep)
 	.long CSYM(sys_ni_syscall)	// sys_mremap
diff -Nru a/arch/v850/kernel/head.S b/arch/v850/kernel/head.S
--- a/arch/v850/kernel/head.S	Sun Nov 24 17:34:43 2002
+++ b/arch/v850/kernel/head.S	Tue May 27 00:09:43 2003
@@ -39,7 +39,7 @@
 	cmp	r19, r20
 	bne	1f			// Guard was not active
 
-	// If we get here, the reset guard was active.	Load up some
+	// If we get here, the reset guard was active.  Load up some
 	// interesting values as arguments, and jump to the handler.
 	st.w	r0, RESET_GUARD		// Allow further resets to succeed
 	mov	lp, r6			// Arg 0: return address
@@ -53,7 +53,7 @@
 
 1:	st.w	r20, RESET_GUARD	// Turn on reset guard
 #endif /* CONFIG_RESET_GUARD */
-  
+
 	// Setup a temporary stack for doing pre-initialization function calls.
 	// 
 	// We can't use the initial kernel stack, because (1) it may be
diff -Nru a/arch/v850/kernel/irq.c b/arch/v850/kernel/irq.c
--- a/arch/v850/kernel/irq.c	Sat Mar  8 14:50:43 2003
+++ b/arch/v850/kernel/irq.c	Tue May 27 00:09:43 2003
@@ -1,7 +1,7 @@
 /*
  * arch/v850/kernel/irq.c -- High-level interrupt handling
  *
- *  Copyright (C) 2001,02,03  NEC Corporation
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
  *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
  *  Copyright (C) 1994-2000  Ralf Baechle
  *  Copyright (C) 1992  Linus Torvalds
@@ -35,7 +35,7 @@
  * 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) { }
 
 /*
  * Generic no controller code
@@ -352,7 +352,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)
diff -Nru a/arch/v850/kernel/ma.c b/arch/v850/kernel/ma.c
--- a/arch/v850/kernel/ma.c	Mon Feb 24 12:42:23 2003
+++ b/arch/v850/kernel/ma.c	Tue May 27 00:09:43 2003
@@ -1,8 +1,8 @@
 /*
  * arch/v850/kernel/ma.c -- V850E/MA series of cpu chips
  *
- *  Copyright (C) 2001,02  NEC Corporation
- *  Copyright (C) 2001,02  Miles Bader <miles@gnu.org>
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
  *
  * This file is subject to the terms and conditions of the GNU General
  * Public License.  See the file COPYING in the main directory of this
diff -Nru a/arch/v850/kernel/mach.h b/arch/v850/kernel/mach.h
--- a/arch/v850/kernel/mach.h	Sun Feb  9 17:30:00 2003
+++ b/arch/v850/kernel/mach.h	Tue May 27 00:09:43 2003
@@ -1,8 +1,8 @@
 /*
  * arch/v850/kernel/mach.h -- Machine-dependent functions used by v850 port
  *
- *  Copyright (C) 2001,02  NEC Corporation
- *  Copyright (C) 2001,02  Miles Bader <miles@gnu.org>
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
  *
  * This file is subject to the terms and conditions of the GNU General
  * Public License.  See the file COPYING in the main directory of this
diff -Nru a/arch/v850/kernel/process.c b/arch/v850/kernel/process.c
--- a/arch/v850/kernel/process.c	Thu Apr  3 14:56:44 2003
+++ b/arch/v850/kernel/process.c	Tue May 27 00:54:00 2003
@@ -1,7 +1,7 @@
 /*
  * arch/v850/kernel/process.c -- Arch-dependent process handling
  *
- *  Copyright (C) 2001,02,03  NEC Corporation
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
  *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
  *
  * This file is subject to the terms and conditions of the GNU General
@@ -198,14 +198,6 @@
 	}
 
 	return error;
-}
-
-/* This is the common part of the various fork-like system calls (which
-   are in entry.S).  */
-int fork_common (int flags, unsigned long new_sp, struct pt_regs *regs)
-{
-	struct task_struct *p = do_fork (flags, new_sp, regs, 0, 0, 0);
-	return IS_ERR (p) ? PTR_ERR (p) : p->pid;
 }
 
 
diff -Nru a/arch/v850/kernel/ptrace.c b/arch/v850/kernel/ptrace.c
--- a/arch/v850/kernel/ptrace.c	Fri Nov  1 07:20:35 2002
+++ b/arch/v850/kernel/ptrace.c	Tue May 27 00:09:43 2003
@@ -1,8 +1,8 @@
 /*
  * arch/v850/kernel/ptrace.c -- `ptrace' system call
  *
- *  Copyright (C) 2002  NEC Corporation
- *  Copyright (C) 2002  Miles Bader <miles@gnu.org>
+ *  Copyright (C) 2002,03  NEC Electronics Corporation
+ *  Copyright (C) 2002,03  Miles Bader <miles@gnu.org>
  *
  * Derived from arch/mips/kernel/ptrace.c:
  *
@@ -29,6 +29,89 @@
 #include <asm/processor.h>
 #include <asm/uaccess.h>
 
+/* Returns the address where the register at REG_OFFS in P is stashed away.  */
+static v850_reg_t *reg_save_addr (unsigned reg_offs, struct task_struct *t)
+{
+	struct pt_regs *regs;
+
+	/* Three basic cases:
+
+	   (1) A register normally saved before calling the scheduler, is
+	       available in the kernel entry pt_regs structure at the top
+	       of the kernel stack.  The kernel trap/irq exit path takes
+	       care to save/restore almost all registers for ptrace'd
+	       processes.
+
+	   (2) A call-clobbered register, where the process P entered the
+	       kernel via [syscall] trap, is not stored anywhere; that's
+	       OK, because such registers are not expected to be preserved
+	       when the trap returns anyway (so we don't actually bother to
+	       test for this case).
+
+	   (3) A few registers not used at all by the kernel, and so
+	       normally never saved except by context-switches, are in the
+	       context switch state.  */
+
+	if (reg_offs == PT_CTPC || reg_offs == PT_CTPSW || reg_offs == PT_CTBP)
+		/* Register saved during context switch.  */
+		regs = thread_saved_regs (t);
+	else
+		/* Register saved during kernel entry (or not available).  */
+		regs = task_regs (t);
+
+	return (v850_reg_t *)((char *)regs + reg_offs);
+}
+
+/* Set the bits SET and clear the bits CLEAR in the v850e DIR
+   (`debug information register').  Returns the new value of DIR.  */
+static inline v850_reg_t set_dir (v850_reg_t set, v850_reg_t clear)
+{
+	register v850_reg_t rval asm ("r10");
+	register v850_reg_t arg0 asm ("r6") = set;
+	register v850_reg_t arg1 asm ("r7") = clear;
+
+	/* The dbtrap handler has exactly this functionality when called
+	   from kernel mode.  0xf840 is a `dbtrap' insn.  */
+	asm (".short 0xf840" : "=r" (rval) : "r" (arg0), "r" (arg1));
+
+	return rval;
+}
+
+/* Makes sure hardware single-stepping is (globally) enabled.
+   Returns true if successful.  */
+static inline int enable_single_stepping (void)
+{
+	static int enabled = 0;	/* Remember whether we already did it.  */
+	if (! enabled) {
+		/* Turn on the SE (`single-step enable') bit, 0x100, in the
+		   DIR (`debug information register').  This may fail if a
+		   processor doesn't support it or something.  We also try
+		   to clear bit 0x40 (`INI'), which is necessary to use the
+		   debug stuff on the v850e2; on the v850e, clearing 0x40
+		   shouldn't cause any problem.  */
+		v850_reg_t dir = set_dir (0x100, 0x40);
+		/* Make sure it really got set.  */
+		if (dir & 0x100)
+			enabled = 1;
+	}
+	return enabled;
+}
+
+/* Try to set CHILD's single-step flag to VAL.  Returns true if successful.  */
+static int set_single_step (struct task_struct *t, int val)
+{
+	v850_reg_t *psw_addr = reg_save_addr(PT_PSW, t);
+	if (val) {
+		/* Make sure single-stepping is enabled.  */
+		if (! enable_single_stepping ())
+			return 0;
+		/* Set T's single-step flag.  */
+		*psw_addr |= 0x800;
+	} else
+		*psw_addr &= ~0x800;
+	return 1;
+}
+
 int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
@@ -36,12 +119,6 @@
 
 	lock_kernel();
 
-#if 0
-	printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n",
-	       (int) request, (int) pid, (unsigned long) addr,
-	       (unsigned long) data);
-#endif
-
 	if (request == PTRACE_TRACEME) {
 		/* are we already being traced? */
 		if (current->ptrace & PT_PTRACED) {
@@ -81,31 +158,15 @@
 		goto out_tsk;
 
 	switch (request) {
-	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
-	case PTRACE_PEEKDATA:{
-		unsigned long tmp;
-		int copied;
+		unsigned long val, copied;
 
-		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+	case PTRACE_PEEKTEXT: /* read word at location addr. */
+	case PTRACE_PEEKDATA:
+		copied = access_process_vm(child, addr, &val, sizeof(val), 0);
 		rval = -EIO;
-		if (copied != sizeof(tmp))
+		if (copied != sizeof(val))
 			break;
-		rval = put_user(tmp,(unsigned long *) data);
-
-		goto out;
-		}
-
-	/* Read the word at location addr in the USER area.  */
-	case PTRACE_PEEKUSR: 
-		if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) {
-			struct pt_regs *regs = task_regs (child);
-			unsigned long val =
-				*(unsigned long *)((char *)regs + addr);
-			rval = put_user (val, (unsigned long *)data);
-		} else {
-			rval = 0;
-			rval = -EIO;			
-		}
+		rval = put_user(val, (unsigned long *)data);
 		goto out;
 
 	case PTRACE_POKETEXT: /* write the word at location addr. */
@@ -117,35 +178,62 @@
 		rval = -EIO;
 		goto out;
 
+	/* Read/write the word at location ADDR in the registers.  */
+	case PTRACE_PEEKUSR:
 	case PTRACE_POKEUSR:
-		if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) {
-			struct pt_regs *regs = task_regs (child);
-			unsigned long *loc =
-				(unsigned long *)((char *)regs + addr);
-			*loc = data;
-		} else {
-			rval = 0;
-			rval = -EIO;			
-		}
+		rval = 0;
+		if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) {
+			/* Special requests that don't actually correspond
+			   to offsets in struct pt_regs.  */
+			if (addr == PT_TEXT_ADDR)
+				val = child->mm->start_code;
+			else if (addr == PT_DATA_ADDR)
+				val = child->mm->start_data;
+			else if (addr == PT_TEXT_LEN)
+				val = child->mm->end_code
+					- child->mm->start_code;
+			else
+				rval = -EIO;
+		} else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) {
+			v850_reg_t *reg_addr = reg_save_addr(addr, child);
+			if (request == PTRACE_PEEKUSR)
+				val = *reg_addr;
+			else
+				*reg_addr = data;
+		} else
+			rval = -EIO;
+
+		if (rval == 0 && request == PTRACE_PEEKUSR)
+			rval = put_user (val, (unsigned long *)data);
 		goto out;
 
-	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
-	case PTRACE_CONT: /* rvaltart after signal. */
+	/* Continue and stop at next (return from) syscall */
+	case PTRACE_SYSCALL:
+	/* Restart after a signal.  */
+	case PTRACE_CONT:
+	/* Execute a single instruction. */
+	case PTRACE_SINGLESTEP:
 		rval = -EIO;
 		if ((unsigned long) data > _NSIG)
 			break;
+
+		/* Turn CHILD's single-step flag on or off.  */
+		if (! set_single_step (child, request == PTRACE_SINGLESTEP))
+			break;
+
 		if (request == PTRACE_SYSCALL)
 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		else
 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+
 		child->exit_code = data;
 		wake_up_process(child);
 		rval = 0;
 		break;
 
 	/*
-	 * make the child exit.  Best I can do is send it a sigkill. 
-	 * perhaps it should be put in the status that it wants to 
+	 * make the child exit.  Best I can do is send it a sigkill.
+	 * perhaps it should be put in the status that it wants to
 	 * exit.
 	 */
 	case PTRACE_KILL:
@@ -157,6 +245,7 @@
 		break;
 
 	case PTRACE_DETACH: /* detach a process that was attached. */
+		set_single_step (child, 0);  /* Clear single-step flag */
 		rval = ptrace_detach(child, data);
 		break;
 
@@ -181,7 +270,7 @@
 	/* The 0x80 provides a way for the tracing parent to distinguish
 	   between a syscall stop and SIGTRAP delivery */
 	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-	                                ? 0x80 : 0);
+					? 0x80 : 0);
 	current->state = TASK_STOPPED;
 	notify_parent(current, SIGCHLD);
 	schedule();
diff -Nru a/arch/v850/kernel/rte_cb_leds.c b/arch/v850/kernel/rte_cb_leds.c
--- a/arch/v850/kernel/rte_cb_leds.c	Sun Nov 24 17:34:44 2002
+++ b/arch/v850/kernel/rte_cb_leds.c	Tue May 27 00:09:43 2003
@@ -1,8 +1,8 @@
 /*
  * include/asm-v850/rte_cb_leds.c -- Midas lab RTE-CB board LED device support
  *
- *  Copyright (C) 2002  NEC Corporation
- *  Copyright (C) 2002  Miles Bader <miles@gnu.org>
+ *  Copyright (C) 2002,03  NEC Electronics Corporation
+ *  Copyright (C) 2002,03  Miles Bader <miles@gnu.org>
  *
  * This file is subject to the terms and conditions of the GNU General
  * Public License.  See the file COPYING in the main directory of this
@@ -14,6 +14,7 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/fs.h>
 #include <linux/miscdevice.h>
 
 #include <asm/uaccess.h>
diff -Nru a/arch/v850/kernel/rte_cb_multi.c b/arch/v850/kernel/rte_cb_multi.c
--- a/arch/v850/kernel/rte_cb_multi.c	Thu Apr  3 15:01:04 2003
+++ b/arch/v850/kernel/rte_cb_multi.c	Tue May 27 00:09:43 2003
@@ -2,7 +2,7 @@
  * include/asm-v850/rte_multi.c -- Support for Multi debugger monitor ROM
  * 	on Midas lab RTE-CB series of evaluation boards
  *
- *  Copyright (C) 2001,02,03  NEC Corporation
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
  *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
  *
  * This file is subject to the terms and conditions of the GNU General
diff -Nru a/arch/v850/kernel/rte_ma1_cb.c b/arch/v850/kernel/rte_ma1_cb.c
--- a/arch/v850/kernel/rte_ma1_cb.c	Thu Apr  3 15:01:04 2003
+++ b/arch/v850/kernel/rte_ma1_cb.c	Tue May 27 00:09:43 2003
@@ -1,7 +1,7 @@
 /*
  * arch/v850/kernel/rte_ma1_cb.c -- Midas labs RTE-V850E/MA1-CB board
  *
- *  Copyright (C) 2001,02,03  NEC Corporation
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
  *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
  *
  * This file is subject to the terms and conditions of the GNU General
diff -Nru a/arch/v850/vmlinux.lds.S b/arch/v850/vmlinux.lds.S
--- a/arch/v850/vmlinux.lds.S	Wed Apr  2 00:42:56 2003
+++ b/arch/v850/vmlinux.lds.S	Tue May 27 00:09:43 2003
@@ -105,9 +105,9 @@
 #define RAMK_INIT_CONTENTS_NO_END					      \
 		. = ALIGN (4096) ;					      \
 		__init_start = . ;					      \
-			_sinittext = .;					      \
+			__sinittext = .;				      \
 			*(.init.text)	/* 2.5 convention */		      \
-			_einittext = .;					      \
+			__einittext = .;				      \
 			*(.init.data)					      \
 			*(.text.init)	/* 2.4 convention */		      \
 			*(.data.init)					      \
diff -Nru a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c
--- a/arch/x86_64/kernel/reboot.c	Fri May 23 03:22:07 2003
+++ b/arch/x86_64/kernel/reboot.c	Tue May 27 03:48:22 2003
@@ -124,7 +124,7 @@
 {
 	int i;
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	smp_halt(); 
 #endif
 
diff -Nru a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
--- a/arch/x86_64/kernel/setup.c	Fri May 23 03:22:07 2003
+++ b/arch/x86_64/kernel/setup.c	Thu May 29 22:42:35 2003
@@ -31,6 +31,7 @@
 #include <linux/initrd.h>
 #include <linux/highmem.h>
 #include <linux/bootmem.h>
+#include <linux/module.h>
 #include <asm/processor.h>
 #include <linux/console.h>
 #include <linux/seq_file.h>
@@ -61,6 +62,7 @@
 struct cpuinfo_x86 boot_cpu_data;
 
 unsigned long mmu_cr4_features;
+EXPORT_SYMBOL_GPL(mmu_cr4_features);
 
 int acpi_disabled __initdata = 0;
 
diff -Nru a/crypto/Kconfig b/crypto/Kconfig
--- a/crypto/Kconfig	Sat May 17 15:30:03 2003
+++ b/crypto/Kconfig	Thu May 29 20:10:22 2003
@@ -7,7 +7,7 @@
 config CRYPTO
 	bool "Cryptographic API"
 	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
+		     INET6_ESP=y || INET6_ESP=m || INET6_IPCOMP=y || INET6_IPCOMP=m || IPV6_PRIVACY=y
 	help
 	  This option provides the core Cryptographic API.
 
@@ -36,7 +36,7 @@
 	tristate "MD5 digest algorithm"
 	depends on CRYPTO
 	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
+	             INET6_ESP=y || INET6_ESP=m || IPV6_PRIVACY=y
 	help
 	  MD5 message digest algorithm (RFC1321).
 
diff -Nru a/crypto/sha512.c b/crypto/sha512.c
--- a/crypto/sha512.c	Tue Jan 14 03:44:40 2003
+++ b/crypto/sha512.c	Tue May 27 00:09:39 2003
@@ -48,33 +48,33 @@
 }
 
 const u64 sha512_K[80] = {
-        0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f,
-        0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019,
-        0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242,
-        0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
-        0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
-        0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3,
-        0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275,
-        0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
-        0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f,
-        0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
-        0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc,
-        0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
-        0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6,
-        0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001,
-        0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
-        0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
-        0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99,
-        0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb,
-        0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc,
-        0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
-        0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915,
-        0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207,
-        0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba,
-        0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
-        0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
-        0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
-        0x5fcb6fab3ad6faec, 0x6c44198c4a475817,
+        0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
+        0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+        0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
+        0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+        0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
+        0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+        0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
+        0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+        0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
+        0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+        0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
+        0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+        0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
+        0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+        0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
+        0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+        0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
+        0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+        0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
+        0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+        0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
+        0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+        0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
+        0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+        0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
+        0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+        0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL,
 };
 
 #define e0(x)       (RORu64(x,28) ^ RORu64(x,34) ^ RORu64(x,39))
@@ -83,24 +83,24 @@
 #define s1(x)       (RORu64(x,19) ^ RORu64(x,61) ^ (x >> 6))
 
 /* H* initial state for SHA-512 */
-#define H0         0x6a09e667f3bcc908
-#define H1         0xbb67ae8584caa73b
-#define H2         0x3c6ef372fe94f82b
-#define H3         0xa54ff53a5f1d36f1
-#define H4         0x510e527fade682d1
-#define H5         0x9b05688c2b3e6c1f
-#define H6         0x1f83d9abfb41bd6b
-#define H7         0x5be0cd19137e2179
+#define H0         0x6a09e667f3bcc908ULL
+#define H1         0xbb67ae8584caa73bULL
+#define H2         0x3c6ef372fe94f82bULL
+#define H3         0xa54ff53a5f1d36f1ULL
+#define H4         0x510e527fade682d1ULL
+#define H5         0x9b05688c2b3e6c1fULL
+#define H6         0x1f83d9abfb41bd6bULL
+#define H7         0x5be0cd19137e2179ULL
 
 /* H'* initial state for SHA-384 */
-#define HP0 0xcbbb9d5dc1059ed8
-#define HP1 0x629a292a367cd507
-#define HP2 0x9159015a3070dd17
-#define HP3 0x152fecd8f70e5939
-#define HP4 0x67332667ffc00b31
-#define HP5 0x8eb44a8768581511
-#define HP6 0xdb0c2e0d64f98fa7
-#define HP7 0x47b5481dbefa4fa4
+#define HP0 0xcbbb9d5dc1059ed8ULL
+#define HP1 0x629a292a367cd507ULL
+#define HP2 0x9159015a3070dd17ULL
+#define HP3 0x152fecd8f70e5939ULL
+#define HP4 0x67332667ffc00b31ULL
+#define HP5 0x8eb44a8768581511ULL
+#define HP6 0xdb0c2e0d64f98fa7ULL
+#define HP7 0x47b5481dbefa4fa4ULL
 
 static inline void LOAD_OP(int I, u64 *W, const u8 *input)
 {
diff -Nru a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile
--- a/drivers/acorn/char/Makefile	Sat Dec 14 04:38:56 2002
+++ b/drivers/acorn/char/Makefile	Wed May 28 06:26:28 2003
@@ -2,22 +2,6 @@
 # Makefile for the acorn character device drivers.
 #
 
-obj-arc		:= keyb_arc.o defkeymap-acorn.o
-
 obj-$(CONFIG_ARCH_ACORN)	+= i2c.o pcf8583.o
 obj-$(CONFIG_L7200_KEYB)	+= defkeymap-l7200.o keyb_l7200.o
 obj-y				+= $(obj-$(MACHINE))
-
-$(obj)/defkeymap-acorn.o: $(obj)/defkeymap-acorn.c
-
-# Uncomment if you're changing the keymap and have an appropriate
-# loadkeys version for the map. By default, we'll use the shipped
-# versions.
-# GENERATE_KEYMAP := 1
-
-ifdef GENERATE_KEYMAP
-
-$(obj)/defkeymap-acorn.c: $(obj)/%.c: $(src)/%.map
-	loadkeys --mktable $< > $@
-
-endif
diff -Nru a/drivers/acorn/char/defkeymap-acorn.c_shipped b/drivers/acorn/char/defkeymap-acorn.c_shipped
--- a/drivers/acorn/char/defkeymap-acorn.c_shipped	Sun Jun 23 10:09:27 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,262 +0,0 @@
-/* Do not edit this file! It was automatically generated by   */
-/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
-
-#include <linux/types.h>
-#include <linux/keyboard.h>
-#include <linux/kd.h>
-
-u_short plain_map[NR_KEYS] = {
-	0xf01b,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,	0xf105,	0xf106,
-	0xf107,	0xf108,	0xf109,	0xf10a,	0xf10b,	0xf200,	0xf209,	0xf205,
-	0xf060,	0xf031,	0xf032,	0xf033,	0xf034,	0xf035,	0xf036,	0xf037,
-	0xf038,	0xf039,	0xf030,	0xf02d,	0xf03d,	0xf0a3,	0xf07f,	0xf115,
-	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf009,	0xfb71,
-	0xfb77,	0xfb65,	0xfb72,	0xfb74,	0xfb79,	0xfb75,	0xfb69,	0xfb6f,
-	0xfb70,	0xf05b,	0xf05d,	0xf05c,	0xf116,	0xf117,	0xf119,	0xf307,
-	0xf308,	0xf309,	0xf30b,	0xf702,	0xfb61,	0xfb73,	0xfb64,	0xfb66,
-	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,	0xf03b,	0xf027,	0xf201,
-	0xf304,	0xf305,	0xf306,	0xf30a,	0xf700,	0xf200,	0xfb7a,	0xfb78,
-	0xfb63,	0xfb76,	0xfb62,	0xfb6e,	0xfb6d,	0xf02c,	0xf02e,	0xf02f,
-	0xf700,	0xf603,	0xf301,	0xf302,	0xf303,	0xf207,	0xf703,	0xf020,
-	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf300,	0xf310,	0xf30e,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short shift_map[NR_KEYS] = {
-	0xf01b,	0xf10a,	0xf10b,	0xf10c,	0xf10d,	0xf10e,	0xf10f,	0xf110,
-	0xf111,	0xf112,	0xf113,	0xf10a,	0xf10b,	0xf200,	0xf203,	0xf205,
-	0xf07e,	0xf021,	0xf040,	0xf023,	0xf024,	0xf025,	0xf05e,	0xf026,
-	0xf02a,	0xf028,	0xf029,	0xf05f,	0xf02b,	0xf0a4,	0xf07f,	0xf115,
-	0xf114,	0xf20b,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf009,	0xfb51,
-	0xfb57,	0xfb45,	0xfb52,	0xfb54,	0xfb59,	0xfb55,	0xfb49,	0xfb4f,
-	0xfb50,	0xf07b,	0xf07d,	0xf07c,	0xf116,	0xf117,	0xf20a,	0xf307,
-	0xf308,	0xf309,	0xf30b,	0xf702,	0xfb41,	0xfb53,	0xfb44,	0xfb46,
-	0xfb47,	0xfb48,	0xfb4a,	0xfb4b,	0xfb4c,	0xf03a,	0xf022,	0xf201,
-	0xf304,	0xf305,	0xf306,	0xf30a,	0xf700,	0xf200,	0xfb5a,	0xfb58,
-	0xfb43,	0xfb56,	0xfb42,	0xfb4e,	0xfb4d,	0xf03c,	0xf03e,	0xf03f,
-	0xf700,	0xf603,	0xf301,	0xf302,	0xf303,	0xf207,	0xf703,	0xf020,
-	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf300,	0xf310,	0xf30e,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short altgr_map[NR_KEYS] = {
-	0xf200,	0xf50c,	0xf50d,	0xf50e,	0xf50f,	0xf510,	0xf511,	0xf512,
-	0xf513,	0xf514,	0xf515,	0xf516,	0xf517,	0xf200,	0xf202,	0xf205,
-	0xf200,	0xf200,	0xf040,	0xf200,	0xf024,	0xf200,	0xf200,	0xf07b,
-	0xf05b,	0xf05d,	0xf07d,	0xf05c,	0xf200,	0xf200,	0xf200,	0xf115,
-	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf200,	0xfb71,
-	0xfb77,	0xf918,	0xfb72,	0xfb74,	0xfb79,	0xfb75,	0xfb69,	0xfb6f,
-	0xfb70,	0xf200,	0xf07e,	0xf200,	0xf116,	0xf117,	0xf119,	0xf911,
-	0xf912,	0xf913,	0xf30b,	0xf702,	0xf914,	0xfb73,	0xf917,	0xf919,
-	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,	0xf200,	0xf200,	0xf201,
-	0xf90e,	0xf90f,	0xf910,	0xf30a,	0xf700,	0xf200,	0xfb7a,	0xfb78,
-	0xf916,	0xfb76,	0xf915,	0xfb6e,	0xfb6d,	0xf200,	0xf200,	0xf200,
-	0xf700,	0xf603,	0xf90b,	0xf90c,	0xf90d,	0xf207,	0xf703,	0xf200,
-	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf90a,	0xf310,	0xf30e,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short ctrl_map[NR_KEYS] = {
-	0xf200,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,	0xf105,	0xf106,
-	0xf107,	0xf108,	0xf109,	0xf10a,	0xf10b,	0xf200,	0xf204,	0xf205,
-	0xf200,	0xf200,	0xf000,	0xf01b,	0xf01c,	0xf01d,	0xf01e,	0xf01f,
-	0xf07f,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf008,	0xf115,
-	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf200,	0xf011,
-	0xf017,	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,	0xf00f,
-	0xf010,	0xf01b,	0xf01d,	0xf01c,	0xf116,	0xf117,	0xf119,	0xf307,
-	0xf308,	0xf309,	0xf30b,	0xf702,	0xf001,	0xf013,	0xf004,	0xf006,
-	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf007,	0xf201,
-	0xf304,	0xf305,	0xf306,	0xf30a,	0xf700,	0xf200,	0xf01a,	0xf018,
-	0xf003,	0xf016,	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf20e,	0xf07f,
-	0xf700,	0xf603,	0xf301,	0xf302,	0xf303,	0xf207,	0xf703,	0xf000,
-	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf300,	0xf310,	0xf30e,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short shift_ctrl_map[NR_KEYS] = {
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf209,	0xf205,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf200,	0xf115,
-	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf200,	0xf011,
-	0xf017,	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,	0xf00f,
-	0xf010,	0xf200,	0xf200,	0xf200,	0xf116,	0xf117,	0xf119,	0xf307,
-	0xf308,	0xf309,	0xf30b,	0xf702,	0xf001,	0xf013,	0xf004,	0xf006,
-	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf200,	0xf201,
-	0xf304,	0xf305,	0xf306,	0xf30a,	0xf700,	0xf200,	0xf01a,	0xf018,
-	0xf003,	0xf016,	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf200,	0xf200,
-	0xf700,	0xf603,	0xf301,	0xf302,	0xf303,	0xf207,	0xf703,	0xf200,
-	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf300,	0xf310,	0xf30e,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short alt_map[NR_KEYS] = {
-	0xf81b,	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,	0xf505,	0xf506,
-	0xf507,	0xf508,	0xf509,	0xf50a,	0xf50b,	0xf200,	0xf209,	0xf205,
-	0xf860,	0xf831,	0xf832,	0xf833,	0xf834,	0xf835,	0xf836,	0xf837,
-	0xf838,	0xf839,	0xf830,	0xf82d,	0xf83d,	0xf8a3,	0xf87f,	0xf115,
-	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf809,	0xf871,
-	0xf877,	0xf865,	0xf872,	0xf874,	0xf879,	0xf875,	0xf869,	0xf86f,
-	0xf870,	0xf85b,	0xf85d,	0xf85c,	0xf116,	0xf117,	0xf119,	0xf907,
-	0xf908,	0xf909,	0xf30b,	0xf702,	0xf861,	0xf873,	0xf864,	0xf866,
-	0xf867,	0xf868,	0xf86a,	0xf86b,	0xf86c,	0xf83b,	0xf827,	0xf80d,
-	0xf904,	0xf905,	0xf906,	0xf30a,	0xf700,	0xf200,	0xf87a,	0xf878,
-	0xf863,	0xf876,	0xf862,	0xf86e,	0xf86d,	0xf82c,	0xf82e,	0xf82f,
-	0xf700,	0xf603,	0xf901,	0xf902,	0xf903,	0xf207,	0xf703,	0xf820,
-	0xf701,	0xf702,	0xf210,	0xf600,	0xf211,	0xf900,	0xf310,	0xf30e,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-u_short ctrl_alt_map[NR_KEYS] = {
-	0xf200,	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,	0xf505,	0xf506,
-	0xf507,	0xf508,	0xf509,	0xf50a,	0xf50b,	0xf200,	0xf209,	0xf205,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf115,
-	0xf114,	0xf118,	0xf208,	0xf30d,	0xf30c,	0xf314,	0xf200,	0xf811,
-	0xf817,	0xf805,	0xf812,	0xf814,	0xf819,	0xf815,	0xf809,	0xf80f,
-	0xf810,	0xf200,	0xf200,	0xf200,	0xf20c,	0xf117,	0xf119,	0xf307,
-	0xf308,	0xf309,	0xf30b,	0xf702,	0xf801,	0xf813,	0xf804,	0xf806,
-	0xf807,	0xf808,	0xf80a,	0xf80b,	0xf80c,	0xf200,	0xf200,	0xf201,
-	0xf304,	0xf305,	0xf306,	0xf30a,	0xf700,	0xf200,	0xf81a,	0xf818,
-	0xf803,	0xf816,	0xf802,	0xf80e,	0xf80d,	0xf200,	0xf200,	0xf200,
-	0xf700,	0xf603,	0xf301,	0xf302,	0xf303,	0xf207,	0xf703,	0xf200,
-	0xf701,	0xf702,	0xf601,	0xf600,	0xf602,	0xf300,	0xf20c,	0xf30e,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-};
-
-ushort *key_maps[MAX_NR_KEYMAPS] = {
-	plain_map, shift_map, altgr_map, 0,
-	ctrl_map, shift_ctrl_map, 0, 0,
-	alt_map, 0, 0, 0,
-	ctrl_alt_map,	0
-};
-
-unsigned int keymap_count = 7;
-
-/*
- * Philosophy: most people do not define more strings, but they who do
- * often want quite a lot of string space. So, we statically allocate
- * the default and allocate dynamically in chunks of 512 bytes.
- */
-
-char func_buf[] = {
-	'\033', '[', '[', 'A', 0, 
-	'\033', '[', '[', 'B', 0, 
-	'\033', '[', '[', 'C', 0, 
-	'\033', '[', '[', 'D', 0, 
-	'\033', '[', '[', 'E', 0, 
-	'\033', '[', '1', '7', '~', 0, 
-	'\033', '[', '1', '8', '~', 0, 
-	'\033', '[', '1', '9', '~', 0, 
-	'\033', '[', '2', '0', '~', 0, 
-	'\033', '[', '2', '1', '~', 0, 
-	'\033', '[', '2', '3', '~', 0, 
-	'\033', '[', '2', '4', '~', 0, 
-	'\033', '[', '2', '5', '~', 0, 
-	'\033', '[', '2', '6', '~', 0, 
-	'\033', '[', '2', '8', '~', 0, 
-	'\033', '[', '2', '9', '~', 0, 
-	'\033', '[', '3', '1', '~', 0, 
-	'\033', '[', '3', '2', '~', 0, 
-	'\033', '[', '3', '3', '~', 0, 
-	'\033', '[', '3', '4', '~', 0, 
-	'\033', '[', '1', '~', 0, 
-	'\033', '[', '2', '~', 0, 
-	'\033', '[', '3', '~', 0, 
-	'\033', '[', '4', '~', 0, 
-	'\033', '[', '5', '~', 0, 
-	'\033', '[', '6', '~', 0, 
-	'\033', '[', 'M', 0, 
-	'\033', '[', 'P', 0, 
-};
-
-char *funcbufptr = func_buf;
-int funcbufsize = sizeof(func_buf);
-int funcbufleft = 0;          /* space left */
-
-char *func_table[MAX_NR_FUNC] = {
-	func_buf + 0,
-	func_buf + 5,
-	func_buf + 10,
-	func_buf + 15,
-	func_buf + 20,
-	func_buf + 25,
-	func_buf + 31,
-	func_buf + 37,
-	func_buf + 43,
-	func_buf + 49,
-	func_buf + 55,
-	func_buf + 61,
-	func_buf + 67,
-	func_buf + 73,
-	func_buf + 79,
-	func_buf + 85,
-	func_buf + 91,
-	func_buf + 97,
-	func_buf + 103,
-	func_buf + 109,
-	func_buf + 115,
-	func_buf + 120,
-	func_buf + 125,
-	func_buf + 130,
-	func_buf + 135,
-	func_buf + 140,
-	func_buf + 145,
-	0,
-	0,
-	func_buf + 149,
-	0,
-};
-
-struct kbdiacr accent_table[MAX_DIACR] = {
-	{'`', 'A', '\300'},	{'`', 'a', '\340'},
-	{'\'', 'A', '\301'},	{'\'', 'a', '\341'},
-	{'^', 'A', '\302'},	{'^', 'a', '\342'},
-	{'~', 'A', '\303'},	{'~', 'a', '\343'},
-	{'"', 'A', '\304'},	{'"', 'a', '\344'},
-	{'O', 'A', '\305'},	{'o', 'a', '\345'},
-	{'0', 'A', '\305'},	{'0', 'a', '\345'},
-	{'A', 'A', '\305'},	{'a', 'a', '\345'},
-	{'A', 'E', '\306'},	{'a', 'e', '\346'},
-	{',', 'C', '\307'},	{',', 'c', '\347'},
-	{'`', 'E', '\310'},	{'`', 'e', '\350'},
-	{'\'', 'E', '\311'},	{'\'', 'e', '\351'},
-	{'^', 'E', '\312'},	{'^', 'e', '\352'},
-	{'"', 'E', '\313'},	{'"', 'e', '\353'},
-	{'`', 'I', '\314'},	{'`', 'i', '\354'},
-	{'\'', 'I', '\315'},	{'\'', 'i', '\355'},
-	{'^', 'I', '\316'},	{'^', 'i', '\356'},
-	{'"', 'I', '\317'},	{'"', 'i', '\357'},
-	{'-', 'D', '\320'},	{'-', 'd', '\360'},
-	{'~', 'N', '\321'},	{'~', 'n', '\361'},
-	{'`', 'O', '\322'},	{'`', 'o', '\362'},
-	{'\'', 'O', '\323'},	{'\'', 'o', '\363'},
-	{'^', 'O', '\324'},	{'^', 'o', '\364'},
-	{'~', 'O', '\325'},	{'~', 'o', '\365'},
-	{'"', 'O', '\326'},	{'"', 'o', '\366'},
-	{'/', 'O', '\330'},	{'/', 'o', '\370'},
-	{'`', 'U', '\331'},	{'`', 'u', '\371'},
-	{'\'', 'U', '\332'},	{'\'', 'u', '\372'},
-	{'^', 'U', '\333'},	{'^', 'u', '\373'},
-	{'"', 'U', '\334'},	{'"', 'u', '\374'},
-	{'\'', 'Y', '\335'},	{'\'', 'y', '\375'},
-	{'T', 'H', '\336'},	{'t', 'h', '\376'},
-	{'s', 's', '\337'},	{'"', 'y', '\377'},
-	{'s', 'z', '\337'},	{'i', 'j', '\377'},
-};
-
-unsigned int accent_table_size = 68;
diff -Nru a/drivers/acorn/char/defkeymap-acorn.map b/drivers/acorn/char/defkeymap-acorn.map
--- a/drivers/acorn/char/defkeymap-acorn.map	Tue Feb  5 12:09:39 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,356 +0,0 @@
-# Default kernel keymap for Acorn machines.  This uses 7 modifier combinations.
-keymaps 0-2,4-5,8,12
-# Change the above line into
-#	keymaps 0-2,4-6,8,12
-# in case you want the entries
-#	altgr	control	keycode  52 = Boot
-#	altgr	control	keycode 102 = Boot
-# below.
-#
-# In fact AltGr is used very little, and one more keymap can
-# be saved by mapping AltGr to Alt (and adapting a few entries):
-# keycode  96 = Alt             
-#
-keycode   0 = Escape
-	shift	keycode   0 = Escape
-	alt	keycode   0 = Meta_Escape
-keycode   1 = F1              F11               Console_13      
-	control	keycode   1 = F1              
-	alt	keycode   1 = Console_1       
-	control	alt	keycode   1 = Console_1       
-keycode   2 = F2              F12               Console_14      
-	control	keycode   2 = F2              
-	alt	keycode   2 = Console_2       
-	control	alt	keycode   2 = Console_2       
-keycode   3 = F3              F13               Console_15      
-	control	keycode   3 = F3              
-	alt	keycode   3 = Console_3       
-	control	alt	keycode   3 = Console_3       
-keycode   4 = F4              F14               Console_16      
-	control	keycode   4 = F4              
-	alt	keycode   4 = Console_4       
-	control	alt	keycode   4 = Console_4       
-keycode   5 = F5              F15               Console_17      
-	control	keycode   5 = F5              
-	alt	keycode   5 = Console_5       
-	control	alt	keycode   5 = Console_5       
-keycode   6 = F6              F16               Console_18      
-	control	keycode   6 = F6              
-	alt	keycode   6 = Console_6       
-	control	alt	keycode   6 = Console_6       
-keycode   7 = F7              F17               Console_19      
-	control	keycode   7 = F7              
-	alt	keycode   7 = Console_7       
-	control	alt	keycode   7 = Console_7       
-keycode   8 = F8              F18               Console_20      
-	control	keycode   8 = F8              
-	alt	keycode   8 = Console_8       
-	control	alt	keycode   8 = Console_8       
-keycode   9 = F9              F19               Console_21
-	control	keycode   9 = F9              
-	alt	keycode   9 = Console_9       
-	control	alt	keycode   9 = Console_9       
-keycode  10 = F10             F20               Console_22
-	control	keycode  10 = F10
-	alt	keycode  10 = Console_10      
-	control	alt	keycode  10 = Console_10      
-keycode  11 = F11             F11               Console_23
-	control	keycode  11 = F11
-	alt	keycode  11 = Console_11      
-	control	alt	keycode  11 = Console_11      
-keycode  12 = F12             F12               Console_24
-	control	keycode  12 = F12
-	alt	keycode  12 = Console_12      
-	control	alt	keycode  12 = Console_12      
-keycode  13 =
-keycode  14 = Scroll_Lock     
-	shift	keycode  14 = Show_Memory     
-	altgr	keycode  14 = Show_Registers  
-	control	keycode  14 = Show_State      
-	alt	keycode  14 = Scroll_Lock
-keycode  15 = Break           
-keycode  16 = grave            asciitilde      
-	alt	keycode  16 = Meta_grave      
-keycode  17 = one              exclam          
-	alt	keycode  17 = Meta_one        
-keycode  18 = two              at               at
-	control	keycode  18 = nul
-	alt	keycode  18 = Meta_two
-keycode  19 = three            numbersign      
-	control	keycode  19 = Escape
-	alt	keycode  19 = Meta_three      
-keycode  20 = four             dollar           dollar
-	control	keycode  20 = Control_backslash
-	alt	keycode  20 = Meta_four       
-keycode  21 = five             percent         
-	control	keycode  21 = Control_bracketright
-	alt	keycode  21 = Meta_five       
-keycode  22 = six              asciicircum     
-	control	keycode  22 = Control_asciicircum
-	alt	keycode  22 = Meta_six        
-keycode  23 = seven            ampersand        braceleft
-	control	keycode  23 = Control_underscore
-	alt	keycode  23 = Meta_seven      
-keycode  24 = eight            asterisk         bracketleft
-	control	keycode  24 = Delete
-	alt	keycode  24 = Meta_eight      
-keycode  25 = nine             parenleft        bracketright
-	alt	keycode  25 = Meta_nine       
-keycode  26 = zero             parenright       braceright
-	alt	keycode  26 = Meta_zero       
-keycode  27 = minus            underscore       backslash
-	control	keycode  27 =  Control_underscore
-	shift	control	keycode  27 = Control_underscore
-	alt	keycode  27 = Meta_minus      
-keycode  28 = equal            plus            
-	alt	keycode  28 = Meta_equal      
-keycode  29 = sterling         currency        
-	alt	keycode  29 = 0x08a3          
-keycode  30 = Delete           Delete          
-	control	keycode  30 = BackSpace       
-	alt	keycode  30 = Meta_Delete     
-keycode  31 = Insert          
-keycode  32 = Find            
-keycode  33 = Prior           
-	shift	keycode  33 = Scroll_Backward 
-keycode  34 = Num_Lock        
-keycode  35 = KP_Divide       
-keycode  36 = KP_Multiply     
-keycode  37 = 0x0314          
-keycode  38 = Tab              Tab             
-	alt	keycode  38 = Meta_Tab        
-keycode  39 = q               
-keycode  40 = w               
-keycode  41 = e               
-	altgr	keycode  41 = Hex_E
-keycode  42 = r               
-keycode  43 = t               
-keycode  44 = y               
-keycode  45 = u               
-keycode  46 = i               
-keycode  47 = o               
-keycode  48 = p               
-keycode  49 = bracketleft      braceleft       
-	control	keycode  49 = Escape          
-	alt	keycode  49 = Meta_bracketleft
-keycode  50 = bracketright     braceright       asciitilde
-	control	keycode  50 = Control_bracketright
-	alt	keycode  50 = Meta_bracketright
-keycode  51 = backslash        bar             
-	control	keycode  51 = Control_backslash
-	alt	keycode  51 = Meta_backslash  
-keycode  52 = Remove          
-#	altgr	control	keycode  52 = Boot
-	control	alt	keycode  52 = Boot            
-keycode  53 = Select          
-keycode  54 = Next            
-	shift	keycode  54 = Scroll_Forward  
-keycode  55 = KP_7            
-	altgr	keycode  55 = Hex_7           
-	alt	keycode  55 = Ascii_7         
-keycode  56 = KP_8            
-	altgr	keycode  56 = Hex_8           
-	alt	keycode  56 = Ascii_8         
-keycode  57 = KP_9            
-	altgr	keycode  57 = Hex_9           
-	alt	keycode  57 = Ascii_9         
-keycode  58 = KP_Subtract     
-keycode  59 = Control         
-keycode  60 = a
-	altgr	keycode  60 = Hex_A
-keycode  61 = s               
-keycode  62 = d
-	altgr	keycode  62 = Hex_D
-keycode  63 = f
-	altgr	keycode  63 = Hex_F
-keycode  64 = g               
-keycode  65 = h               
-keycode  66 = j               
-keycode  67 = k               
-keycode  68 = l               
-keycode  69 = semicolon        colon           
-	alt	keycode  69 = Meta_semicolon  
-keycode  70 = apostrophe       quotedbl        
-	control	keycode  70 = Control_g       
-	alt	keycode  70 = Meta_apostrophe 
-keycode  71 = Return          
-	alt	keycode  71 = Meta_Control_m  
-keycode  72 = KP_4            
-	altgr	keycode  72 = Hex_4           
-	alt	keycode  72 = Ascii_4         
-keycode  73 = KP_5            
-	altgr	keycode  73 = Hex_5           
-	alt	keycode  73 = Ascii_5         
-keycode  74 = KP_6            
-	altgr	keycode  74 = Hex_6           
-	alt	keycode  74 = Ascii_6         
-keycode  75 = KP_Add          
-keycode  76 = Shift           
-keycode  77 =
-keycode  78 = z               
-keycode  79 = x               
-keycode  80 = c
-	altgr	keycode  80 = Hex_C
-keycode  81 = v               
-keycode  82 = b
-	altgr	keycode  82 = Hex_B
-keycode  83 = n               
-keycode  84 = m               
-keycode  85 = comma            less            
-	alt	keycode  85 = Meta_comma      
-keycode  86 = period           greater         
-	control	keycode  86 = Compose         
-	alt	keycode  86 = Meta_period     
-keycode  87 = slash            question        
-	control	keycode  87 = Delete          
-	alt	keycode  87 = Meta_slash
-keycode  88 = Shift           
-keycode  89 = Up              
-keycode  90 = KP_1            
-	altgr	keycode  90 = Hex_1           
-	alt	keycode  90 = Ascii_1         
-keycode  91 = KP_2            
-	altgr	keycode  91 = Hex_2           
-	alt	keycode  91 = Ascii_2         
-keycode  92 = KP_3            
-	altgr	keycode  92 = Hex_3           
-	alt	keycode  92 = Ascii_3         
-keycode  93 = Caps_Lock       
-keycode  94 = Alt             
-keycode  95 = space            space           
-	control	keycode  95 = nul             
-	alt	keycode  95 = Meta_space      
-keycode  96 = AltGr           
-keycode  97 = Control         
-keycode  98 = Left            
-	alt	keycode  98 = Decr_Console    
-keycode  99 = Down            
-keycode 100 = Right           
-	alt	keycode 100 = Incr_Console    
-keycode 101 = KP_0            
-	altgr	keycode 101 = Hex_0           
-	alt	keycode 101 = Ascii_0         
-keycode 102 = KP_Period       
-#	altgr	control	keycode 102 = Boot
-	control	alt	keycode 102 = Boot            
-keycode 103 = KP_Enter        
-keycode 104 =
-keycode 105 =
-keycode 106 =
-keycode 107 =
-keycode 108 =
-keycode 109 =
-keycode 110 =
-keycode 111 =
-keycode 112 =
-keycode 113 =
-keycode 114 =
-keycode 115 =
-keycode 116 =
-keycode 117 =
-keycode 118 =
-keycode 119 =
-keycode 120 =
-keycode 121 =
-keycode 122 =
-keycode 123 =
-keycode 124 =
-keycode 125 =
-keycode 126 =
-keycode 127 =
-string F1 = "\033[[A"
-string F2 = "\033[[B"
-string F3 = "\033[[C"
-string F4 = "\033[[D"
-string F5 = "\033[[E"
-string F6 = "\033[17~"
-string F7 = "\033[18~"
-string F8 = "\033[19~"
-string F9 = "\033[20~"
-string F10 = "\033[21~"
-string F11 = "\033[23~"
-string F12 = "\033[24~"
-string F13 = "\033[25~"
-string F14 = "\033[26~"
-string F15 = "\033[28~"
-string F16 = "\033[29~"
-string F17 = "\033[31~"
-string F18 = "\033[32~"
-string F19 = "\033[33~"
-string F20 = "\033[34~"
-string Find = "\033[1~"
-string Insert = "\033[2~"
-string Remove = "\033[3~"
-string Select = "\033[4~"
-string Prior = "\033[5~"
-string Next = "\033[6~"
-string Macro = "\033[M"
-string Pause = "\033[P"
-compose '`' 'A' to 'À'
-compose '`' 'a' to 'à'
-compose '\'' 'A' to 'Á'
-compose '\'' 'a' to 'á'
-compose '^' 'A' to 'Â'
-compose '^' 'a' to 'â'
-compose '~' 'A' to 'Ã'
-compose '~' 'a' to 'ã'
-compose '"' 'A' to 'Ä'
-compose '"' 'a' to 'ä'
-compose 'O' 'A' to 'Å'
-compose 'o' 'a' to 'å'
-compose '0' 'A' to 'Å'
-compose '0' 'a' to 'å'
-compose 'A' 'A' to 'Å'
-compose 'a' 'a' to 'å'
-compose 'A' 'E' to 'Æ'
-compose 'a' 'e' to 'æ'
-compose ',' 'C' to 'Ç'
-compose ',' 'c' to 'ç'
-compose '`' 'E' to 'È'
-compose '`' 'e' to 'è'
-compose '\'' 'E' to 'É'
-compose '\'' 'e' to 'é'
-compose '^' 'E' to 'Ê'
-compose '^' 'e' to 'ê'
-compose '"' 'E' to 'Ë'
-compose '"' 'e' to 'ë'
-compose '`' 'I' to 'Ì'
-compose '`' 'i' to 'ì'
-compose '\'' 'I' to 'Í'
-compose '\'' 'i' to 'í'
-compose '^' 'I' to 'Î'
-compose '^' 'i' to 'î'
-compose '"' 'I' to 'Ï'
-compose '"' 'i' to 'ï'
-compose '-' 'D' to 'Ð'
-compose '-' 'd' to 'ð'
-compose '~' 'N' to 'Ñ'
-compose '~' 'n' to 'ñ'
-compose '`' 'O' to 'Ò'
-compose '`' 'o' to 'ò'
-compose '\'' 'O' to 'Ó'
-compose '\'' 'o' to 'ó'
-compose '^' 'O' to 'Ô'
-compose '^' 'o' to 'ô'
-compose '~' 'O' to 'Õ'
-compose '~' 'o' to 'õ'
-compose '"' 'O' to 'Ö'
-compose '"' 'o' to 'ö'
-compose '/' 'O' to 'Ø'
-compose '/' 'o' to 'ø'
-compose '`' 'U' to 'Ù'
-compose '`' 'u' to 'ù'
-compose '\'' 'U' to 'Ú'
-compose '\'' 'u' to 'ú'
-compose '^' 'U' to 'Û'
-compose '^' 'u' to 'û'
-compose '"' 'U' to 'Ü'
-compose '"' 'u' to 'ü'
-compose '\'' 'Y' to 'Ý'
-compose '\'' 'y' to 'ý'
-compose 'T' 'H' to 'Þ'
-compose 't' 'h' to 'þ'
-compose 's' 's' to 'ß'
-compose '"' 'y' to 'ÿ'
-compose 's' 'z' to 'ß'
-compose 'i' 'j' to 'ÿ'
diff -Nru a/drivers/acorn/char/keyb_arc.c b/drivers/acorn/char/keyb_arc.c
--- a/drivers/acorn/char/keyb_arc.c	Wed Feb 12 01:41:01 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,450 +0,0 @@
-/*
- *  linux/drivers/acorn/char/keyb_arc.c
- *
- *  Copyright (C) 2000 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Acorn keyboard driver for ARM Linux.
- *
- *  The Acorn keyboard appears to have a ***very*** buggy reset protocol -
- *  every reset behaves differently.  We try to get round this by attempting
- *  a few things...
- */
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/ptrace.h>
-#include <linux/signal.h>
-#include <linux/timer.h>
-#include <linux/random.h>
-#include <linux/ctype.h>
-#include <linux/init.h>
-#include <linux/kbd_ll.h>
-#include <linux/kbd_kern.h>
-#include <linux/delay.h>
-
-#include <asm/bitops.h>
-#include <asm/keyboard.h>
-#include <asm/irq.h>
-#include <asm/hardware.h>
-#include <asm/hardware/ioc.h>
-
-#include "../../char/busmouse.h"
-
-extern struct tasklet_struct keyboard_tasklet;
-extern void kbd_reset_kdown(void);
-
-#define VERSION 108
-
-#define KBD_REPORT_ERR
-#define KBD_REPORT_UNKN
-
-#include <asm/io.h>
-#include <asm/system.h>
-
-static char kbd_txval[4];
-static unsigned char kbd_txhead, kbd_txtail;
-#define KBD_INCTXPTR(ptr) ((ptr) = ((ptr) + 1) & 3)
-static int kbd_id = -1;
-static DECLARE_WAIT_QUEUE_HEAD(kbd_waitq);
-#ifdef CONFIG_KBDMOUSE
-static int mousedev;
-#endif
-
-/*
- * Protocol codes to send the keyboard.
- */
-#define HRST 0xff	/* reset keyboard */
-#define RAK1 0xfe	/* reset response */
-#define RAK2 0xfd	/* reset response */
-#define BACK 0x3f	/* Ack for first keyboard pair */
-#define SMAK 0x33	/* Last data byte ack (key scanning + mouse movement scanning) */
-#define MACK 0x32	/* Last data byte ack (mouse movement scanning) */
-#define SACK 0x31	/* Last data byte ack (key scanning) */
-#define NACK 0x30	/* Last data byte ack (no scanning, mouse data) */
-#define RQMP 0x22	/* Request mouse data */
-#define PRST 0x21	/* nothing */
-#define RQID 0x20	/* Request ID */
-
-#define UP_FLAG 1
-
-#ifdef CONFIG_MAGIC_SYSRQ
-unsigned char a5kkbd_sysrq_xlate[] = 
-{
-    27,    0,    0,    0,    0,    0,    0,    0,
-     0,    0,    0,    0,    0,    0,    0,    0,
-   '`',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
-   '8',  '9',  '0',  '-',  '=',  '£',  127,    0,
-     0,    0,    0,  '/',  '*',  '#',    9,  'q',
-   'w',  'e',  'r',  't',  'y',  'u',  'i',  'o',
-   'p',  '[',  ']', '\\',  22,    23,   25,  '7',
-   '8',  '9',  '-',    0,  'a',  's',  'd',  'f',
-   'g',  'h',  'j',  'k',  'l',  ';', '\'',   13,
-   '4',  '5',  '6',  '+',    0,    0,  'z',  'x',
-   'c',  'v',  'b',  'n',  'm',  ',',  '.',  '/',
-     0,    0,  '1',  '2',  '3',    0,    0,  ' ',
-     0,    0,    0,    0,    0,  '0',  '.',   10,
-     0,    0,    0,    0,    0,    0,    0,    0,
-     0,    0,    0,    0,    0,    0,    0,    0,
-     0,    0,    0,    0,    0,    0,    0,    0,
-};
-#endif
-
-/*
- * This array converts the scancode that we get from the keyboard to the
- * real rows/columns on the A5000 keyboard.  This might be keyboard specific...
- *
- * It is these values that we use to maintain the key down array.  That way, we
- * should pick up on the ghost key presses (which is what happens when you press
- * three keys, and the keyboard thinks you have pressed four!)
- *
- * Row 8 (0x80+c) is actually a column with one key per row.  It is isolated from
- * the other keys, and can't cause these problems (its used for shift, ctrl, alt etc).
- *
- * Illegal scancodes are denoted by an 0xff (in other words, we don't know about
- * them, and can't process them for ghosts).  This does however, cause problems with
- * autorepeat processing...
- */
-static unsigned char scancode_2_colrow[256] = {
-  0x01, 0x42, 0x32, 0x33, 0x43, 0x56, 0x5a, 0x6c, 0x7c, 0x5c, 0x5b, 0x6b, 0x7b, 0x84, 0x70, 0x60,
-  0x11, 0x51, 0x62, 0x63, 0x44, 0x54, 0x55, 0x45, 0x46, 0x4a, 0x3c, 0x4b, 0x59, 0x49, 0x69, 0x79,
-  0x83, 0x40, 0x30, 0x3b, 0x39, 0x38, 0x31, 0x61, 0x72, 0x73, 0x64, 0x74, 0x75, 0x65, 0x66, 0x6a,
-  0x1c, 0x2c, 0x7a, 0x36, 0x48, 0x68, 0x78, 0x20, 0x2b, 0x29, 0x28, 0x81, 0x71, 0x22, 0x23, 0x34,
-  0x24, 0x25, 0x35, 0x26, 0x3a, 0x0c, 0x2a, 0x76, 0x10, 0x1b, 0x19, 0x18, 0x82, 0xff, 0x21, 0x12,
-  0x13, 0x14, 0x04, 0x05, 0x15, 0x16, 0x1a, 0x0a, 0x85, 0x77, 0x00, 0x0b, 0x09, 0x02, 0x80, 0x03,
-  0x87, 0x86, 0x06, 0x17, 0x27, 0x07, 0x37, 0x08, 0xff,
-};
-
-#define BITS_PER_SHORT (8*sizeof(unsigned short))
-static unsigned short ghost_down[128/BITS_PER_SHORT];
-
-static void a5kkbd_key(unsigned int keycode, unsigned int up_flag)
-{
-	unsigned int real_keycode;
-
-	if (keycode > 0x72) {
-#ifdef KBD_REPORT_UNKN
-		printk ("kbd: unknown scancode 0x%04x\n", keycode);
-#endif
-		return;
-	}
-	if (keycode >= 0x70) {
-#ifdef CONFIG_KBDMOUSE
-		if (mousedev >= 0)
-			switch (keycode) {
-			case 0x70: /* Left mouse button */
-				busmouse_add_buttons(mousedev, 4, up_flag ? 4 : 0);
-				break;
-
-			case 0x71: /* Middle mouse button */
-				busmouse_add_buttons(mousedev, 2, up_flag ? 2 : 0);
-				break;
-
-			case 0x72:/* Right mouse button */
-				busmouse_add_buttons(mousedev, 1, up_flag ? 1 : 0);
-				break;
-			}
-#endif
-		return;
-	}
-
-	/*
-	 * We have to work out if we accept this key press as a real key, or
-	 * if it is a ghost.  IE. If you press three keys, the keyboard will think
-	 * that you've pressed a fourth: (@ = key down, # = ghost)
-	 *
-	 *   0 1 2 3 4 5 6 7
-	 *   | | | | | | | |
-	 * 0-+-+-+-+-+-+-+-+-
-	 *   | | | | | | | |
-	 * 1-+-@-+-+-+-@-+-+-
-	 *   | | | | | | | |
-	 * 2-+-+-+-+-+-+-+-+-
-	 *   | | | | | | | |
-	 * 3-+-@-+-+-+-#-+-+-
-	 *   | | | | | | | |
-	 *
-	 * This is what happens when you have a matrix keyboard...
-	 */
-
-	real_keycode = scancode_2_colrow[keycode];
-
-	if ((real_keycode & 0x80) == 0) {
-		int rr, kc = (real_keycode >> 4) & 7;
-		int cc;
-		unsigned short res, kdownkc;
-
-		kdownkc = ghost_down[kc] | (1 << (real_keycode & 15));
-
-		for (rr = 0; rr < 128/BITS_PER_SHORT; rr++)
-			if (rr != kc && (res = ghost_down[rr] & kdownkc)) {
-			    	/*
-				 * we have found a second row with at least one key pressed in the
-			    	 * same column.
-			    	 */
-			    	for (cc = 0; res; res >>= 1)
-					cc += (res & 1);
-				if (cc > 1)
-					return; /* ignore it */
-			}
-		if (up_flag)
-			clear_bit (real_keycode, ghost_down);
-		else
-			set_bit (real_keycode, ghost_down);
-	}
-
-	handle_scancode(keycode, !up_flag);
-}
-
-static inline void a5kkbd_sendbyte(unsigned char val)
-{
-	kbd_txval[kbd_txhead] = val;
-	KBD_INCTXPTR(kbd_txhead);
-	enable_irq(IRQ_KEYBOARDTX);
-}
-
-static inline void a5kkbd_reset(void)
-{
-	int i;
-
-	for (i = 0; i < NR_SCANCODES/BITS_PER_SHORT; i++)
-		ghost_down[i] = 0;
-
-	kbd_reset_kdown();
-}
-
-void a5kkbd_leds(unsigned char leds)
-{
-	leds =  ((leds & (1<<VC_SCROLLOCK))?4:0) | ((leds & (1<<VC_NUMLOCK))?2:0) |
-		((leds & (1<<VC_CAPSLOCK))?1:0);
-	a5kkbd_sendbyte(leds);
-}
-
-/* Keyboard states:
- *  0 initial reset condition, receive HRST, send RRAK1
- *  1 Sent RAK1, wait for RAK1, send RRAK2
- *  2 Sent RAK2, wait for RAK2, send SMAK or RQID
- *  3 Sent RQID, expect KBID, send SMAK
- *  4 Sent SMAK, wait for anything
- *  5 Wait for second keyboard nibble for key pressed
- *  6 Wait for second keyboard nibble for key released
- *  7 Wait for second part of mouse data
- *
- * This function returns 1 when we successfully enter the IDLE state
- * (and hence need to do some keyboard processing).
- */
-#define KBD_INITRST	0
-#define KBD_RAK1	1
-#define KBD_RAK2	2
-#define KBD_ID		3
-#define KBD_IDLE	4
-#define KBD_KEYDOWN	5
-#define KBD_KEYUP	6
-#define KBD_MOUSE	7
-
-static int handle_rawcode(unsigned int keyval)
-{
-	static signed char kbd_mousedx = 0;
-	       signed char kbd_mousedy;
-	static unsigned char kbd_state = KBD_INITRST;
-	static unsigned char kbd_keyhigh = 0;
-
-	if (keyval == HRST && kbd_state != KBD_INITRST && kbd_state != KBD_ID) {
-		a5kkbd_sendbyte (HRST);
-		a5kkbd_reset ();
-		kbd_state = KBD_INITRST;
-	} else switch(kbd_state) {
-	case KBD_INITRST:			/* hard reset - sent HRST */
-		if (keyval == HRST) {
-			a5kkbd_sendbyte (RAK1);
-			kbd_state = KBD_RAK1;
-		} else if (keyval == RAK1) {
-			/* Some A5000 keyboards are very fussy and don't follow Acorn's
-			 * specs - this appears to fix them, but them it might stop
-			 * them from being initialised.
-			 *  fix by Philip Blundell
-			 */
-			printk(KERN_DEBUG "keyboard sent early RAK1 -- ignored\n");
-		} else
-			goto kbd_wontreset;
-		break;
-
-	case KBD_RAK1:				/* sent RAK1 - expect RAK1 and send RAK2 */
-		if (keyval == RAK1) {
-			a5kkbd_sendbyte (RAK2);
-			kbd_state = KBD_RAK2;
-		} else
-			goto kbd_wontreset;
-		break;
-
-	case KBD_RAK2:				/* Sent RAK2 - expect RAK2 and send either RQID or SMAK */
-		if (keyval == RAK2) {
-			if (kbd_id == -1) {
-				a5kkbd_sendbyte (NACK);
-				a5kkbd_sendbyte (RQID);
-				kbd_state = KBD_ID;
-			} else {
-				a5kkbd_sendbyte (SMAK);
-				kbd_state = KBD_IDLE;
-			}
-		} else
-			goto kbd_wontreset;
-		break;
-
-	case KBD_ID:				/* Sent RQID - expect KBID */
-		if (keyval == HRST) {
-			kbd_id = -2;
-			a5kkbd_reset ();
-			a5kkbd_sendbyte (HRST);
-			kbd_state = KBD_INITRST;
-			wake_up (&kbd_waitq);
-		} else if ((keyval & 0xc0) == 0x80) {
-			kbd_id = keyval & 0x3f;
-			a5kkbd_sendbyte (SMAK);
-			kbd_state = KBD_IDLE;
-			wake_up (&kbd_waitq);
-		}
-		break;
-
-	case KBD_IDLE:				/* Send SMAK, ready for any reply */
-		switch (keyval & 0xf0) {
-		default:	/* 0x00 - 0x7f */
-			kbd_mousedx = keyval & 0x40 ? keyval|0x80 : keyval;
-			kbd_state   = KBD_MOUSE;
-			a5kkbd_sendbyte (BACK);
-			break;
-
-		case 0x80:
-		case 0x90:
-		case 0xa0:
-		case 0xb0:
-		    	if (kbd_id == -1)
-				kbd_id = keyval & 0x3f;
-			break;
-
-		case 0xc0:
-			kbd_keyhigh = keyval;
-			kbd_state   = KBD_KEYDOWN;
-			a5kkbd_sendbyte (BACK);
-			break;
-
-		case 0xd0:
-			kbd_keyhigh = keyval;
-			kbd_state   = KBD_KEYUP;
-			a5kkbd_sendbyte (BACK);
-			break;
-
-		case 0xe0:
-		case 0xf0:
-			goto kbd_error;
-		}
-		break;
-
-	case KBD_KEYDOWN:
-		if ((keyval & 0xf0) != 0xc0)
-			goto kbd_error;
-		else {
-			kbd_state = KBD_IDLE;
-			a5kkbd_sendbyte (SMAK);
-			if (((kbd_keyhigh ^ keyval) & 0xf0) == 0)
-				a5kkbd_key ((keyval & 0x0f) | ((kbd_keyhigh << 4) & 0xf0), 0);
-		}
-		break;
-
-	case KBD_KEYUP:
-		if ((keyval & 0xf0) != 0xd0)
-			goto kbd_error;
-		else {
-			kbd_state = KBD_IDLE;
-			a5kkbd_sendbyte (SMAK);
-			if (((kbd_keyhigh ^ keyval) & 0xf0) == 0)
-				a5kkbd_key ((keyval & 0x0f) | ((kbd_keyhigh << 4) & 0xf0), UP_FLAG);
-		}
-		break;
-
-	case KBD_MOUSE:
-		if (keyval & 0x80)
-			goto kbd_error;
-		else {
-			kbd_state = KBD_IDLE;
-			a5kkbd_sendbyte (SMAK);
-			kbd_mousedy = (char)(keyval & 0x40 ? keyval | 0x80 : keyval);
-#ifdef CONFIG_KBDMOUSE
-			if (mousedev >= 0)
-				busmouse_add_movement(mousedev, (int)kbd_mousedx, (int)kbd_mousedy);
-#endif
-		}
-	}
-	return kbd_state == KBD_IDLE ? 1 : 0;
-
-kbd_wontreset:
-#ifdef KBD_REPORT_ERR
-	printk ("kbd: keyboard won't reset (kbdstate %d, keyval %02X)\n",
-		kbd_state, keyval);
-#endif
-	mdelay(1);
-	ioc_readb(IOC_KARTRX);
-	a5kkbd_sendbyte (HRST);
-	kbd_state = KBD_INITRST;
-	return 0;
-
-kbd_error:
-#ifdef KBD_REPORT_ERR
-	printk ("kbd: keyboard out of sync - resetting\n");
-#endif
-	a5kkbd_sendbyte (HRST);
-	kbd_state = KBD_INITRST;
-	return 0;
-}
-
-static void a5kkbd_rx(int irq, void *dev_id, struct pt_regs *regs)
-{
-	if (handle_rawcode(ioc_readb(IOC_KARTRX)))
-		tasklet_schedule(&keyboard_tasklet);
-}
-
-static void a5kkbd_tx(int irq, void *dev_id, struct pt_regs *regs)
-{
-	ioc_writeb (kbd_txval[kbd_txtail], IOC_KARTTX);
-	KBD_INCTXPTR(kbd_txtail);
-	if (kbd_txtail == kbd_txhead)
-		disable_irq(irq);
-}
-
-#ifdef CONFIG_KBDMOUSE
-static struct busmouse a5kkbd_mouse = {
-	6, "kbdmouse", NULL, NULL, NULL, 7
-};
-#endif
-
-void __init a5kkbd_init_hw (void)
-{
-	if (request_irq (IRQ_KEYBOARDTX, a5kkbd_tx, 0, "keyboard", NULL) != 0)
-		panic("Could not allocate keyboard transmit IRQ!");
-	(void)ioc_readb(IOC_KARTRX);
-	if (request_irq (IRQ_KEYBOARDRX, a5kkbd_rx, 0, "keyboard", NULL) != 0)
-		panic("Could not allocate keyboard receive IRQ!");
-
-	a5kkbd_sendbyte (HRST);	/* send HRST (expect HRST) */
-
-	/* wait 1s for keyboard to initialise */
-	interruptible_sleep_on_timeout(&kbd_waitq, HZ);
-
-#ifdef CONFIG_KBDMOUSE
-	mousedev = register_busmouse(&a5kkbd_mouse);
-	if (mousedev < 0)
-		printk(KERN_ERR "Unable to register mouse driver\n");
-#endif
-
-	printk (KERN_INFO "Keyboard driver v%d.%02d. (", VERSION/100, VERSION%100);
-	if (kbd_id != -1)
-	      printk ("id=%d ", kbd_id);
-	printk ("English)\n");
-}
diff -Nru a/drivers/acorn/char/mouse_ps2.c b/drivers/acorn/char/mouse_ps2.c
--- a/drivers/acorn/char/mouse_ps2.c	Mon Oct  7 07:38:07 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,294 +0,0 @@
-/* 
- * Driver for PS/2 mouse on IOMD interface
- */
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/ptrace.h>
-#include <linux/signal.h>
-#include <linux/timer.h>
-#include <linux/random.h>
-#include <linux/ctype.h>
-#include <linux/kbd_ll.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/miscdevice.h>
-
-#include <asm/bitops.h>
-#include <asm/irq.h>
-#include <asm/hardware.h>
-#include <asm/io.h>
-#include <asm/hardware/iomd.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-/*
- *	PS/2 Auxiliary Device
- */
-
-static struct aux_queue *queue;	/* Mouse data buffer. */
-static int aux_count = 0;
-/* used when we send commands to the mouse that expect an ACK. */
-static unsigned char mouse_reply_expected = 0;
-
-#define MAX_RETRIES	60		/* some aux operations take long time*/
-
-/*
- *	Mouse Commands
- */
-
-#define AUX_SET_RES		0xE8	/* Set resolution */
-#define AUX_SET_SCALE11		0xE6	/* Set 1:1 scaling */
-#define AUX_SET_SCALE21		0xE7	/* Set 2:1 scaling */
-#define AUX_GET_SCALE		0xE9	/* Get scaling factor */
-#define AUX_SET_STREAM		0xEA	/* Set stream mode */
-#define AUX_SET_SAMPLE		0xF3	/* Set sample rate */
-#define AUX_ENABLE_DEV		0xF4	/* Enable aux device */
-#define AUX_DISABLE_DEV		0xF5	/* Disable aux device */
-#define AUX_RESET		0xFF	/* Reset aux device */
-#define AUX_ACK			0xFA	/* Command byte ACK. */
-
-#define AUX_BUF_SIZE		2048	/* This might be better divisible by
-					   three to make overruns stay in sync
-					   but then the read function would 
-					   need a lock etc - ick */
-
-struct aux_queue {
-	unsigned long head;
-	unsigned long tail;
-	wait_queue_head_t proc_list;
-	struct fasync_struct *fasync;
-	unsigned char buf[AUX_BUF_SIZE];
-};
-
-/*
- * Send a byte to the mouse.
- */
-static void aux_write_dev(int val)
-{
-	while (!(iomd_readb(IOMD_MSECTL) & 0x80));
-	iomd_writeb(val, IOMD_MSEDAT);
-}
-
-/*
- * Send a byte to the mouse & handle returned ack
- */
-static void aux_write_ack(int val)
-{
-	while (!(iomd_readb(IOMD_MSECTL) & 0x80));
-	iomd_writeb(val, IOMD_MSEDAT);
-
-	/* we expect an ACK in response. */
-	mouse_reply_expected++;
-}
-
-static unsigned char get_from_queue(void)
-{
-	unsigned char result;
-
-	result = queue->buf[queue->tail];
-	queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
-	return result;
-}
-
-static void psaux_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	int val = iomd_readb(IOMD_MSEDAT);
-
-	if (mouse_reply_expected) {
-		if (val == AUX_ACK) {
-			mouse_reply_expected--;
-			return;
-		}
-		mouse_reply_expected = 0;
-	}
-
-	add_mouse_randomness(val);
-	if (aux_count) {
-		int head = queue->head;
-
-		queue->buf[head] = val;
-		head = (head + 1) & (AUX_BUF_SIZE-1);
-		if (head != queue->tail) {
-			queue->head = head;
-			kill_fasync(&queue->fasync, SIGIO, POLL_IN);
-			wake_up_interruptible(&queue->proc_list);
-		}
-	}
-}
-
-static inline int queue_empty(void)
-{
-	return queue->head == queue->tail;
-}
-
-static int fasync_aux(int fd, struct file *filp, int on)
-{
-	int retval;
-
-	retval = fasync_helper(fd, filp, on, &queue->fasync);
-	if (retval < 0)
-		return retval;
-	return 0;
-}
-
-
-/*
- * Random magic cookie for the aux device
- */
-#define AUX_DEV ((void *)queue)
-
-static int release_aux(struct inode * inode, struct file * file)
-{
-	fasync_aux(-1, file, 0);
-	if (--aux_count)
-		return 0;
-	free_irq(IRQ_MOUSERX, AUX_DEV);
-	return 0;
-}
-
-/*
- * Install interrupt handler.
- * Enable auxiliary device.
- */
-
-static int open_aux(struct inode * inode, struct file * file)
-{
-	if (aux_count++)
-		return 0;
-
-	queue->head = queue->tail = 0;		/* Flush input queue */
-	if (request_irq(IRQ_MOUSERX, psaux_interrupt, SA_SHIRQ, "ps/2 mouse", 
-			AUX_DEV)) {
-		aux_count--;
-		return -EBUSY;
-	}
-
-	aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
-
-	return 0;
-}
-
-/*
- * Put bytes from input queue to buffer.
- */
-
-static ssize_t read_aux(struct file * file, char * buffer,
-			size_t count, loff_t *ppos)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t i = count;
-	unsigned char c;
-
-	if (queue_empty()) {
-		if (file->f_flags & O_NONBLOCK)
-			return -EAGAIN;
-		add_wait_queue(&queue->proc_list, &wait);
-repeat:
-		current->state = TASK_INTERRUPTIBLE;
-		if (queue_empty() && !signal_pending(current)) {
-			schedule();
-			goto repeat;
-		}
-		current->state = TASK_RUNNING;
-		remove_wait_queue(&queue->proc_list, &wait);
-	}
-	while (i > 0 && !queue_empty()) {
-		c = get_from_queue();
-		put_user(c, buffer++);
-		i--;
-	}
-	if (count-i) {
-		file->f_dentry->d_inode->i_atime = CURRENT_TIME;
-		return count-i;
-	}
-	if (signal_pending(current))
-		return -ERESTARTSYS;
-	return 0;
-}
-
-/*
- * Write to the aux device.
- */
-
-static ssize_t write_aux(struct file * file, const char * buffer,
-			 size_t count, loff_t *ppos)
-{
-	ssize_t retval = 0;
-
-	if (count) {
-		ssize_t written = 0;
-
-		if (count > 32)
-			count = 32; /* Limit to 32 bytes. */
-		do {
-			char c;
-			get_user(c, buffer++);
-			aux_write_dev(c);
-			written++;
-		} while (--count);
-		retval = -EIO;
-		if (written) {
-			retval = written;
-			file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
-		}
-	}
-
-	return retval;
-}
-
-static unsigned int aux_poll(struct file *file, poll_table * wait)
-{
-	poll_wait(file, &queue->proc_list, wait);
-	if (!queue_empty())
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
-struct file_operations psaux_fops = {
-	.read		= read_aux,
-	.write		= write_aux,
-	.poll		= aux_poll,
-	.open		= open_aux,
-	.release	= release_aux,
-	.fasync		= fasync_aux,
-};
-
-/*
- * Initialize driver.
- */
-static struct miscdevice psaux_mouse = {
-	PSMOUSE_MINOR, "psaux", &psaux_fops
-};
-
-int __init psaux_init(void)
-{
-	/* Reset the mouse state machine. */
-	iomd_writeb(0, IOMD_MSECTL);
-	iomd_writeb(8, IOMD_MSECTL);
-  
-	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
-	if (queue == NULL)
-		return -ENOMEM;
-
-	if (misc_register(&psaux_mouse)) {
-		kfree(queue);
-		return -ENODEV;
-	}
-
-	memset(queue, 0, sizeof(*queue));
-	queue->head = queue->tail = 0;
-	init_waitqueue_head(&queue->proc_list);
-
-	aux_write_ack(AUX_SET_SAMPLE);
-	aux_write_ack(100);			/* 100 samples/sec */
-	aux_write_ack(AUX_SET_RES);
-	aux_write_ack(3);			/* 8 counts per mm */
-	aux_write_ack(AUX_SET_SCALE21);		/* 2:1 scaling */
-
-	return 0;
-}
diff -Nru a/drivers/atm/Makefile b/drivers/atm/Makefile
--- a/drivers/atm/Makefile	Wed May  7 12:23:04 2003
+++ b/drivers/atm/Makefile	Thu May 29 20:32:49 2003
@@ -8,7 +8,9 @@
 host-progs	:= fore200e_mkfirm
 
 # Files generated that shall be removed upon make clean
-clean-files := {atmsar11,pca200e,pca200e_ecd,sba200e_ecd}.{bin,bin1,bin2}
+clean-files := atmsar11.bin atmsar11.bin1 atmsar11.bin2 pca200e.bin \
+	pca200e.bin1 pca200e.bin2 pca200e_ecd.bin pca200e_ecd.bin1 \
+	pca200e_ecd.bin2 sba200e_ecd.bin sba200e_ecd.bin1 sba200e_ecd.bin2
 # Firmware generated that shall be removed upon make clean
 clean-files += fore200e_pca_fw.c fore200e_sba_fw.c
 
diff -Nru a/drivers/atm/he.c b/drivers/atm/he.c
--- a/drivers/atm/he.c	Thu May 15 17:20:17 2003
+++ b/drivers/atm/he.c	Thu May 29 19:58:27 2003
@@ -132,9 +132,9 @@
 
 #undef DEBUG
 #ifdef DEBUG
-#define HPRINTK(fmt,args...)	hprintk(fmt,args)
+#define HPRINTK(fmt,args...)	printk(KERN_DEBUG DEV_LABEL "%d: " fmt, he_dev->number , ##args)
 #else
-#define HPRINTK(fmt,args...)	do { } while(0)
+#define HPRINTK(fmt,args...)	do { } while (0)
 #endif /* DEBUG */
 
 
@@ -179,9 +179,7 @@
    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 */
@@ -189,7 +187,7 @@
 #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_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 */
@@ -203,7 +201,7 @@
 	(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);
+	while (he_readl(he_dev, CON_CTL) & CON_CTL_BUSY);
 }
 
 #define he_writel_rcm(dev, val, reg) 				\
@@ -219,7 +217,7 @@
 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);
+	while (he_readl(he_dev, CON_CTL) & CON_CTL_BUSY);
 	return he_readl(he_dev, CON_DAT);
 }
 
@@ -374,7 +372,8 @@
 
 	printk(KERN_INFO "he: %s\n", version);
 
-	if (pci_enable_device(pci_dev)) return -EIO;
+	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;
@@ -407,7 +406,8 @@
 		goto init_one_failure;
 	}
 	he_dev->next = NULL;
-	if (he_devs) he_dev->next = he_devs;
+	if (he_devs)
+		he_dev->next = he_devs;
 	he_devs = he_dev;
 	return 0;
 
@@ -447,11 +447,11 @@
 
         unsigned exp = 0;
 
-        if (rate == 0) return(0);
+        if (rate == 0)
+		return(0);
 
         rate <<= 9;
-        while (rate > 0x3ff)
-        {
+        while (rate > 0x3ff) {
                 ++exp;
                 rate >>= 1;
         }
@@ -472,16 +472,14 @@
 
 	he_writel(he_dev, lbufd_index, RLBF0_H);
 
-        for (i = 0, lbuf_count = 0; i < he_dev->r0_numbuffs; ++i)
-        {
+        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)
-                {
+                if (++lbuf_count == lbufs_per_row) {
                         lbuf_count = 0;
                         row_offset += he_dev->bytes_per_row;
                 }
@@ -505,16 +503,14 @@
 
 	he_writel(he_dev, lbufd_index, RLBF1_H);
 
-        for (i = 0, lbuf_count = 0; i < he_dev->r1_numbuffs; ++i)
-        {
+        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)
-                {
+                if (++lbuf_count == lbufs_per_row) {
                         lbuf_count = 0;
                         row_offset += he_dev->bytes_per_row;
                 }
@@ -538,16 +534,14 @@
 
 	he_writel(he_dev, lbufd_index, TLBF_H);
 
-        for (i = 0, lbuf_count = 0; i < he_dev->tx_numbuffs; ++i)
-        {
+        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)
-                {
+                if (++lbuf_count == lbufs_per_row) {
                         lbuf_count = 0;
                         row_offset += he_dev->bytes_per_row;
                 }
@@ -562,8 +556,7 @@
 {
 	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) 
-	{
+	if (he_dev->tpdrq_base == NULL) {
 		hprintk("failed to alloc tpdrq\n");
 		return -ENOMEM;
 	}
@@ -588,7 +581,7 @@
 
 	/* 5.1.7 cs block initialization */
 
-	for(reg = 0; reg < 0x20; ++reg)
+	for (reg = 0; reg < 0x20; ++reg)
 		he_writel_mbox(he_dev, 0x0, CS_STTIM0 + reg);
 
 	/* rate grid timer reload values */
@@ -597,8 +590,7 @@
 	rate = he_dev->atm_dev->link_rate;
 	delta = rate / 16 / 2;
 
-	for(reg = 0; reg < 0x10; ++reg)
-	{
+	for (reg = 0; reg < 0x10; ++reg) {
 		/* 2.4 internal transmit function
 		 *
 	 	 * we initialize the first row in the rate grid.
@@ -610,8 +602,7 @@
 		rate -= delta;
 	}
 
-	if (he_is622(he_dev))
-	{
+	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);
@@ -640,9 +631,7 @@
 		/* table 5.9 */
 		he_writel_mbox(he_dev, 0x5, CS_OTPPER);
 		he_writel_mbox(he_dev, 0x14, CS_OTWPER);
-	}
-	else
-	{
+	} else {
 		/* table 5.1 (4 cells per lbuf) */
 		he_writel_mbox(he_dev, 0x000400ea, CS_ERTHR0);
 		he_writel_mbox(he_dev, 0x00063388, CS_ERTHR1);
@@ -671,20 +660,19 @@
 		/* 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)
+	for (reg = 0; reg < 0x8; ++reg)
 		he_writel_mbox(he_dev, 0x0, CS_HGRRT0 + reg);
 
 }
 
-static void __init
+static int __init
 he_init_cs_block_rcm(struct he_dev *he_dev)
 {
-	unsigned rategrid[16][16];
+	unsigned (*rategrid)[16][16];
 	unsigned rate, delta;
 	int i, j, reg;
 
@@ -692,6 +680,10 @@
 	unsigned long long rate_cps;
         int mult, buf, buf_limit = 4;
 
+	rategrid = kmalloc( sizeof(unsigned) * 16 * 16, GFP_KERNEL);
+	if (!rategrid)
+		return -ENOMEM;
+
 	/* initialize rate grid group table */
 
 	for (reg = 0x0; reg < 0xff; ++reg)
@@ -720,18 +712,17 @@
 	 * in order to construct the rate to group table below
 	 */
 
-	for (j = 0; j < 16; j++)
-	{
-		rategrid[0][j] = rate;
+	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;
+				(*rategrid)[i][j] = (*rategrid)[i - 1][j] / 4;
 			else
-				rategrid[i][j] = rategrid[i - 1][j] / 2;
+				(*rategrid)[i][j] = (*rategrid)[i - 1][j] / 2;
 
 	/*
 	 * 2.4 transmit internal function
@@ -742,8 +733,7 @@
 	 */
 
 	rate_atmf = 0;
-	while (rate_atmf < 0x400)
-	{
+	while (rate_atmf < 0x400) {
 		man = (rate_atmf & 0x1f) << 4;
 		exp = rate_atmf >> 5;
 
@@ -753,12 +743,12 @@
 		*/
 		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 */
+		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? */
+			if ((*rategrid)[i/16][i%16] >= rate_cps)
+				break;	 /* pick nearest rate instead? */
 
 		/*
 		 * each table entry is 16 bits: (rate grid index (8 bits)
@@ -773,12 +763,17 @@
 		/* 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;
+                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;
+                if (buf > buf_limit)
+			buf = buf_limit;
 		reg = (reg<<16) | ((i<<8) | buf);
 
 #define RTGTBL_OFFSET 0x400
@@ -789,6 +784,9 @@
 
 		++rate_atmf;
 	}
+
+	kfree(rategrid);
+	return 0;
 }
 
 static int __init
@@ -801,8 +799,7 @@
 #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)
-	{
+	if (he_dev->rbps_pool == NULL) {
 		hprintk("unable to create rbps pages\n");
 		return -ENOMEM;
 	}
@@ -817,16 +814,14 @@
 
 	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)
-	{
+	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)
-	{
+	for (i = 0; i < CONFIG_RBPS_SIZE; ++i) {
 		dma_addr_t dma_handle;
 		void *cpuaddr;
 
@@ -868,16 +863,14 @@
 #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)
-	{
+	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)
-	{
+	if (he_dev->rbpl_pages == NULL) {
 		hprintk("unable to create rbpl pages\n");
 		return -ENOMEM;
 	}
@@ -885,16 +878,14 @@
 
 	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)
-	{
+	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)
-	{
+	for (i = 0; i < CONFIG_RBPL_SIZE; ++i) {
 		dma_addr_t dma_handle;
 		void *cpuaddr;
 
@@ -910,7 +901,6 @@
 		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];
 
@@ -929,8 +919,7 @@
 
 	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)
-	{
+	if (he_dev->rbrq_base == NULL) {
 		hprintk("failed to allocate rbrq\n");
 		return -ENOMEM;
 	}
@@ -942,13 +931,11 @@
 	he_writel(he_dev,
 		RBRQ_THRESH(CONFIG_RBRQ_THRESH) | RBRQ_SIZE(CONFIG_RBRQ_SIZE-1),
 						G0_RBRQ_Q + (group * 16));
-	if (irq_coalesce)
-	{
+	if (irq_coalesce) {
 		hprintk("coalescing interrupts\n");
 		he_writel(he_dev, RBRQ_TIME(768) | RBRQ_COUNT(7),
 						G0_RBRQ_I + (group * 16));
-	}
-	else
+	} else
 		he_writel(he_dev, RBRQ_TIME(0) | RBRQ_COUNT(1),
 						G0_RBRQ_I + (group * 16));
 
@@ -956,8 +943,7 @@
 
 	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)
-	{
+	if (he_dev->tbrq_base == NULL) {
 		hprintk("failed to allocate tbrq\n");
 		return -ENOMEM;
 	}
@@ -983,8 +969,7 @@
 
         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)
-	{
+	if (he_dev->irq_base == NULL) {
 		hprintk("failed to allocate irq\n");
 		return -ENOMEM;
 	}
@@ -994,7 +979,7 @@
 	he_dev->irq_head = he_dev->irq_base;
 	he_dev->irq_tail = he_dev->irq_base;
 
-	for(i=0; i < CONFIG_IRQ_SIZE; ++i)
+	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);
@@ -1026,8 +1011,7 @@
 	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))
-	{
+	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;
         }   
@@ -1067,46 +1051,39 @@
 	 */
 
 	/* 4.3 pci bus controller-specific initialization */
-	if (pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0) != 0)
-	{
+	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)
-	{
+	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)
-	{
+	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)
-	{
+	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))
-	{
+	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)
-	{
+	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))
-	{
+	if (pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &timer)) {
 		hprintk("can't read latency timer?\n");
 		return -EINVAL;
 	}
@@ -1120,8 +1097,7 @@
 	 *
 	 */ 
 #define LAT_TIMER 209
-	if (timer < LAT_TIMER)
-	{
+	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))
@@ -1139,8 +1115,7 @@
 
 	udelay(16*1000);	/* 16 ms */
 	status = he_readl(he_dev, RESET_CNTL);
-	if ((status & BOARD_RST_STATUS) == 0)
-	{
+	if ((status & BOARD_RST_STATUS) == 0) {
 		hprintk("reset failed\n");
 		return -EINVAL;
 	}
@@ -1152,23 +1127,23 @@
 	else
 		gen_cntl_0 &= ~ENBL_64;
 
-	if (disable64 == 1)
-	{
+	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");
+	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)
+	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)
+	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",
@@ -1205,7 +1180,8 @@
 	he_writel(he_dev, lb_swap, LB_SWAP);
 
 	/* 4.10 initialize the interrupt queues */
-	if ((err = he_init_irq(he_dev)) != 0) return err;
+	if ((err = he_init_irq(he_dev)) != 0)
+		return err;
 
 #ifdef USE_TASKLET
 	tasklet_init(&he_dev->tasklet, he_tasklet, (unsigned long) he_dev);
@@ -1258,27 +1234,23 @@
 	he_dev->vcibits = CONFIG_DEFAULT_VCIBITS;
 	he_dev->vpibits = CONFIG_DEFAULT_VPIBITS;
 
-	if (nvpibits != -1 && nvcibits != -1 && nvpibits+nvcibits != HE_MAXCIDBITS)
-	{
+	if (nvpibits != -1 && nvcibits != -1 && nvpibits+nvcibits != HE_MAXCIDBITS) {
 		hprintk("nvpibits + nvcibits != %d\n", HE_MAXCIDBITS);
 		return -ENODEV;
 	}
 
-	if (nvpibits != -1)
-	{
+	if (nvpibits != -1) {
 		he_dev->vpibits = nvpibits;
 		he_dev->vcibits = HE_MAXCIDBITS - nvpibits;
 	}
 
-	if (nvcibits != -1)
-	{
+	if (nvcibits != -1) {
 		he_dev->vcibits = nvcibits;
 		he_dev->vpibits = HE_MAXCIDBITS - nvcibits;
 	}
 
 
-	if (he_is622(he_dev))
-	{
+	if (he_is622(he_dev)) {
 		he_dev->cells_per_row = 40;
 		he_dev->bytes_per_row = 2048;
 		he_dev->r0_numrows = 256;
@@ -1287,9 +1259,7 @@
 		he_dev->r0_startrow = 0;
 		he_dev->tx_startrow = 256;
 		he_dev->r1_startrow = 768;
-	}
-	else
-	{
+	} else {
 		he_dev->cells_per_row = 20;
 		he_dev->bytes_per_row = 1024;
 		he_dev->r0_numrows = 512;
@@ -1304,15 +1274,18 @@
 	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;
+	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;
+	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;
+	if (he_dev->tx_numbuffs > 5120)
+		he_dev->tx_numbuffs = 5120;
 
 	/* 5.1.2 configure hardware dependent registers */
 
@@ -1355,10 +1328,10 @@
 
 	/* 5.1.3 initialize connection memory */
 
-	for(i=0; i < TCM_MEM_SIZE; ++i)
+	for (i=0; i < TCM_MEM_SIZE; ++i)
 		he_writel_tcm(he_dev, 0, i);
 
-	for(i=0; i < RCM_MEM_SIZE; ++i)
+	for (i=0; i < RCM_MEM_SIZE; ++i)
 		he_writel_rcm(he_dev, 0, i);
 
 	/*
@@ -1448,8 +1421,7 @@
 
 	/* 5.1.5 initialize intermediate receive queues */
 
-	if (he_is622(he_dev))
-	{
+	if (he_is622(he_dev)) {
 		he_writel(he_dev, 0x000f, G0_INMQ_S);
 		he_writel(he_dev, 0x200f, G0_INMQ_L);
 
@@ -1473,9 +1445,7 @@
 
 		he_writel(he_dev, 0x007f, G7_INMQ_S);
 		he_writel(he_dev, 0x207f, G7_INMQ_L);
-	}
-	else
-	{
+	} else {
 		he_writel(he_dev, 0x0000, G0_INMQ_S);
 		he_writel(he_dev, 0x0008, G0_INMQ_L);
 
@@ -1514,7 +1484,8 @@
 
 	/* 5.1.8 cs block connection memory initialization */
 	
-	he_init_cs_block_rcm(he_dev);
+	if (he_init_cs_block_rcm(he_dev) < 0)
+		return -ENOMEM;
 
 	/* 5.1.10 initialize host structures */
 
@@ -1523,8 +1494,7 @@
 #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)
-	{
+	if (he_dev->tpd_pool == NULL) {
 		hprintk("unable to create tpd pci_pool\n");
 		return -ENOMEM;         
 	}
@@ -1536,8 +1506,7 @@
 	if (!he_dev->tpd_base)
 		return -ENOMEM;
 
-	for(i = 0; i < CONFIG_NUMTPDS; ++i)
-	{
+	for (i = 0; i < CONFIG_NUMTPDS; ++i) {
 		he_dev->tpd_base[i].status = (i << TPD_ADDR_SHIFT);
 		he_dev->tpd_base[i].inuse = 0;
 	}
@@ -1549,8 +1518,7 @@
 	if (he_init_group(he_dev, 0) != 0)
 		return -ENOMEM;
 
-	for (group = 1; group < HE_NUM_GROUPS; ++group)
-	{
+	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));
@@ -1580,8 +1548,7 @@
 
 	he_dev->hsp = pci_alloc_consistent(he_dev->pci_dev,
 				sizeof(struct he_hsp), &he_dev->hsp_phys);
-	if (he_dev->hsp == NULL)
-	{
+	if (he_dev->hsp == NULL) {
 		hprintk("failed to allocate host status page\n");
 		return -ENOMEM;
 	}
@@ -1596,8 +1563,7 @@
 		he_dev->atm_dev->phy->start(he_dev->atm_dev);
 #endif /* CONFIG_ATM_HE_USE_SUNI */
 
-	if (sdh)
-	{
+	if (sdh) {
 		/* this really should be in suni.c but for now... */
 
 		int val;
@@ -1620,8 +1586,7 @@
 #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)
-	{
+	if (he_dev->he_vcc_table == NULL) {
 		hprintk("failed to alloc he_vcc_table\n");
 		return -ENOMEM;
 	}
@@ -1629,8 +1594,7 @@
 				(1 << (he_dev->vcibits + he_dev->vpibits)));
 #endif
 
-	for (i = 0; i < HE_NUM_CS_STPER; ++i)
-	{
+	for (i = 0; i < HE_NUM_CS_STPER; ++i) {
 		he_dev->cs_stper[i].inuse = 0;
 		he_dev->cs_stper[i].pcr = -1;
 	}
@@ -1663,8 +1627,7 @@
 
 	/* disable interrupts */
 
-	if (he_dev->membase)
-	{
+	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);
@@ -1689,8 +1652,7 @@
 		he_dev->atm_dev->phy->stop(he_dev->atm_dev);
 #endif /* CONFIG_ATM_HE_USE_SUNI */
 
-	if (he_dev->irq)
-	{
+	if (he_dev->irq) {
 #ifdef BUS_INT_WAR
 		sn_delete_polled_interrupt(he_dev->irq);
 #endif
@@ -1705,11 +1667,9 @@
 		pci_free_consistent(he_dev->pci_dev, sizeof(struct he_hsp),
 						he_dev->hsp, he_dev->hsp_phys);
 
-	if (he_dev->rbpl_base)
-	{
+	if (he_dev->rbpl_base) {
 #ifdef USE_RBPL_POOL
-		for (i=0; i<CONFIG_RBPL_SIZE; ++i)
-		{
+		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;
 
@@ -1729,11 +1689,9 @@
 #endif
 
 #ifdef USE_RBPS
-	if (he_dev->rbps_base)
-	{
+	if (he_dev->rbps_base) {
 #ifdef USE_RBPS_POOL
-		for (i=0; i<CONFIG_RBPS_SIZE; ++i)
-		{
+		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;
 
@@ -1780,14 +1738,14 @@
 		kfree(he_dev->he_vcc_table);
 #endif
 
-	if (he_dev->pci_dev)
-	{
+	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);
+	if (he_dev->membase)
+		iounmap((void *) he_dev->membase);
 }
 
 static struct he_tpd *
@@ -1811,8 +1769,7 @@
 #else
 	int i;
 
-	for(i = 0; i < CONFIG_NUMTPDS; ++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;
@@ -1862,8 +1819,7 @@
 	int pdus_assembled = 0;
 	int updated = 0;
 
-	while (he_dev->rbrq_head != rbrq_tail)
-	{
+	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",
@@ -1895,8 +1851,7 @@
 #else
 		vcc = HE_LOOKUP_VCC(he_dev, cid);
 #endif
-		if (vcc == NULL)
-		{
+		if (vcc == NULL) {
 			hprintk("vcc == NULL  (cid 0x%x)\n", cid);
 			if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
 					rbp->status &= ~RBP_LOANED;
@@ -1905,16 +1860,14 @@
 		}
 
 		he_vcc = HE_VCC(vcc);
-		if (he_vcc == NULL)
-		{
+		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))
-		{
+		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;
@@ -1925,8 +1878,7 @@
 		he_vcc->pdu_len += buf_len;
 		++he_vcc->iov_tail;
 
-		if (RBRQ_CON_CLOSED(he_dev->rbrq_head))
-		{
+		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);
@@ -1934,17 +1886,16 @@
 		}
 
 #ifdef notdef
-		if ((he_vcc->iov_tail - he_vcc->iov_head) > HE_MAXIOV)
-		{
+		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_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))
-		{
+				|| RBRQ_CRC_ERR(he_dev->rbrq_head)) {
 			HPRINTK("%s%s (%d.%d)\n",
 				RBRQ_CRC_ERR(he_dev->rbrq_head)
 							? "CRC_ERR " : "",
@@ -1957,19 +1908,18 @@
 
 		skb = atm_alloc_charge(vcc, he_vcc->pdu_len + rx_skb_reserve,
 							GFP_ATOMIC);
-		if (!skb)
-		{
+		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);
+		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)
-		{
+		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),
@@ -1980,8 +1930,7 @@
 					he_dev->rbpl_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len);
 		}
 
-		switch(vcc->qos.aal)
-		{
+		switch (vcc->qos.aal) {
 			case ATM_AAL0:
 				/* 2.10.1.5 raw cell receive */
 				skb->len = ATM_AAL0_SDU;
@@ -1993,8 +1942,7 @@
 				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) 
-				{
+				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);
@@ -2018,9 +1966,8 @@
 return_host_buffers:
 		++pdus_assembled;
 
-		for(iov = he_vcc->iov_head;
-				iov < he_vcc->iov_tail; ++iov)
-		{
+		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)];
@@ -2041,9 +1988,9 @@
 
 	}
 
-	if (updated)
-	{
-		if (updated > he_dev->rbrq_peak) he_dev->rbrq_peak = updated;
+	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));
@@ -2069,8 +2016,7 @@
 
 	/* 2.1.6 transmit buffer return queue */
 
-	while (he_dev->tbrq_head != tbrq_tail)
-	{
+	while (he_dev->tbrq_head != tbrq_tail) {
 		++updated;
 
 		HPRINTK("tbrq%d 0x%x%s%s\n",
@@ -2081,19 +2027,16 @@
 #ifdef USE_TPD_POOL
 		tpd = NULL;
 		p = &he_dev->outstanding_tpds;
-		while ((p = p->next) != &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))
-			{
+			if (TPD_ADDR(__tpd->status) == TBRQ_TPD(he_dev->tbrq_head)) {
 				tpd = __tpd;
 				list_del(&__tpd->entry);
 				break;
 			}
 		}
 
-		if (tpd == NULL)
-		{
+		if (tpd == NULL) {
 			hprintk("unable to locate tpd for dma buffer %x\n",
 						TBRQ_TPD(he_dev->tbrq_head));
 			goto next_tbrq_entry;
@@ -2102,8 +2045,7 @@
 		tpd = &he_dev->tpd_base[ TPD_INDEX(TBRQ_TPD(he_dev->tbrq_head)) ];
 #endif
 
-		if (TBRQ_EOS(he_dev->tbrq_head))
-		{
+		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)
@@ -2112,19 +2054,18 @@
 			goto next_tbrq_entry;
 		}
 
-		for(slot = 0; slot < TPD_MAXIOV; ++slot)
-		{
+		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->iovec[slot].len & TPD_LST)
+				break;
 				
 		}
 
-		if (tpd->skb)	/* && !TBRQ_MULTIPLE(he_dev->tbrq_head) */
-		{
+		if (tpd->skb) {	/* && !TBRQ_MULTIPLE(he_dev->tbrq_head) */
 			if (tpd->vcc && tpd->vcc->pop)
 				tpd->vcc->pop(tpd->vcc, tpd->skb);
 			else
@@ -2133,7 +2074,8 @@
 
 next_tbrq_entry:
 #ifdef USE_TPD_POOL
-		if (tpd) pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status));
+		if (tpd)
+			pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status));
 #else
 		tpd->inuse = 0;
 #endif
@@ -2142,9 +2084,9 @@
 					TBRQ_MASK(++he_dev->tbrq_head));
 	}
 
-	if (updated)
-	{
-		if (updated > he_dev->tbrq_peak) he_dev->tbrq_peak = updated;
+	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));
@@ -2165,8 +2107,7 @@
 	rbpl_head = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base |
 					RBPL_MASK(he_readl(he_dev, G0_RBPL_S)));
 
-	for(;;)
-	{
+	for (;;) {
 		newtail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base |
 						RBPL_MASK(he_dev->rbpl_tail+1));
 
@@ -2177,7 +2118,6 @@
 		newtail->status |= RBP_LOANED;
 		he_dev->rbpl_tail = newtail;
 		++moved;
-
 	} 
 
 	if (moved) {
@@ -2199,8 +2139,7 @@
 	rbps_head = (struct he_rbp *) ((unsigned long)he_dev->rbps_base |
 					RBPS_MASK(he_readl(he_dev, G0_RBPS_S)));
 
-	for(;;)
-	{
+	for (;;) {
 		newtail = (struct he_rbp *) ((unsigned long)he_dev->rbps_base |
 						RBPS_MASK(he_dev->rbps_tail+1));
 
@@ -2211,7 +2150,6 @@
 		newtail->status |= RBP_LOANED;
 		he_dev->rbps_tail = newtail;
 		++moved;
-
 	} 
 
 	if (moved) {
@@ -2236,20 +2174,18 @@
 	HE_SPIN_LOCK(he_dev, flags);
 #endif
 
-	while(he_dev->irq_head != he_dev->irq_tail)
-	{
+	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)
-		{
+		switch (type) {
 			case ITYPE_RBRQ_THRESH:
-				hprintk("rbrq%d threshold\n", group);
+				HPRINTK("rbrq%d threshold\n", group);
+				/* fall through */
 			case ITYPE_RBRQ_TIMER:
-				if (he_service_rbrq(he_dev, group))
-				{
+				if (he_service_rbrq(he_dev, group)) {
 					he_service_rbpl(he_dev, group);
 #ifdef USE_RBPS
 					he_service_rbps(he_dev, group);
@@ -2257,7 +2193,8 @@
 				}
 				break;
 			case ITYPE_TBRQ_THRESH:
-				hprintk("tbrq%d threshold\n", group);
+				HPRINTK("tbrq%d threshold\n", group);
+				/* fall through */
 			case ITYPE_TPD_COMPLETE:
 				he_service_tbrq(he_dev, group);
 				break;
@@ -2270,17 +2207,16 @@
 #endif /* USE_RBPS */
 				break;
 			case ITYPE_PHY:
+				HPRINTK("phy interrupt\n");
 #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)
-				{
+				switch (type|group) {
 					case ITYPE_PARITY:
 						hprintk("parity error\n");
 						break;
@@ -2289,24 +2225,20 @@
 						break;
 				}
 				break;
-			default:
-				if (he_dev->irq_head->isw == ITYPE_INVALID)
-				{
-					/* see 8.1.1 -- check all queues */
+			case ITYPE_TYPE(ITYPE_INVALID):
+				/* see 8.1.1 -- check all queues */
 
-					HPRINTK("isw not updated 0x%x\n",
-						he_dev->irq_head->isw);
+				HPRINTK("isw not updated 0x%x\n", he_dev->irq_head->isw);
 
-					he_service_rbrq(he_dev, 0);
-					he_service_rbpl(he_dev, 0);
+				he_service_rbrq(he_dev, 0);
+				he_service_rbpl(he_dev, 0);
 #ifdef USE_RBPS
-					he_service_rbps(he_dev, 0);
+				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_service_tbrq(he_dev, 0);
+				break;
+			default:
+				hprintk("bad isw 0x%x?\n", he_dev->irq_head->isw);
 		}
 
 		he_dev->irq_head->isw = ITYPE_INVALID;
@@ -2314,9 +2246,9 @@
 		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;
+	if (updated) {
+		if (updated > he_dev->irq_peak)
+			he_dev->irq_peak = updated;
 
 		he_writel(he_dev,
 			IRQ_SIZE(CONFIG_IRQ_SIZE) |
@@ -2344,8 +2276,7 @@
 	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)
-	{
+	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));
@@ -2357,8 +2288,7 @@
 		hprintk("spurious (or shared) interrupt?\n");
 #endif
 
-	if (he_dev->irq_head != he_dev->irq_tail)
-	{
+	if (he_dev->irq_head != he_dev->irq_tail) {
 		handled = 1;
 #ifdef USE_TASKLET
 		tasklet_schedule(&he_dev->tasklet);
@@ -2395,14 +2325,12 @@
 	 * head for every enqueue would be unnecessarily slow)
 	 */
 
-	if (new_tail == he_dev->tpdrq_head)
-	{
+	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)
-		{
+		if (new_tail == he_dev->tpdrq_head) {
 			hprintk("tpdrq full (cid 0x%x)\n", cid);
 			/*
 			 * FIXME
@@ -2410,8 +2338,7 @@
 			 * after service_tbrq, service the backlog
 			 * for now, we just drop the pdu
 			 */
-			if (tpd->skb)
-			{
+			if (tpd->skb) {
 				if (tpd->vcc->pop)
 					tpd->vcc->pop(tpd->vcc, tpd->skb);
 				else
@@ -2456,12 +2383,12 @@
 	unsigned cid, rsr0, rsr1, rsr4, tsr0, tsr0_aal, tsr4, period, reg, clock;
 
 	
-	if ((err = atm_find_ci(vcc, &vpi, &vci)))
-	{
+	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;
+	if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC)
+		return 0;
 	vcc->vpi = vpi;
 	vcc->vci = vci;
 
@@ -2472,8 +2399,7 @@
 	cid = he_mkcid(he_dev, vpi, vci);
 
 	he_vcc = (struct he_vcc *) kmalloc(sizeof(struct he_vcc), GFP_ATOMIC);
-	if (he_vcc == NULL)
-	{
+	if (he_vcc == NULL) {
 		hprintk("unable to allocate he_vcc during open\n");
 		return -ENOMEM;
 	}
@@ -2487,8 +2413,7 @@
 
 	HE_VCC(vcc) = he_vcc;
 
-	if (vcc->qos.txtp.traffic_class != ATM_NONE)
-	{
+	if (vcc->qos.txtp.traffic_class != ATM_NONE) {
 		int pcr_goal;
 
                 pcr_goal = atm_pcr_goal(&vcc->qos.txtp);
@@ -2499,8 +2424,7 @@
 
 		HPRINTK("open tx cid 0x%x pcr_goal %d\n", cid, pcr_goal);
 
-		switch (vcc->qos.aal)
-		{
+		switch (vcc->qos.aal) {
 			case ATM_AAL5:
 				tsr0_aal = TSR0_AAL5;
 				tsr4 = TSR4_AAL5;
@@ -2518,15 +2442,13 @@
 		tsr0 = he_readl_tsr0(he_dev, cid);
 		HE_SPIN_UNLOCK(he_dev, flags);
 
-		if (TSR0_CONN_STATE(tsr0) != 0)
-		{
+		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)
-		{
+		switch (vcc->qos.txtp.traffic_class) {
 			case ATM_UBR:
 				/* 2.3.3.1 open connection ubr */
 
@@ -2548,13 +2470,12 @@
 				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)
+				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;
+					    he_dev->cs_stper[reg].pcr == pcr_goal)
+							break;
 
-				if (reg == HE_NUM_CS_STPER)
-				{
+				if (reg == HE_NUM_CS_STPER) {
 					err = -EBUSY;
 					HE_SPIN_UNLOCK(he_dev, flags);
 					goto open_failed;
@@ -2610,15 +2531,13 @@
 		HE_SPIN_UNLOCK(he_dev, flags);
 	}
 
-	if (vcc->qos.rxtp.traffic_class != ATM_NONE)
-	{
+	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)
-		{
+		switch (vcc->qos.aal) {
 			case ATM_AAL5:
 				aal = RSR0_AAL5;
 				break;
@@ -2633,8 +2552,7 @@
 		HE_SPIN_LOCK(he_dev, flags);
 
 		rsr0 = he_readl_rsr0(he_dev, cid);
-		if (rsr0 & RSR0_OPEN_CONN)
-		{
+		if (rsr0 & RSR0_OPEN_CONN) {
 			HE_SPIN_UNLOCK(he_dev, flags);
 
 			hprintk("cid 0x%x not idle (rsr0 = 0x%x)\n", cid, rsr0);
@@ -2653,7 +2571,8 @@
 				(RSR0_EPD_ENABLE|RSR0_PPD_ENABLE) : 0;
 
 #ifdef USE_CHECKSUM_HW
-		if (vpi == 0 && vci >= ATM_NOT_RSV_VCI) rsr0 |= RSR0_TCP_CKSUM;
+		if (vpi == 0 && vci >= ATM_NOT_RSV_VCI)
+			rsr0 |= RSR0_TCP_CKSUM;
 #endif
 
 		he_writel_rsr4(he_dev, rsr4, cid);
@@ -2675,9 +2594,9 @@
 
 open_failed:
 
-	if (err)
-	{
-		if (he_vcc) kfree(he_vcc);
+	if (err) {
+		if (he_vcc)
+			kfree(he_vcc);
 		clear_bit(ATM_VF_ADDR, &vcc->flags);
 	}
 	else
@@ -2703,8 +2622,7 @@
 	clear_bit(ATM_VF_READY, &vcc->flags);
 	cid = he_mkcid(he_dev, vcc->vpi, vcc->vci);
 
-	if (vcc->qos.rxtp.traffic_class != ATM_NONE)
-	{
+	if (vcc->qos.rxtp.traffic_class != ATM_NONE) {
 		int timeout;
 
 		HPRINTK("close rx cid 0x%x\n", cid);
@@ -2714,8 +2632,7 @@
 		/* wait for previous close (if any) to finish */
 
 		HE_SPIN_LOCK(he_dev, flags);
-		while(he_readl(he_dev, RCC_STAT) & RCC_BUSY)
-		{
+		while (he_readl(he_dev, RCC_STAT) & RCC_BUSY) {
 			HPRINTK("close cid 0x%x RCC_BUSY\n", cid);
 			udelay(250);
 		}
@@ -2745,8 +2662,7 @@
 
 	}
 
-	if (vcc->qos.txtp.traffic_class != ATM_NONE)
-	{
+	if (vcc->qos.txtp.traffic_class != ATM_NONE) {
 		volatile unsigned tsr4, tsr0;
 		int timeout;
 
@@ -2761,19 +2677,19 @@
 		 * TBRQ, the host issues the close command to the adapter.
 		 */
 
-		while (((tx_inuse = atomic_read(&vcc->sk->wmem_alloc)) > 0)
-							&& (retry < MAX_RETRY))
-		{
+		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;
+			if (sleep < HZ)
+				sleep = sleep * 2;
 
 			++retry;
 		}
 
-		if (tx_inuse) hprintk("close tx cid 0x%x tx_inuse = %d\n",
-								cid, tx_inuse);
+		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 */
 
@@ -2784,8 +2700,7 @@
 		(void) he_readl_tsr4(he_dev, cid);
 #endif
 
-		switch(vcc->qos.txtp.traffic_class)
-		{
+		switch (vcc->qos.txtp.traffic_class) {
 			case ATM_UBR:
 				he_writel_tsr1(he_dev, 
 					TSR1_MCR(rate_to_atmf(200000))
@@ -2796,10 +2711,8 @@
 				break;
 		}
 
-
 		tpd = __alloc_tpd(he_dev);
-		if (tpd == NULL)
-		{
+		if (tpd == NULL) {
 			hprintk("close tx he_alloc_tpd failed cid 0x%x\n", cid);
 			goto close_tx_incomplete;
 		}
@@ -2818,30 +2731,25 @@
 		remove_wait_queue(&he_vcc->tx_waitq, &wait);
 		set_current_state(TASK_RUNNING);
 
-		if (timeout == 0)
-		{
+		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))
-		{
+		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)
-		{
+		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)
-		{
+		if (vcc->qos.txtp.traffic_class == ATM_CBR) {
 			int reg = he_vcc->rc_index;
 
 			HPRINTK("cs_stper reg = %d\n", reg);
@@ -2889,8 +2797,7 @@
 	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)))
-	{
+	    ((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);
@@ -2901,8 +2808,7 @@
 	}
 
 #ifndef USE_SCATTERGATHER
-	if (skb_shinfo(skb)->nr_frags)
-	{
+	if (skb_shinfo(skb)->nr_frags) {
 		hprintk("no scatter/gather support\n");
 		if (vcc->pop)
 			vcc->pop(vcc, skb);
@@ -2915,8 +2821,7 @@
 	HE_SPIN_LOCK(he_dev, flags);
 
 	tpd = __alloc_tpd(he_dev);
-	if (tpd == NULL)
-	{
+	if (tpd == NULL) {
 		if (vcc->pop)
 			vcc->pop(vcc, skb);
 		else
@@ -2928,15 +2833,15 @@
 
 	if (vcc->qos.aal == ATM_AAL5)
 		tpd->status |= TPD_CELLTYPE(TPD_USERCELL);
-	else
-	{
+	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;
+		if (clp)
+			tpd->status |= TPD_CLP;
 
 		skb_pull(skb, ATM_AAL0_SDU - ATM_CELL_PAYLOAD);
 	}
@@ -2947,12 +2852,10 @@
 	tpd->iovec[slot].len = skb->len - skb->data_len;
 	++slot;
 
-	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
-	{
+	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 */
-		{
+		if (slot == TPD_MAXIOV) {	/* queue tpd; start new tpd */
 			tpd->vcc = vcc;
 			tpd->skb = NULL;	/* not the last fragment
 						   so dont ->push() yet */
@@ -2960,8 +2863,7 @@
 
 			__enqueue_tpd(he_dev, tpd, cid);
 			tpd = __alloc_tpd(he_dev);
-			if (tpd == NULL)
-			{
+			if (tpd == NULL) {
 				if (vcc->pop)
 					vcc->pop(vcc, skb);
 				else
@@ -3010,16 +2912,15 @@
 	struct he_ioctl_reg reg;
 	int err = 0;
 
-	switch (cmd)
-	{
+	switch (cmd) {
 		case HE_GET_REG:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+			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)
-			{
+			switch (reg.type) {
 				case HE_REGTYPE_PCI:
 					reg.val = he_readl(he_dev, reg.addr);
 					break;
@@ -3040,7 +2941,8 @@
 					break;
 			}
 			HE_SPIN_UNLOCK(he_dev, flags);
-			if (err == 0) copy_to_user((struct he_ioctl_reg *) arg, &reg,
+			if (err == 0)
+				copy_to_user((struct he_ioctl_reg *) arg, &reg,
 							sizeof(struct he_ioctl_reg));
 			break;
 		default:
@@ -3048,7 +2950,7 @@
 			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;
+			err = -EINVAL;
 #endif /* CONFIG_ATM_HE_USE_SUNI */
 			break;
 	}
@@ -3146,7 +3048,8 @@
         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);
+	if (inuse < 0)
+		inuse += CONFIG_RBPL_SIZE * sizeof(struct he_rbp);
 	inuse /= sizeof(struct he_rbp);
 
 	if (!left--)
diff -Nru a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
--- a/drivers/block/cciss_scsi.c	Wed May 14 23:48:56 2003
+++ b/drivers/block/cciss_scsi.c	Mon May 12 07:33:45 2003
@@ -54,11 +54,11 @@
 const char *cciss_scsi_info(struct Scsi_Host *sa);
 
 int cciss_scsi_proc_info(
+		struct Scsi_Host *sh,
 		char *buffer, /* data buffer */
 		char **start, 	   /* where data in buffer starts */
 		off_t offset,	   /* offset from start of imaginary file */
 		int length, 	   /* length of data in buffer */
-		int hostnum, 	   /* which host adapter (always zero for me) */
 		int func);	   /* 0 == read, 1 == write */
 
 int cciss_scsi_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *));
@@ -1121,24 +1121,19 @@
 
 
 int
-cciss_scsi_proc_info(char *buffer, /* data buffer */
+cciss_scsi_proc_info(struct Scsi_Host *sh,
+		char *buffer, /* data buffer */
 		char **start, 	   /* where data in buffer starts */
 		off_t offset,	   /* offset from start of imaginary file */
 		int length, 	   /* length of data in buffer */
-		int hostnum, 	   /* which host adapter (always zero for me) */
 		int func)	   /* 0 == read, 1 == write */
 {
 
 	int buflen, datalen;
-	struct Scsi_Host *sh;
 	ctlr_info_t *ci;
 	int cntl_num;
 
 
-	sh = scsi_host_hn_get(hostnum);
-	if (sh == NULL) /* This really shouldn't ever happen. */
-		return -EINVAL;
-
 	ci = (ctlr_info_t *) sh->hostdata[0];
 	if (ci == NULL)  /* This really shouldn't ever happen. */
 		return -EINVAL;
@@ -1146,7 +1141,7 @@
 	cntl_num = ci->ctlr;	/* Get our index into the hba[] array */
 
 	if (func == 0) {	/* User is reading from /proc/scsi/ciss*?/?*  */
-		buflen = sprintf(buffer, "hostnum=%d\n", hostnum); 	
+		buflen = sprintf(buffer, "hostnum=%d\n", sh->host_no); 	
 
 		datalen = buflen - offset;
 		if (datalen < 0) { 	/* they're reading past EOF. */
@@ -1156,7 +1151,7 @@
 			*start = buffer + offset;
 		return(datalen);
 	} else 	/* User is writing to /proc/scsi/cciss*?/?*  ... */
-		return cciss_scsi_user_command(cntl_num, hostnum,
+		return cciss_scsi_user_command(cntl_num, sh->host_no,
 			buffer, length);	
 } 
 
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Thu May  8 02:30:11 2003
+++ b/drivers/block/ll_rw_blk.c	Tue May 27 13:21:00 2003
@@ -413,11 +413,12 @@
 {
 	struct blk_queue_tag *bqt = q->queue_tags;
 
-	if (unlikely(bqt == NULL || bqt->max_depth < tag))
+	if (unlikely(bqt == NULL || tag >= bqt->real_max_depth))
 		return NULL;
 
 	return bqt->tag_index[tag];
 }
+
 /**
  * blk_queue_free_tags - release tag maintenance info
  * @q:  the request queue for the device
@@ -448,39 +449,28 @@
 	q->queue_flags &= ~(1 << QUEUE_FLAG_QUEUED);
 }
 
-/**
- * blk_queue_init_tags - initialize the queue tag info
- * @q:  the request queue for the device
- * @depth:  the maximum queue depth supported
- **/
-int blk_queue_init_tags(request_queue_t *q, int depth)
+static int init_tag_map(struct blk_queue_tag *tags, int depth)
 {
-	struct blk_queue_tag *tags;
 	int bits, i;
 
 	if (depth > (queue_nr_requests*2)) {
 		depth = (queue_nr_requests*2);
-		printk("blk_queue_init_tags: adjusted depth to %d\n", depth);
+		printk(KERN_ERR "%s: adjusted depth to %d\n", __FUNCTION__, depth);
 	}
 
-	tags = kmalloc(sizeof(struct blk_queue_tag),GFP_ATOMIC);
-	if (!tags)
-		goto fail;
-
 	tags->tag_index = kmalloc(depth * sizeof(struct request *), GFP_ATOMIC);
 	if (!tags->tag_index)
-		goto fail_index;
+		goto fail;
 
 	bits = (depth / BLK_TAGS_PER_LONG) + 1;
 	tags->tag_map = kmalloc(bits * sizeof(unsigned long), GFP_ATOMIC);
 	if (!tags->tag_map)
-		goto fail_map;
+		goto fail;
 
 	memset(tags->tag_index, 0, depth * sizeof(struct request *));
 	memset(tags->tag_map, 0, bits * sizeof(unsigned long));
-	INIT_LIST_HEAD(&tags->busy_list);
-	tags->busy = 0;
 	tags->max_depth = depth;
+	tags->real_max_depth = bits * BITS_PER_LONG;
 
 	/*
 	 * set the upper bits if the depth isn't a multiple of the word size
@@ -488,22 +478,89 @@
 	for (i = depth; i < bits * BLK_TAGS_PER_LONG; i++)
 		__set_bit(i, tags->tag_map);
 
+	return 0;
+fail:
+	kfree(tags->tag_index);
+	return -ENOMEM;
+}
+
+
+/**
+ * blk_queue_init_tags - initialize the queue tag info
+ * @q:  the request queue for the device
+ * @depth:  the maximum queue depth supported
+ **/
+int blk_queue_init_tags(request_queue_t *q, int depth)
+{
+	struct blk_queue_tag *tags;
+
+	tags = kmalloc(sizeof(struct blk_queue_tag),GFP_ATOMIC);
+	if (!tags)
+		goto fail;
+
+	if (init_tag_map(tags, depth))
+		goto fail;
+
+	INIT_LIST_HEAD(&tags->busy_list);
+	tags->busy = 0;
+
 	/*
 	 * assign it, all done
 	 */
 	q->queue_tags = tags;
 	q->queue_flags |= (1 << QUEUE_FLAG_QUEUED);
 	return 0;
-
-fail_map:
-	kfree(tags->tag_index);
-fail_index:
-	kfree(tags);
 fail:
+	kfree(tags);
 	return -ENOMEM;
 }
 
 /**
+ * blk_queue_resize_tags - change the queueing depth
+ * @q:  the request queue for the device
+ * @new_depth: the new max command queueing depth
+ *
+ *  Notes:
+ *    Must be called with the queue lock held.
+ **/
+int blk_queue_resize_tags(request_queue_t *q, int new_depth)
+{
+	struct blk_queue_tag *bqt = q->queue_tags;
+	struct request **tag_index;
+	unsigned long *tag_map;
+	int bits, max_depth;
+
+	if (!bqt)
+		return -ENXIO;
+
+	/*
+	 * don't bother sizing down
+	 */
+	if (new_depth <= bqt->real_max_depth) {
+		bqt->max_depth = new_depth;
+		return 0;
+	}
+
+	/*
+	 * save the old state info, so we can copy it back
+	 */
+	tag_index = bqt->tag_index;
+	tag_map = bqt->tag_map;
+	max_depth = bqt->real_max_depth;
+
+	if (init_tag_map(bqt, new_depth))
+		return -ENOMEM;
+
+	memcpy(bqt->tag_index, tag_index, max_depth * sizeof(struct request *));
+	bits = max_depth / BLK_TAGS_PER_LONG;
+	memcpy(bqt->tag_map, bqt->tag_map, bits * sizeof(unsigned long));
+
+	kfree(tag_index);
+	kfree(tag_map);
+	return 0;
+}
+
+/**
  * blk_queue_end_tag - end tag operations for a request
  * @q:  the request queue for the device
  * @tag:  the tag that has completed
@@ -524,7 +581,7 @@
 
 	BUG_ON(tag == -1);
 
-	if (unlikely(tag >= bqt->max_depth))
+	if (unlikely(tag >= bqt->real_max_depth))
 		return;
 
 	if (unlikely(!__test_and_clear_bit(tag, bqt->tag_map))) {
diff -Nru a/drivers/char/amiserial.c b/drivers/char/amiserial.c
--- a/drivers/char/amiserial.c	Tue May  6 06:50:50 2003
+++ b/drivers/char/amiserial.c	Mon May 26 15:29:19 2003
@@ -102,13 +102,12 @@
 
 static char *serial_name = "Amiga-builtin serial driver";
 
-static struct tty_driver serial_driver, callout_driver;
+static struct tty_driver serial_driver;
 static int serial_refcount;
 
 /* serial subtype definitions */
 #ifndef SERIAL_TYPE_NORMAL
 #define SERIAL_TYPE_NORMAL	1
-#define SERIAL_TYPE_CALLOUT	2
 #endif
 
 /* number of characters left in xmit buffer before we ask for more */
@@ -448,8 +447,7 @@
 #endif
 		if (!(status & SER_DCD))
 			wake_up_interruptible(&info->open_wait);
-		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-			   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+		else {
 #ifdef SERIAL_DEBUG_OPEN
 			printk("doing serial hangup...");
 #endif
@@ -1567,8 +1565,6 @@
 	 */
 	if (info->flags & ASYNC_NORMAL_ACTIVE)
 		info->state->normal_termios = *tty->termios;
-	if (info->flags & ASYNC_CALLOUT_ACTIVE)
-		info->state->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -1613,8 +1609,7 @@
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	local_irq_restore(flags);
 }
@@ -1698,7 +1693,7 @@
 	shutdown(info);
 	info->event = 0;
 	state->count = 0;
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -1738,43 +1733,17 @@
 	}
 
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-
-	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (state->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
 
 	/*
 	 * Block waiting for the carrier detect and the line to become
@@ -1798,8 +1767,7 @@
 	info->blocked_open++;
 	while (1) {
 		local_irq_save(flags);
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (tty->termios->c_cflag & CBAUD))
+		if (tty->termios->c_cflag & CBAUD)
 		        rtsdtr_ctrl(SER_DTR|SER_RTS);
 		local_irq_restore(flags);
 		set_current_state(TASK_INTERRUPTIBLE);
@@ -1815,8 +1783,7 @@
 #endif
 			break;
 		}
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(info->flags & ASYNC_CLOSING) &&
+		if (!(info->flags & ASYNC_CLOSING) &&
 		    (do_clocal || (!(ciab.pra & SER_DCD)) ))
 			break;
 		if (signal_pending(current)) {
@@ -1957,14 +1924,9 @@
 
 	if ((info->state->count == 1) &&
 	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->state->normal_termios;
-		else 
-			*tty->termios = info->state->callout_termios;
+		*tty->termios = info->state->normal_termios;
 		change_speed(info, 0);
 	}
-	info->session = current->session;
-	info->pgrp = current->pgrp;
 
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_open %s successful...", tty->name);
@@ -2150,21 +2112,8 @@
 	serial_driver.wait_until_sent = rs_wait_until_sent;
 	serial_driver.read_proc = rs_read_proc;
 
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	callout_driver = serial_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(&serial_driver))
 		panic("Couldn't register serial driver\n");
-	if (tty_register_driver(&callout_driver))
-		panic("Couldn't register callout driver\n");
 
 	state = rs_table;
 	state->magic = SSTATE_MAGIC;
@@ -2173,7 +2122,6 @@
 	state->custom_divisor = 0;
 	state->close_delay = 5*HZ/10;
 	state->closing_wait = 30*HZ;
-	state->callout_termios = callout_driver.init_termios;
 	state->normal_termios = serial_driver.init_termios;
 	state->icount.cts = state->icount.dsr = 
 	  state->icount.rng = state->icount.dcd = 0;
@@ -2229,9 +2177,6 @@
 	if ((e1 = tty_unregister_driver(&serial_driver)))
 		printk("SERIAL: failed to unregister serial driver (%d)\n",
 		       e1);
-	if ((e2 = tty_unregister_driver(&callout_driver)))
-		printk("SERIAL: failed to unregister callout driver (%d)\n", 
-		       e2);
 
 	if (info) {
 	  rs_table[0].info = NULL;
diff -Nru a/drivers/char/cyclades.c b/drivers/char/cyclades.c
--- a/drivers/char/cyclades.c	Wed May  7 07:11:08 2003
+++ b/drivers/char/cyclades.c	Mon May 26 15:29:19 2003
@@ -712,7 +712,7 @@
 
 #define	JIFFIES_DIFF(n, j)	((j) - (n))
 
-static struct tty_driver cy_serial_driver, cy_callout_driver;
+static struct tty_driver cy_serial_driver;
 static int serial_refcount;
 
 #ifdef CONFIG_ISA
@@ -968,8 +968,7 @@
     if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
         tty_hangup(info->tty);
         wake_up_interruptible(&info->open_wait);
-        info->flags &= ~(ASYNC_NORMAL_ACTIVE|
-                             ASYNC_CALLOUT_ACTIVE);
+        info->flags &= ~ASYNC_NORMAL_ACTIVE;
     }
     if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
         wake_up_interruptible(&info->open_wait);
@@ -1448,10 +1447,7 @@
                             if(mdm_status & CyDCD){
                                 cy_sched_event(info,
 				    Cy_EVENT_OPEN_WAKEUP);
-                            }else if(!((info->flags
-			                & ASYNC_CALLOUT_ACTIVE)
-				 &&(info->flags
-				    & ASYNC_CALLOUT_NOHUP))){
+                            }else{
                                 cy_sched_event(info,
 				    Cy_EVENT_HANGUP);
                             }
@@ -1823,8 +1819,7 @@
 			  ((u_long)param) : 
 			  cy_readl(&ch_ctrl->rs_status)) & C_RS_DCD) {
 			cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP);
-		    }else if(!((info->flags & ASYNC_CALLOUT_ACTIVE)
-			     &&(info->flags & ASYNC_CALLOUT_NOHUP))){
+		    }else{
 			cy_sched_event(info, Cy_EVENT_HANGUP);
 		    }
 		}
@@ -2376,36 +2371,11 @@
     }
 
     /*
-     * If this is a callout device, then just make sure the normal
-     * device isn't being used.
-     */
-    if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-        if (info->flags & ASYNC_NORMAL_ACTIVE){
-            return -EBUSY;
-        }
-        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-            (info->flags & ASYNC_SESSION_LOCKOUT) &&
-            (info->session != current->session)){
-            return -EBUSY;
-        }
-        if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-            (info->flags & ASYNC_PGRP_LOCKOUT) &&
-            (info->pgrp != current->pgrp)){
-            return -EBUSY;
-        }
-        info->flags |= ASYNC_CALLOUT_ACTIVE;
-        return 0;
-    }
-
-    /*
      * If non-blocking mode is set, then make the check up front
      * and then exit.
      */
     if ((filp->f_flags & O_NONBLOCK) ||
 	(tty->flags & (1 << TTY_IO_ERROR))) {
-        if (info->flags & ASYNC_CALLOUT_ACTIVE){
-            return -EBUSY;
-        }
         info->flags |= ASYNC_NORMAL_ACTIVE;
         return 0;
     }
@@ -2442,8 +2412,7 @@
 
 	while (1) {
 	    CY_LOCK(info, flags);
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (tty->termios->c_cflag & CBAUD)){
+		if ((tty->termios->c_cflag & CBAUD)){
 		    cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
 		    cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
 		    cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
@@ -2466,8 +2435,7 @@
 
 	    CY_LOCK(info, flags);
 		cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
-		&& !(info->flags & ASYNC_CLOSING)
+		if (!(info->flags & ASYNC_CLOSING)
 		&& (C_CLOCAL(tty)
 		    || (cy_readb(base_addr+(CyMSVR1<<index)) & CyDCD))) {
 			CY_UNLOCK(info, flags);
@@ -2507,8 +2475,7 @@
 	ch_ctrl = zfw_ctrl->ch_ctrl;
 
 	while (1) {
-	    if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		(tty->termios->c_cflag & CBAUD)){
+	    if ((tty->termios->c_cflag & CBAUD)){
 		cy_writel(&ch_ctrl[channel].rs_control,
 			cy_readl(&ch_ctrl[channel].rs_control) |
 			(C_RS_RTS | C_RS_DTR));
@@ -2530,8 +2497,7 @@
 		    -EAGAIN : -ERESTARTSYS);
 		break;
 	    }
-	    if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
-	    && !(info->flags & ASYNC_CLOSING)
+	    if (!(info->flags & ASYNC_CLOSING)
 	    && (C_CLOCAL(tty)
 	      || (cy_readl(&ch_ctrl[channel].rs_status) & C_RS_DCD))) {
 		break;
@@ -2680,15 +2646,9 @@
     }
 
     if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
-        if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-            *tty->termios = info->normal_termios;
-        else 
-            *tty->termios = info->callout_termios;
+	*tty->termios = info->normal_termios;
     }
 
-    info->session = current->session;
-    info->pgrp = current->pgrp;
-
 #ifdef CY_DEBUG_OPEN
     printk(" cyc:cy_open done\n");/**/
 #endif
@@ -2839,8 +2799,6 @@
      */
     if (info->flags & ASYNC_NORMAL_ACTIVE)
         info->normal_termios = *tty->termios;
-    if (info->flags & ASYNC_CALLOUT_ACTIVE)
-        info->callout_termios = *tty->termios;
 
     /*
     * Now we wait for the transmit buffer to clear; and we notify
@@ -2917,8 +2875,7 @@
         wake_up_interruptible(&info->open_wait);
 	CY_LOCK(info, flags);
     }
-    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-                     ASYNC_CLOSING);
+    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
     wake_up_interruptible(&info->close_wait);
 
 #ifdef CY_DEBUG_OTHER
@@ -4701,7 +4658,7 @@
     printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid);
 #endif
     info->tty = 0;
-    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+    info->flags &= ~ASYNC_NORMAL_ACTIVE;
     wake_up_interruptible(&info->open_wait);
 } /* cy_hangup */
 
@@ -5523,22 +5480,8 @@
     cy_serial_driver.wait_until_sent = cy_wait_until_sent;
     cy_serial_driver.read_proc = cyclades_get_proc_info;
 
-    /*
-     * The callout device is just like normal device except for
-     * major number and the subtype code.
-     */
-    cy_callout_driver = cy_serial_driver;
-    cy_callout_driver.name = "cub";
-    cy_callout_driver.major = CYCLADESAUX_MAJOR;
-    cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-    cy_callout_driver.read_proc = 0;
-    cy_callout_driver.proc_entry = 0;
-
-
     if (tty_register_driver(&cy_serial_driver))
             panic("Couldn't register Cyclades serial driver\n");
-    if (tty_register_driver(&cy_callout_driver))
-            panic("Couldn't register Cyclades callout driver\n");
 
     for (i = 0; i < NR_CARDS; i++) {
             /* base_addr=0 indicates board not found */
@@ -5629,8 +5572,6 @@
                     info->default_threshold = 0;
                     info->default_timeout = 0;
 		    INIT_WORK(&info->tqueue, do_softint, info);
-                    info->callout_termios =
-		                cy_callout_driver.init_termios;
                     info->normal_termios =
 		                cy_serial_driver.init_termios;
 		    init_waitqueue_head(&info->open_wait);
@@ -5708,8 +5649,6 @@
                     info->default_threshold = 0;
                     info->default_timeout = 0;
 		    INIT_WORK(&info->tqueue, do_softint, info);
-                    info->callout_termios =
-		               cy_callout_driver.init_termios;
                     info->normal_termios =
 		               cy_serial_driver.init_termios;
 		    init_waitqueue_head(&info->open_wait);
@@ -5761,9 +5700,6 @@
     if ((e1 = tty_unregister_driver(&cy_serial_driver)))
             printk("cyc: failed to unregister Cyclades serial driver(%d)\n",
 		e1);
-    if ((e2 = tty_unregister_driver(&cy_callout_driver)))
-            printk("cyc: failed to unregister Cyclades callout driver (%d)\n", 
-		e2);
 
     restore_flags(flags);
 
diff -Nru a/drivers/char/dz.c b/drivers/char/dz.c
--- a/drivers/char/dz.c	Wed May  7 15:51:55 2003
+++ b/drivers/char/dz.c	Mon May 26 15:29:19 2003
@@ -1095,8 +1095,6 @@
 	 */
 	if (info->flags & DZ_NORMAL_ACTIVE)
 		info->normal_termios = *tty->termios;
-	if (info->flags & DZ_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify the line
 	 * discipline to only process XON/XOFF characters.
@@ -1136,7 +1134,7 @@
 		wake_up_interruptible(&info->open_wait);
 	}
 
-	info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE | DZ_CLOSING);
+	info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 
 	restore_flags(flags);
@@ -1153,7 +1151,7 @@
 	shutdown(info);
 	info->event = 0;
 	info->count = 0;
-	info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE);
+	info->flags &= ~DZ_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -1180,47 +1178,18 @@
 	}
 
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & DZ_NORMAL_ACTIVE)
-			return -EBUSY;
-    
-		if ((info->flags & DZ_CALLOUT_ACTIVE) &&
-		    (info->flags & DZ_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-			return -EBUSY;
-    
-		if ((info->flags & DZ_CALLOUT_ACTIVE) &&
-		    (info->flags & DZ_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-			return -EBUSY;
-
-		info->flags |= DZ_CALLOUT_ACTIVE;
-		return 0;
-	}
-
-	/*
 	 * If non-blocking mode is set, or the port is not enabled, then make
 	 * the check up front and then exit.
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & DZ_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= DZ_NORMAL_ACTIVE;
 
 		return 0;
 	}
 
-	if (info->flags & DZ_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
+	if (tty->termios->c_cflag & CLOCAL)
 		do_clocal = 1;
-	}
 
 	/*
 	 * Block waiting for the carrier detect and the line to become free
@@ -1239,8 +1208,7 @@
 			retval = -EAGAIN;
 			break;
 		}
-		if (!(info->flags & DZ_CALLOUT_ACTIVE) &&
-		    !(info->flags & DZ_CLOSING) && do_clocal)
+		if (!(info->flags & DZ_CLOSING) && do_clocal)
 			break;
 		if (signal_pending(current)) {
 			retval = -ERESTARTSYS;
@@ -1301,16 +1269,10 @@
 		return retval;
 
 	if ((info->count == 1) && (info->flags & DZ_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->normal_termios;
-		else 
-			*tty->termios = info->callout_termios;
+		*tty->termios = info->normal_termios;
 		change_speed(info);
 	}
 
-	info->session = current->session;
-	info->pgrp = current->pgrp;
-
 	return 0;
 }
 
@@ -1369,23 +1331,8 @@
 	serial_driver.start = dz_start;
 	serial_driver.hangup = dz_hangup;
 
-	/*
-	 * The callout device is just like normal device except for major
-	 * number and the subtype code.
-	 */
-	callout_driver = serial_driver;
-#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
-	callout_driver.name = "cua";
-#else
-	callout_driver.name = "cua/";
-#endif
-	callout_driver.major = TTYAUX_MAJOR;
-	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-
 	if (tty_register_driver (&serial_driver))
 		panic("Couldn't register serial driver\n");
-	if (tty_register_driver (&callout_driver))
-		panic("Couldn't register callout driver\n");
 
 	save_flags(flags); cli();
 	for (i=0; i < DZ_NB_PORT;  i++) {
@@ -1411,7 +1358,6 @@
 		info->tqueue.data = info;
 		info->tqueue_hangup.routine = do_serial_hangup;
 		info->tqueue_hangup.data = info;
-		info->callout_termios = callout_driver.init_termios;
 		info->normal_termios = serial_driver.init_termios;
 		init_waitqueue_head(&info->open_wait); 
 		init_waitqueue_head(&info->close_wait); 
@@ -1427,7 +1373,6 @@
 		       info->port, SERIAL);
 
 		tty_register_device(&serial_driver, info->line, NULL);
-		tty_register_device(&callout_driver, info->line, NULL);
 	}
 
 	/* Reset the chip */
diff -Nru a/drivers/char/dz.h b/drivers/char/dz.h
--- a/drivers/char/dz.h	Tue Feb  5 09:40:06 2002
+++ b/drivers/char/dz.h	Mon May 26 15:29:25 2003
@@ -157,12 +157,8 @@
   struct tq_struct        tqueue;              /* Queue for BH */
   struct tq_struct        tqueue_hangup;
   struct termios          normal_termios;
-  struct termios          callout_termios;
   wait_queue_head_t       open_wait;
   wait_queue_head_t       close_wait;
-
-  long                    session;             /* Session of opening process */
-  long                    pgrp;                /* pgrp of opening process */
 
   unsigned char           is_console;          /* flag indicating a serial console */
   unsigned char           is_initialized;
diff -Nru a/drivers/char/epca.c b/drivers/char/epca.c
--- a/drivers/char/epca.c	Mon Apr 21 20:58:41 2003
+++ b/drivers/char/epca.c	Mon May 26 15:29:18 2003
@@ -98,7 +98,6 @@
 /* ------------- Begin structures used for driver registeration ---------- */
 
 struct tty_driver pc_driver;
-struct tty_driver pc_callout;
 struct tty_driver pc_info;
 
 /* The below structures are used to initialize the tty_driver structures. */
@@ -562,9 +561,6 @@
 		if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
 			ch->normal_termios = *tty->termios;
 
-		if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
-			ch->callout_termios = *tty->termios;
-
 		tty->closing = 1;
 
 		if (ch->asyncflags & ASYNC_INITIALIZED) 
@@ -599,7 +595,7 @@
 		} /* End if blocked_open */
 
 		ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | 
-		                      ASYNC_CALLOUT_ACTIVE | ASYNC_CLOSING);
+		                      ASYNC_CLOSING);
 		wake_up_interruptible(&ch->close_wait);
 
 
@@ -693,7 +689,7 @@
 		ch->event = 0;
 		ch->count = 0;
 		restore_flags(flags);
-		ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | ASYNC_CALLOUT_ACTIVE);
+		ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
 		wake_up_interruptible(&ch->open_wait);
 
 	} /* End if ch != NULL */
@@ -1233,31 +1229,6 @@
 			return -ERESTARTSYS;
 	}
 
-	/* ----------------------------------------------------------------- 
-	   If this is a callout device, then just make sure the normal
-	   device isn't being used.
-	-------------------------------------------------------------------- */
-
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) 
-	{ /* A cud device has been opened */
-		if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-
-		if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
-		    (ch->asyncflags & ASYNC_SESSION_LOCKOUT) &&
-		    (ch->session != current->session))
-		    return -EBUSY;
-
-		if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
-		    (ch->asyncflags & ASYNC_PGRP_LOCKOUT) &&
-		    (ch->pgrp != current->pgrp))
-		    return -EBUSY;
- 
-		ch->asyncflags |= ASYNC_CALLOUT_ACTIVE;
-
-		return 0;
-	} /* End a cud device has been opened */
-
 	if (filp->f_flags & O_NONBLOCK) 
 	{
 		/* ----------------------------------------------------------------- 
@@ -1265,25 +1236,14 @@
 	  	 and then exit.
 		-------------------------------------------------------------------- */
 
-		if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
-
 		ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
 
 		return 0;
 	}
 
 
-	if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) 
-	{
-		if (ch->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	else 
-	{
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
 	
    /* Block waiting for the carrier detect and the line to become free */
 	
@@ -1317,7 +1277,6 @@
 		}
 
 		if (!(ch->asyncflags & ASYNC_CLOSING) && 
-		    !(ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
 			  (do_clocal || (ch->imodem & ch->dcd)))
 			break;
 
@@ -1453,15 +1412,9 @@
 	/* Should this be here except for SPLIT termios ? */
 	if (ch->count == 1) 
 	{
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = ch->normal_termios;
-		else 
-			*tty->termios = ch->callout_termios;
+		*tty->termios = ch->normal_termios;
 	}
 
-	ch->session = current->session;
-	ch->pgrp = current->pgrp;
-
 	save_flags(flags);
 	cli();
 
@@ -1558,7 +1511,6 @@
 	cli();
 
 	if ((tty_unregister_driver(&pc_driver)) ||  
-	    (tty_unregister_driver(&pc_callout)) ||
 	    (tty_unregister_driver(&pc_info)))
 	{
 		printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n");
@@ -1701,7 +1653,6 @@
 #endif /* ENABLE_PCI */
 
 	memset(&pc_driver, 0, sizeof(struct tty_driver));
-	memset(&pc_callout, 0, sizeof(struct tty_driver));
 	memset(&pc_info, 0, sizeof(struct tty_driver));
 
 	pc_driver.magic = TTY_DRIVER_MAGIC;
@@ -1747,13 +1698,6 @@
 	pc_driver.throttle = pc_throttle;
 	pc_driver.unthrottle = pc_unthrottle;
 	pc_driver.hangup = pc_hangup;
-	pc_callout = pc_driver;
-
-	pc_callout.name = "cud";
-	pc_callout.major = DIGICU_MAJOR;
-	pc_callout.minor_start = 0;
-	pc_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
-	pc_callout.subtype = SERIAL_TYPE_CALLOUT;
 
 	pc_info = pc_driver;
 	pc_info.name = "digi_ctl";
@@ -1889,9 +1833,6 @@
 	if (tty_register_driver(&pc_driver))
 		panic("Couldn't register Digi PC/ driver");
 
-	if (tty_register_driver(&pc_callout))
-		panic("Couldn't register Digi PC/ callout");
-
 	if (tty_register_driver(&pc_info))
 		panic("Couldn't register Digi PC/ info ");
 
@@ -2165,7 +2106,6 @@
 		ch->close_delay = 50;
 		ch->count = 0;
 		ch->blocked_open = 0;
-		ch->callout_termios = pc_callout.init_termios;
 		ch->normal_termios = pc_driver.init_termios;
 		init_waitqueue_head(&ch->open_wait);
 		init_waitqueue_head(&ch->close_wait);
@@ -2712,7 +2652,7 @@
 			the driver will wait on carrier detect.
 		------------------------------------------------------------------- */
 
-		if ((ts->c_cflag & CLOCAL) || (tty->driver->subtype == SERIAL_TYPE_CALLOUT))
+		if (ts->c_cflag & CLOCAL)
 		{ /* Begin it is a cud device or a ttyD device with CLOCAL on */
 			ch->asyncflags &= ~ASYNC_CHECK_CD;
 		} /* End it is a cud device or a ttyD device with CLOCAL on */
@@ -3406,7 +3346,7 @@
 
 				tty_hangup(tty);	/* FIXME: module removal race here - AKPM */
 				wake_up_interruptible(&ch->open_wait);
-				ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+				ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
 
 			} /* End if clear_bit */
 		}
diff -Nru a/drivers/char/epca.h b/drivers/char/epca.h
--- a/drivers/char/epca.h	Tue Oct  1 08:49:32 2002
+++ b/drivers/char/epca.h	Mon May 26 15:29:18 2003
@@ -78,7 +78,6 @@
 
 #define FEPTIMEOUT 200000  
 #define SERIAL_TYPE_NORMAL  1
-#define SERIAL_TYPE_CALLOUT 2
 #define SERIAL_TYPE_INFO    3
 #define EPCA_EVENT_HANGUP   1
 #define EPCA_MAGIC          0x5c6df104L
@@ -124,8 +123,6 @@
 	ulong  event;
 	int    asyncflags;
 	uint   dev;
-	long   session;
-	long   pgrp;
 	ulong  statusflags;
 	ulong  c_iflag;
 	ulong  c_cflag;
@@ -139,7 +136,6 @@
 	struct digi_struct          digiext;
 	struct tty_struct           *tty;
 	struct termios              normal_termios;
-	struct termios              callout_termios;
 	wait_queue_head_t           open_wait;
 	wait_queue_head_t           close_wait;
 	struct work_struct            tqueue;
diff -Nru a/drivers/char/esp.c b/drivers/char/esp.c
--- a/drivers/char/esp.c	Wed May  7 07:24:33 2003
+++ b/drivers/char/esp.c	Mon May 26 15:29:18 2003
@@ -109,12 +109,11 @@
 
 static DECLARE_TASK_QUEUE(tq_esp);
 
-static struct tty_driver esp_driver, esp_callout_driver;
+static struct tty_driver esp_driver;
 static int serial_refcount;
 
 /* serial subtype definitions */
 #define SERIAL_TYPE_NORMAL	1
-#define SERIAL_TYPE_CALLOUT	2
 
 /*
  * Serial driver configuration section.  Here are the various options:
@@ -638,8 +637,7 @@
 #endif		
 		if (status & UART_MSR_DCD)
 			wake_up_interruptible(&info->open_wait);
-		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-			   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+		else {
 #ifdef SERIAL_DEBUG_OPEN
 			printk("scheduling hangup...");
 #endif
@@ -2077,8 +2075,6 @@
 	 */
 	if (info->flags & ASYNC_NORMAL_ACTIVE)
 		info->normal_termios = *tty->termios;
-	if (info->flags & ASYNC_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -2126,8 +2122,7 @@
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 out:
 	restore_flags(flags);
@@ -2185,7 +2180,7 @@
 	shutdown(info);
 	info->event = 0;
 	info->count = 0;
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -2222,44 +2217,18 @@
 	}
 
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-	
-	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -2282,8 +2251,7 @@
 	while (1) {
 		save_flags(flags);
 		cli();
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-			(tty->termios->c_cflag & CBAUD)) {
+		if ((tty->termios->c_cflag & CBAUD)) {
 			unsigned int scratch;
 
 			serial_out(info, UART_ESI_CMD1, ESI_READ_UART);
@@ -2313,8 +2281,7 @@
 		if (serial_in(info, UART_ESI_STAT2) & UART_MSR_DCD)
 			do_clocal = 1;
 
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(info->flags & ASYNC_CLOSING) &&
+		if (!(info->flags & ASYNC_CLOSING) &&
 		    (do_clocal))
 			break;
 		if (signal_pending(current)) {
@@ -2399,16 +2366,10 @@
 	}
 
 	if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->normal_termios;
-		else 
-			*tty->termios = info->callout_termios;
+		*tty->termios = info->normal_termios;
 		change_speed(info);
 	}
 
-	info->session = current->session;
-	info->pgrp = current->pgrp;
-
 #ifdef SERIAL_DEBUG_OPEN
 	printk("esp_open %s successful...", tty->name);
 #endif
@@ -2581,35 +2542,18 @@
 	esp_driver.break_ctl = esp_break;
 	esp_driver.wait_until_sent = rs_wait_until_sent;
 
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	esp_callout_driver = esp_driver;
-	esp_callout_driver.name = "cup";
-	esp_callout_driver.major = ESP_OUT_MAJOR;
-	esp_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-
 	if (tty_register_driver(&esp_driver))
 	{
 		printk(KERN_ERR "Couldn't register esp serial driver");
 		return 1;
 	}
 
-	if (tty_register_driver(&esp_callout_driver))
-	{
-		printk(KERN_ERR "Couldn't register esp callout driver");
-		tty_unregister_driver(&esp_driver);
-		return 1;
-	}
-	
 	info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL);
 
 	if (!info)
 	{
 		printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n");
 		tty_unregister_driver(&esp_driver);
-		tty_unregister_driver(&esp_callout_driver);
 		return 1;
 	}
 
@@ -2643,7 +2587,6 @@
 		info->tqueue.data = info;
 		info->tqueue_hangup.routine = do_serial_hangup;
 		info->tqueue_hangup.data = info;
-		info->callout_termios = esp_callout_driver.init_termios;
 		info->normal_termios = esp_driver.init_termios;
 		info->config.rx_timeout = rx_timeout;
 		info->config.flow_on = flow_on;
@@ -2717,9 +2660,6 @@
 	if ((e1 = tty_unregister_driver(&esp_driver)))
 		printk("SERIAL: failed to unregister serial driver (%d)\n",
 		       e1);
-	if ((e2 = tty_unregister_driver(&esp_callout_driver)))
-		printk("SERIAL: failed to unregister callout driver (%d)\n", 
-		       e2);
 	restore_flags(flags);
 
 	while (ports) {
diff -Nru a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
--- a/drivers/char/generic_serial.c	Mon Apr 21 20:58:42 2003
+++ b/drivers/char/generic_serial.c	Mon May 26 15:29:12 2003
@@ -554,7 +554,7 @@
 		return;
 
 	gs_shutdown_port (port);
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE |GS_ACTIVE);
+	port->flags &= ~(ASYNC_NORMAL_ACTIVE|GS_ACTIVE);
 	port->tty = NULL;
 	port->count = 0;
 
@@ -619,47 +619,19 @@
 	gs_dprintk (GS_DEBUG_BTR, "after hung up\n"); 
 
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == GS_TYPE_CALLOUT) {
-		if (port->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (port->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (port->session != current->session))
-			return -EBUSY;
-		if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (port->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (port->pgrp != current->pgrp))
-			return -EBUSY;
-		port->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-
-	gs_dprintk (GS_DEBUG_BTR, "after subtype\n");
-
-	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (port->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		port->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
 	gs_dprintk (GS_DEBUG_BTR, "after nonblock\n"); 
  
-	if (port->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (port->normal_termios.c_cflag & CLOCAL) 
-			do_clocal = 1;
-	} else {
-		if (C_CLOCAL(tty))
-			do_clocal = 1;
-	}
+	if (C_CLOCAL(tty))
+		do_clocal = 1;
 
 	/*
 	 * Block waiting for the carrier detect and the line to become
@@ -690,8 +662,7 @@
 				retval = -ERESTARTSYS;
 			break;
 		}
-		if (!(port->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(port->flags & ASYNC_CLOSING) &&
+		if (!(port->flags & ASYNC_CLOSING) &&
 		    (do_clocal || CD))
 			break;
 		gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n", 
@@ -769,8 +740,6 @@
 	 */
 	if (port->flags & ASYNC_NORMAL_ACTIVE)
 		port->normal_termios = *tty->termios;
-	if (port->flags & ASYNC_CALLOUT_ACTIVE)
-		port->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -812,8 +781,7 @@
 		}
 		wake_up_interruptible(&port->open_wait);
 	}
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-	                 ASYNC_CLOSING | ASYNC_INITIALIZED);
+	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED);
 	wake_up_interruptible(&port->close_wait);
 
 	restore_flags(flags);
diff -Nru a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
--- a/drivers/char/ip2/i2lib.c	Sun Oct 27 08:53:03 2002
+++ b/drivers/char/ip2/i2lib.c	Mon May 26 15:29:26 2003
@@ -326,8 +326,6 @@
 		pCh->speed       = CBR_9600;
 
 		pCh->flags    = 0;
-		pCh->session  = 0;
-		pCh->pgrp     = 0;
 
 		pCh->ClosingDelay     = 5*HZ/10;
 		pCh->ClosingWaitTime  = 30*HZ;
diff -Nru a/drivers/char/ip2/i2lib.h b/drivers/char/ip2/i2lib.h
--- a/drivers/char/ip2/i2lib.h	Tue Oct  1 08:35:18 2002
+++ b/drivers/char/ip2/i2lib.h	Mon May 26 15:29:18 2003
@@ -92,8 +92,6 @@
 	int      throttled;		// Set if upper layer can take no data
 
 	int      flags;         // Defined in tty.h
-	int      session;       // Defined in tty.h
-	int      pgrp;          // Defined in tty.h
 
 	PWAITQ   open_wait;     // Pointer for OS sleep function.
 	PWAITQ   close_wait;    // Pointer for OS sleep function.
@@ -104,7 +102,6 @@
 	wait_queue_head_t pBookmarkWait;   // Used by i2DrainOutput
 
 	struct termios NormalTermios;
-	struct termios CalloutTermios;
 
 	int      BaudBase;
 	int      BaudDivisor;
diff -Nru a/drivers/char/ip2main.c b/drivers/char/ip2main.c
--- a/drivers/char/ip2main.c	Wed May  7 23:16:25 2003
+++ b/drivers/char/ip2main.c	Mon May 26 15:29:18 2003
@@ -194,7 +194,6 @@
 #define ioremap(a,b) vremap((a),(b))
 #define iounmap(a) vfree((a))
 #define SERIAL_TYPE_NORMAL	1
-#define SERIAL_TYPE_CALLOUT	2
 #define schedule_timeout(a){current->timeout = jiffies + (a); schedule();}
 #define signal_pending(a) ((a)->signal & ~(a)->blocked)
 #define in_interrupt()	intr_count
@@ -232,16 +231,13 @@
 static char *pcDriver_name   = "ip2";
 #ifdef	CONFIG_DEVFS_FS
 static char *pcTty    		 = "tts/F%d";
-static char *pcCallout		 = "cua/F%d";
 #else
 static char *pcTty    		 = "ttyF";
-static char *pcCallout		 = "cuf";
 #endif
 static char *pcIpl    		 = "ip2ipl";
 
 /* Serial subtype definitions */
 #define SERIAL_TYPE_NORMAL    1
-#define SERIAL_TYPE_CALLOUT   2
 
 // cheezy kludge or genius - you decide?
 int ip2_loadmain(int *, int *, unsigned char *, int);
@@ -307,7 +303,6 @@
 /***************/
 
 static struct tty_driver ip2_tty_driver;
-static struct tty_driver ip2_callout_driver;
 
 static int ref_count;
 
@@ -523,9 +518,6 @@
 	if ( ( err = tty_unregister_driver ( &ip2_tty_driver ) ) ) {
 		printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
 	}
-	if ( ( err = tty_unregister_driver ( &ip2_callout_driver ) ) ) {
-		printk(KERN_ERR "IP2: failed to unregister callout driver (%d)\n", err);
-	}
 	if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) {
 		printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err);
 	}
@@ -834,27 +826,12 @@
 	ip2_tty_driver.start           = ip2_start;
 	ip2_tty_driver.hangup          = ip2_hangup;
 
-	/* Initialise the callout driver structure from the tty driver, and
-	 * make the needed adjustments.
-	 */
-	ip2_callout_driver         = ip2_tty_driver;
-	ip2_callout_driver.name    = pcCallout;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
-	ip2_callout_driver.driver_name = pcDriver_name;
-	ip2_callout_driver.read_proc  = NULL;
-#endif
-	ip2_callout_driver.major   = IP2_CALLOUT_MAJOR;
-	ip2_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-
 	ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 );
 
 	/* Register the tty devices. */
 	if ( ( err = tty_register_driver ( &ip2_tty_driver ) ) ) {
 		printk(KERN_ERR "IP2: failed to register tty driver (%d)\n", err);
 	} else
-	if ( ( err = tty_register_driver ( &ip2_callout_driver ) ) ) {
-		printk(KERN_ERR "IP2: failed to register callout driver (%d)\n", err);
-	} else
 	/* Register the IPL driver. */
 	if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) {
 		printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err );
@@ -893,9 +870,6 @@
 				        tty_register_device(&ip2_tty_driver,
 					    j + ABS_BIGGEST_BOX *
 						    (box+i*ABS_MAX_BOXES), NULL);
-				            tty_register_device(&ip2_callout_driver,
-					    j + ABS_BIGGEST_BOX *
-						    (box+i*ABS_MAX_BOXES), NULL);
 			    	    }
 			        }
 			    }
@@ -1497,7 +1471,7 @@
 				if ( pCh->wopen ) {
 					wake_up_interruptible ( &pCh->open_wait );
 				}
-			} else if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE) ) {
+			} else {
 				if (pCh->pTTY &&  (!(pCh->pTTY->termios->c_cflag & CLOCAL)) ) {
 					tty_hangup( pCh->pTTY );
 				}
@@ -1603,35 +1577,9 @@
 	remove_wait_queue(&pCh->close_wait, &wait);
 
 	/*
-	 * 2. If this is a callout device, make sure the normal port is not in
-	 *    use, and that someone else doesn't have the callout device locked.
-	 *    (These are the only tests the standard serial driver makes for
-	 *    callout devices.)
-	 */
-	if ( tty->driver->subtype == SERIAL_TYPE_CALLOUT ) {
-		if ( pCh->flags & ASYNC_NORMAL_ACTIVE ) {
-			return -EBUSY;
-		}
-		if ( ( pCh->flags & ASYNC_CALLOUT_ACTIVE )  &&
-		    ( pCh->flags & ASYNC_SESSION_LOCKOUT ) &&
-		    ( pCh->session != current->session ) ) {
-			return -EBUSY;
-		}
-		if ( ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) &&
-		    ( pCh->flags & ASYNC_PGRP_LOCKOUT )   &&
-		    ( pCh->pgrp != current->pgrp ) ) {
-			return -EBUSY;
-		}
-		pCh->flags |= ASYNC_CALLOUT_ACTIVE;
-		goto noblock;
-	}
-	/*
 	 * 3. Handle a non-blocking open of a normal port.
 	 */
 	if ( (pFile->f_flags & O_NONBLOCK) || (tty->flags & (1<<TTY_IO_ERROR) )) {
-		if ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) {
-			return -EBUSY;
-		}
 		pCh->flags |= ASYNC_NORMAL_ACTIVE;
 		goto noblock;
 	}
@@ -1639,15 +1587,8 @@
 	 * 4. Now loop waiting for the port to be free and carrier present
 	 *    (if required).
 	 */
-	if ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) {
-		if ( pCh->NormalTermios.c_cflag & CLOCAL ) {
-			do_clocal = 1;
-		}
-	} else {
-		if ( tty->termios->c_cflag & CLOCAL ) {
-			do_clocal = 1;
-		}
-	}
+	if ( tty->termios->c_cflag & CLOCAL )
+		do_clocal = 1;
 
 #ifdef IP2DEBUG_OPEN
 	printk(KERN_DEBUG "OpenBlock: do_clocal = %d\n", do_clocal);
@@ -1659,32 +1600,27 @@
 	add_wait_queue(&pCh->open_wait, &wait);
 
 	for(;;) {
-		if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE)) {
-			i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
-			pCh->dataSetOut |= (I2_DTR | I2_RTS);
-			set_current_state( TASK_INTERRUPTIBLE );
-			serviceOutgoingFifo( pCh->pMyBord );
-		}
+		i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP);
+		pCh->dataSetOut |= (I2_DTR | I2_RTS);
+		set_current_state( TASK_INTERRUPTIBLE );
+		serviceOutgoingFifo( pCh->pMyBord );
 		if ( tty_hung_up_p(pFile) ) {
 			set_current_state( TASK_RUNNING );
 			remove_wait_queue(&pCh->open_wait, &wait);
 			return ( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EBUSY : -ERESTARTSYS;
 		}
-		if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE) &&
-				!(pCh->flags & ASYNC_CLOSING) && 
+		if (!(pCh->flags & ASYNC_CLOSING) && 
 				(do_clocal || (pCh->dataSetIn & I2_DCD) )) {
 			rc = 0;
 			break;
 		}
 
 #ifdef IP2DEBUG_OPEN
-		printk(KERN_DEBUG "ASYNC_CALLOUT_ACTIVE = %s\n",
-			(pCh->flags & ASYNC_CALLOUT_ACTIVE)?"True":"False");
 		printk(KERN_DEBUG "ASYNC_CLOSING = %s\n",
 			(pCh->flags & ASYNC_CLOSING)?"True":"False");
 		printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n");
 #endif
-		ip2trace (CHANN, ITRC_OPEN, 3, 2, (pCh->flags & ASYNC_CALLOUT_ACTIVE),
+		ip2trace (CHANN, ITRC_OPEN, 3, 2, 0,
 				(pCh->flags & ASYNC_CLOSING) );
 		/* check for signal */
 		if (signal_pending(current)) {
@@ -1711,20 +1647,12 @@
 	if ( tty->count == 1 ) {
 		i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB);
 		if ( pCh->flags & ASYNC_SPLIT_TERMIOS ) {
-			if ( tty->driver->subtype == SERIAL_TYPE_NORMAL ) {
-				*tty->termios = pCh->NormalTermios;
-			} else {
-				*tty->termios = pCh->CalloutTermios;
-			}
+			*tty->termios = pCh->NormalTermios;
 		}
 		/* Now we must send the termios settings to the loadware */
 		set_params( pCh, NULL );
 	}
 
-	/* override previous and never reset ??? */
-	pCh->session = current->session;
-	pCh->pgrp = current->pgrp;
-
 	/*
 	 * Now set any i2lib options. These may go away if the i2lib code ends
 	 * up rolled into the mainline.
@@ -1786,8 +1714,6 @@
 	 */
 	if (pCh->flags & ASYNC_NORMAL_ACTIVE)
 		pCh->NormalTermios = *tty->termios;
-	if (pCh->flags & ASYNC_CALLOUT_ACTIVE)
-		pCh->CalloutTermios = *tty->termios;
 
 	tty->closing = 1;
 
@@ -1833,7 +1759,7 @@
 		wake_up_interruptible(&pCh->open_wait);
 	}
 
-	pCh->flags &=~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);
+	pCh->flags &=~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&pCh->close_wait);
 
 #ifdef IP2DEBUG_OPEN
@@ -1883,7 +1809,7 @@
 
 	wake_up_interruptible ( &pCh->delta_msr_wait );
 
-	pCh->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	pCh->flags &= ~ASYNC_NORMAL_ACTIVE;
 	pCh->pTTY = NULL;
 	wake_up_interruptible ( &pCh->open_wait );
 
diff -Nru a/drivers/char/isicom.c b/drivers/char/isicom.c
--- a/drivers/char/isicom.c	Wed May  7 07:24:28 2003
+++ b/drivers/char/isicom.c	Mon May 26 15:29:13 2003
@@ -76,7 +76,7 @@
 static int isicom_refcount;
 static int prev_card = 3;	/*	start servicing isi_card[0]	*/
 static struct isi_board * irq_to_board[16];
-static struct tty_driver isicom_normal, isicom_callout;
+static struct tty_driver isicom_normal;
 static struct tty_struct * isicom_table[PORT_COUNT];
 static struct termios * isicom_termios[PORT_COUNT];
 static struct termios * isicom_termios_locked[PORT_COUNT];
@@ -588,10 +588,7 @@
 							printk(KERN_DEBUG "ISICOM: interrupt: DCD->low.\n");
 #endif							
 							port->status &= ~ISI_DCD;
-							if (!((port->flags & ASYNC_CALLOUT_ACTIVE) &&
-								(port->flags & ASYNC_CALLOUT_NOHUP))) {
-								schedule_task(&port->hangup_tq);
-							}
+							schedule_task(&port->hangup_tq);
 						}
 					}
 					else {
@@ -903,49 +900,18 @@
 			return -ERESTARTSYS;
 	}
 	
-	/* trying to open a callout device... check for constraints */
-	
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-#ifdef ISICOM_DEBUG
-		printk(KERN_DEBUG "ISICOM: bl_ti_rdy: callout open.\n");	
-#endif		
-		if (port->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (port->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (port->session != current->session))
-			return -EBUSY;
-			
-		if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (port->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (port->pgrp != current->pgrp))
-			return -EBUSY;
-		port->flags |= ASYNC_CALLOUT_ACTIVE;
-		cli();
-		raise_dtr_rts(port);
-		sti();
-		return 0;
-	}
-	
 	/* if non-blocking mode is set ... */
 	
 	if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
 #ifdef ISICOM_DEBUG	
 		printk(KERN_DEBUG "ISICOM: block_til_ready: non-block mode.\n");
 #endif		
-		if (port->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		port->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;	
 	}	
 	
-	if (port->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (port->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1; 
-	} else {
-		if (C_CLOCAL(tty))
-			do_clocal = 1;
-	}
+	if (C_CLOCAL(tty))
+		do_clocal = 1;
 #ifdef ISICOM_DEBUG	
 	if (do_clocal)
 		printk(KERN_DEBUG "ISICOM: block_til_ready: CLOCAL set.\n");
@@ -965,9 +931,7 @@
 #endif	
 	while (1) {
 		cli();
-		if (!(port->flags & ASYNC_CALLOUT_ACTIVE)) 
-			raise_dtr_rts(port);
-		
+		raise_dtr_rts(port);
 		sti();
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { 	
@@ -980,8 +944,7 @@
 #endif			
 			break;
 		}	
-		if (!(port->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(port->flags & ASYNC_CLOSING) &&
+		if (!(port->flags & ASYNC_CLOSING) &&
 		    (do_clocal || (port->status & ISI_DCD))) {
 #ifdef ISICOM_DEBUG		    
 		 	printk(KERN_DEBUG "ISICOM: block_til_ready: do_clocal || DCD.\n");   
@@ -1070,17 +1033,12 @@
 		return error;
 		
 	if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = port->normal_termios;
-		else 
-			*tty->termios = port->callout_termios;
+		*tty->termios = port->normal_termios;
 		save_flags(flags); cli();
 		isicom_config_port(port);
 		restore_flags(flags);		
 	}	
 	
-	port->session = current->session;	
-	port->pgrp = current->pgrp;
 #ifdef ISICOM_DEBUG	
 	printk(KERN_DEBUG "ISICOM: open end!!!.\n");
 #endif	
@@ -1180,8 +1138,6 @@
 	 */	
 	if (port->flags & ASYNC_NORMAL_ACTIVE)
 		port->normal_termios = *tty->termios;
-	if (port->flags & ASYNC_CALLOUT_ACTIVE)
-		port->callout_termios = *tty->termios;
 	
 	tty->closing = 1;
 	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
@@ -1209,8 +1165,7 @@
 		}
 		wake_up_interruptible(&port->open_wait);
 	}	
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | 
-			ASYNC_CLOSING);
+	port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
 	wake_up_interruptible(&port->close_wait);
 	restore_flags(flags);
 #ifdef ISICOM_DEBUG	
@@ -1651,7 +1606,7 @@
 	
 	isicom_shutdown_port(port);
 	port->count = 0;
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+	port->flags &= ~ASYNC_NORMAL_ACTIVE;
 	port->tty = 0;
 	wake_up_interruptible(&port->open_wait);
 }
@@ -1743,32 +1698,17 @@
 	isicom_normal.hangup	= isicom_hangup;
 	isicom_normal.flush_buffer	= isicom_flush_buffer;
 	
-	/*	callout device	*/
-	
-	isicom_callout	= isicom_normal;
-	isicom_callout.name	= "cum"; 
-	isicom_callout.major	= ISICOM_CMAJOR;
-	isicom_callout.subtype	= SERIAL_TYPE_CALLOUT;
-	
 	if ((error=tty_register_driver(&isicom_normal))!=0) {
 		printk(KERN_DEBUG "ISICOM: Couldn't register the dialin driver, error=%d\n",
 			error);
 		return error;
 	}
-	if ((error=tty_register_driver(&isicom_callout))!=0) {
-		tty_unregister_driver(&isicom_normal);
-		printk(KERN_DEBUG "ISICOM: Couldn't register the callout driver, error=%d\n",
-			error);
-		return error;	
-	}
 	return 0;
 }
 
 static void unregister_drivers(void)
 {
 	int error;
-	if ((error=tty_unregister_driver(&isicom_callout))!=0)
-		printk(KERN_DEBUG "ISICOM: couldn't unregister callout driver error=%d.\n",error);
 	if (tty_unregister_driver(&isicom_normal))
 		printk(KERN_DEBUG "ISICOM: couldn't unregister normal driver error=%d.\n",error);
 }
@@ -1897,7 +1837,6 @@
 			port->card = &isi_card[card];
 			port->channel = channel;		
 			port->normal_termios = isicom_normal.init_termios;
-			port->callout_termios = isicom_callout.init_termios;
 		 	port->close_delay = 50 * HZ/100;
 		 	port->closing_wait = 3000 * HZ/100;
 			port->hangup_tq.routine = do_isicom_hangup;
diff -Nru a/drivers/char/istallion.c b/drivers/char/istallion.c
--- a/drivers/char/istallion.c	Wed May  7 23:16:25 2003
+++ b/drivers/char/istallion.c	Mon May 26 15:29:26 2003
@@ -159,9 +159,6 @@
 #define	STL_CALLOUTMAJOR	25
 #endif
 
-#define	STL_DRVTYPSERIAL	1
-#define	STL_DRVTYPCALLOUT	2
-
 /*****************************************************************************/
 
 /*
@@ -172,10 +169,8 @@
 static char	*stli_drvname = "istallion";
 static char	*stli_drvversion = "5.6.0";
 static char	*stli_serialname = "ttyE";
-static char	*stli_calloutname = "cue";
 
 static struct tty_driver	stli_serial;
-static struct tty_driver	stli_callout;
 static struct tty_struct	*stli_ttys[STL_MAXDEVS];
 static struct termios		*stli_termios[STL_MAXDEVS];
 static struct termios		*stli_termioslocked[STL_MAXDEVS];
@@ -857,10 +852,9 @@
 	}
 
 	i = tty_unregister_driver(&stli_serial);
-	j = tty_unregister_driver(&stli_callout);
-	if (i || j) {
+	if (i) {
 		printk("STALLION: failed to un-register tty driver, "
-			"errno=%d,%d\n", -i, -j);
+			"errno=%d,%d\n", -i);
 		restore_flags(flags);
 		return;
 	}
@@ -1114,39 +1108,16 @@
  *	previous opens still in effect. If we are a normal serial device
  *	then also we might have to wait for carrier.
  */
-	if (tty->driver->subtype == STL_DRVTYPCALLOUT) {
-		if (portp->flags & ASYNC_NORMAL_ACTIVE)
-			return(-EBUSY);
-		if (portp->flags & ASYNC_CALLOUT_ACTIVE) {
-			if ((portp->flags & ASYNC_SESSION_LOCKOUT) &&
-			    (portp->session != current->session))
-				return(-EBUSY);
-			if ((portp->flags & ASYNC_PGRP_LOCKOUT) &&
-			    (portp->pgrp != current->pgrp))
-				return(-EBUSY);
-		}
-		portp->flags |= ASYNC_CALLOUT_ACTIVE;
-	} else {
-		if (filp->f_flags & O_NONBLOCK) {
-			if (portp->flags & ASYNC_CALLOUT_ACTIVE)
-				return(-EBUSY);
-		} else {
-			if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0)
-				return(rc);
-		}
-		portp->flags |= ASYNC_NORMAL_ACTIVE;
+	if (!(filp->f_flags & O_NONBLOCK)) {
+		if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0)
+			return(rc);
 	}
+	portp->flags |= ASYNC_NORMAL_ACTIVE;
 
 	if ((portp->refcount == 1) && (portp->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == STL_DRVTYPSERIAL)
-			*tty->termios = portp->normaltermios;
-		else
-			*tty->termios = portp->callouttermios;
+		*tty->termios = portp->normaltermios;
 		stli_setport(portp);
 	}
-
-	portp->session = current->session;
-	portp->pgrp = current->pgrp;
 	return(0);
 }
 
@@ -1183,8 +1154,6 @@
 
 	if (portp->flags & ASYNC_NORMAL_ACTIVE)
 		portp->normaltermios = *tty->termios;
-	if (portp->flags & ASYNC_CALLOUT_ACTIVE)
-		portp->callouttermios = *tty->termios;
 
 /*
  *	May want to wait for data to drain before closing. The BUSY flag
@@ -1226,8 +1195,7 @@
 		wake_up_interruptible(&portp->open_wait);
 	}
 
-	portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE |
-		ASYNC_CLOSING);
+	portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&portp->close_wait);
 	restore_flags(flags);
 }
@@ -1558,13 +1526,8 @@
 	rc = 0;
 	doclocal = 0;
 
-	if (portp->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (portp->normaltermios.c_cflag & CLOCAL)
-			doclocal++;
-	} else {
-		if (portp->tty->termios->c_cflag & CLOCAL)
-			doclocal++;
-	}
+	if (portp->tty->termios->c_cflag & CLOCAL)
+		doclocal++;
 
 	save_flags(flags);
 	cli();
@@ -1573,12 +1536,10 @@
 		portp->refcount--;
 
 	for (;;) {
-		if ((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) {
-			stli_mkasysigs(&portp->asig, 1, 1);
-			if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS,
-			    &portp->asig, sizeof(asysigs_t), 0)) < 0)
-				break;
-		}
+		stli_mkasysigs(&portp->asig, 1, 1);
+		if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS,
+		    &portp->asig, sizeof(asysigs_t), 0)) < 0)
+			break;
 		if (tty_hung_up_p(filp) ||
 		    ((portp->flags & ASYNC_INITIALIZED) == 0)) {
 			if (portp->flags & ASYNC_HUP_NOTIFY)
@@ -1587,8 +1548,7 @@
 				rc = -ERESTARTSYS;
 			break;
 		}
-		if (((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) &&
-		    ((portp->flags & ASYNC_CLOSING) == 0) &&
+		if (((portp->flags & ASYNC_CLOSING) == 0) &&
 		    (doclocal || (portp->sigs & TIOCM_CD))) {
 			break;
 		}
@@ -2420,7 +2380,7 @@
 	clear_bit(ST_RXSTOP, &portp->state);
 	set_bit(TTY_IO_ERROR, &tty->flags);
 	portp->tty = (struct tty_struct *) NULL;
-	portp->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+	portp->flags &= ~ASYNC_NORMAL_ACTIVE;
 	portp->refcount = 0;
 	wake_up_interruptible(&portp->open_wait);
 }
@@ -2996,12 +2956,8 @@
 			if ((oldsigs & TIOCM_CD) &&
 			    ((portp->sigs & TIOCM_CD) == 0)) {
 				if (portp->flags & ASYNC_CHECK_CD) {
-					if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) &&
-					    (portp->flags & ASYNC_CALLOUT_NOHUP))) {
-						if (tty != (struct tty_struct *) NULL) {
-							schedule_task(&portp->tqhangup);
-						}
-					}
+					if (tty)
+						schedule_task(&portp->tqhangup);
 				}
 			}
 		}
@@ -3370,7 +3326,6 @@
 		init_waitqueue_head(&portp->close_wait);
 		init_waitqueue_head(&portp->raw_wait);
 		portp->normaltermios = stli_deftermios;
-		portp->callouttermios = stli_deftermios;
 		panelport++;
 		if (panelport >= brdp->panels[panelnr]) {
 			panelport = 0;
@@ -5336,7 +5291,6 @@
 
 /*
  *	Set up the tty driver structure and register us as a driver.
- *	Also setup the callout tty device.
  */
 	memset(&stli_serial, 0, sizeof(struct tty_driver));
 	stli_serial.magic = TTY_DRIVER_MAGIC;
@@ -5347,7 +5301,7 @@
 	stli_serial.minor_start = 0;
 	stli_serial.num = STL_MAXBRDS * STL_MAXPORTS;
 	stli_serial.type = TTY_DRIVER_TYPE_SERIAL;
-	stli_serial.subtype = STL_DRVTYPSERIAL;
+	stli_serial.subtype = SERIAL_TYPE_NORMAL;
 	stli_serial.init_termios = stli_deftermios;
 	stli_serial.flags = TTY_DRIVER_REAL_RAW;
 	stli_serial.refcount = &stli_refcount;
@@ -5375,17 +5329,8 @@
 	stli_serial.send_xchar = stli_sendxchar;
 	stli_serial.read_proc = stli_readproc;
 
-	stli_callout = stli_serial;
-	stli_callout.name = stli_calloutname;
-	stli_callout.major = STL_CALLOUTMAJOR;
-	stli_callout.subtype = STL_DRVTYPCALLOUT;
-	stli_callout.read_proc = 0;
-
 	if (tty_register_driver(&stli_serial))
 		printk(KERN_ERR "STALLION: failed to register serial driver\n");
-	if (tty_register_driver(&stli_callout))
-		printk(KERN_ERR "STALLION: failed to register callout driver\n");
-
 	return(0);
 }
 
diff -Nru a/drivers/char/moxa.c b/drivers/char/moxa.c
--- a/drivers/char/moxa.c	Wed May  7 07:24:21 2003
+++ b/drivers/char/moxa.c	Mon May 26 15:29:17 2003
@@ -151,12 +151,9 @@
 	int blocked_open;
 	long event; /* long req'd for set_bit --RR */
 	int asyncflags;
-	long session;
-	long pgrp;
 	unsigned long statusflags;
 	struct tty_struct *tty;
 	struct termios normal_termios;
-	struct termios callout_termios;
 	wait_queue_head_t open_wait;
 	wait_queue_head_t close_wait;
 	struct work_struct tqueue;
@@ -185,7 +182,6 @@
 
 
 #define SERIAL_TYPE_NORMAL	1
-#define SERIAL_TYPE_CALLOUT	2
 
 #define WAKEUP_CHARS		256
 
@@ -193,7 +189,6 @@
 
 static int verbose = 0;
 static int ttymajor = MOXAMAJOR;
-static int calloutmajor = MOXACUMAJOR;
 #ifdef MODULE
 /* Variables for insmod */
 static int baseaddr[] 	= 	{0, 0, 0, 0};
@@ -207,13 +202,11 @@
 MODULE_PARM(baseaddr, "1-4i");
 MODULE_PARM(numports, "1-4i");
 MODULE_PARM(ttymajor, "i");
-MODULE_PARM(calloutmajor, "i");
 MODULE_PARM(verbose, "i");
 
 #endif				//MODULE
 
 static struct tty_driver moxaDriver;
-static struct tty_driver moxaCallout;
 static struct tty_struct *moxaTable[MAX_PORTS + 1];
 static struct termios *moxaTermios[MAX_PORTS + 1];
 static struct termios *moxaTermiosLocked[MAX_PORTS + 1];
@@ -319,8 +312,6 @@
 		if (moxaEmptyTimer_on[i])
 			del_timer(&moxaEmptyTimer[i]);
 
-	if (tty_unregister_driver(&moxaCallout))
-		printk("Couldn't unregister MOXA Intellio family callout driver\n");
 	if (tty_unregister_driver(&moxaDriver))
 		printk("Couldn't unregister MOXA Intellio family serial driver\n");
 	if (verbose)
@@ -339,7 +330,6 @@
 
 	init_MUTEX(&moxaBuffSem);
 	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";
@@ -375,11 +365,6 @@
 	moxaDriver.start = moxa_start;
 	moxaDriver.hangup = moxa_hangup;
 
-	moxaCallout = moxaDriver;
-	moxaCallout.name = "ttyA";
-	moxaCallout.major = calloutmajor;
-	moxaCallout.subtype = SERIAL_TYPE_CALLOUT;
-
 	moxaXmitBuff = 0;
 
 	for (i = 0, ch = moxaChannels; i < MAX_PORTS; i++, ch++) {
@@ -391,7 +376,6 @@
 		ch->closing_wait = 30 * HZ;
 		ch->count = 0;
 		ch->blocked_open = 0;
-		ch->callout_termios = moxaCallout.init_termios;
 		ch->normal_termios = moxaDriver.init_termios;
 		init_waitqueue_head(&ch->open_wait);
 		init_waitqueue_head(&ch->close_wait);
@@ -406,17 +390,10 @@
 		moxa_boards[i].pciInfo.devNum = 0;
 	}
 	MoxaDriverInit();
-	printk("Tty devices major number = %d, callout devices major number = %d\n", ttymajor, calloutmajor);
+	printk("Tty devices major number = %d\n", ttymajor);
 
-	ret1 = 0;
-	ret2 = 0;
-	if ((ret1 = tty_register_driver(&moxaDriver))) {
+	if (tty_register_driver(&moxaDriver)) {
 		printk(KERN_ERR "Couldn't install MOXA Smartio family driver !\n");
-	} else if ((ret2 = tty_register_driver(&moxaCallout))) {
-		tty_unregister_driver(&moxaDriver);
-		printk(KERN_ERR "Couldn't install MOXA Smartio family callout driver !\n");
-	}
-	if (ret1 || ret2) {
 		return -1;
 	}
 	for (i = 0; i < MAX_PORTS; i++) {
@@ -542,7 +519,7 @@
 		if (test_and_clear_bit(MOXA_EVENT_HANGUP, &ch->event)) {
 			tty_hangup(tty);	/* FIXME: module removal race here - AKPM */
 			wake_up_interruptible(&ch->open_wait);
-			ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+			ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
 		}
 	}
 }
@@ -583,13 +560,8 @@
 	tty->driver_data = ch;
 	ch->tty = tty;
 	if (ch->count == 1 && (ch->asyncflags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = ch->normal_termios;
-		else
-			*tty->termios = ch->callout_termios;
+		*tty->termios = ch->normal_termios;
 	}
-	ch->session = current->session;
-	ch->pgrp = current->pgrp;
 	if (!(ch->asyncflags & ASYNC_INITIALIZED)) {
 		ch->statusflags = 0;
 		set_tty_param(tty);
@@ -655,8 +627,6 @@
 	 */
 	if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
 		ch->normal_termios = *tty->termios;
-	if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
-		ch->callout_termios = *tty->termios;
 	if (ch->asyncflags & ASYNC_INITIALIZED) {
 		setup_empty_event(tty);
 		tty_wait_until_sent(tty, 30 * HZ);	/* 30 seconds timeout */
@@ -680,8 +650,7 @@
 		}
 		wake_up_interruptible(&ch->open_wait);
 	}
-	ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE |
-			    ASYNC_CLOSING);
+	ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
 	wake_up_interruptible(&ch->close_wait);
 }
 
@@ -963,7 +932,7 @@
 	shut_down(ch);
 	ch->event = 0;
 	ch->count = 0;
-	ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+	ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
 	ch->tty = 0;
 	wake_up_interruptible(&ch->open_wait);
 }
@@ -1083,30 +1052,10 @@
 #endif
 	}
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
-			return (-EBUSY);
-		if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
-		    (ch->asyncflags & ASYNC_SESSION_LOCKOUT) &&
-		    (ch->session != current->session))
-			return (-EBUSY);
-		if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
-		    (ch->asyncflags & ASYNC_PGRP_LOCKOUT) &&
-		    (ch->pgrp != current->pgrp))
-			return (-EBUSY);
-		ch->asyncflags |= ASYNC_CALLOUT_ACTIVE;
-		return (0);
-	}
-	/*
 	 * If non-blocking mode is set, then make the check up front
 	 * and then exit.
 	 */
 	if (filp->f_flags & O_NONBLOCK) {
-		if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
-			return (-EBUSY);
 		ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
 		return (0);
 	}
@@ -1139,8 +1088,7 @@
 #endif
 			break;
 		}
-		if (!(ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(ch->asyncflags & ASYNC_CLOSING) && (do_clocal ||
+		if (!(ch->asyncflags & ASYNC_CLOSING) && (do_clocal ||
 						MoxaPortDCDON(ch->port)))
 			break;
 
@@ -1717,7 +1665,8 @@
 			return -EFAULT;
 		return 0;
 	case MOXA_GET_CUMAJOR:
-		if(copy_to_user((void *)arg, &calloutmajor, sizeof(int)))
+		i = 0;
+		if(copy_to_user((void *)arg, &i, sizeof(int)))
 			return -EFAULT;
 		return 0;
 	case MOXA_GETMSTATUS:
diff -Nru a/drivers/char/mxser.c b/drivers/char/mxser.c
--- a/drivers/char/mxser.c	Wed May  7 07:24:11 2003
+++ b/drivers/char/mxser.c	Mon May 26 15:29:16 2003
@@ -87,7 +87,6 @@
 #define		MXSER_ERR_VECTOR	-4
 
 #define 	SERIAL_TYPE_NORMAL	1
-#define 	SERIAL_TYPE_CALLOUT	2
 
 #define 	WAKEUP_CHARS		256
 
@@ -208,7 +207,6 @@
 
 static int ioaddr[MXSER_BOARDS];
 static int ttymajor = MXSERMAJOR;
-static int calloutmajor = MXSERCUMAJOR;
 static int verbose;
 
 /* Variables for insmod */
@@ -218,7 +216,6 @@
 MODULE_LICENSE("GPL");
 MODULE_PARM(ioaddr, "1-4i");
 MODULE_PARM(ttymajor, "i");
-MODULE_PARM(calloutmajor, "i");
 MODULE_PARM(verbose, "i");
 
 struct mxser_hwconf {
@@ -256,15 +253,12 @@
 	unsigned long event;
 	int count;		/* # of fd on device */
 	int blocked_open;	/* # of blocked opens */
-	long session;		/* Session of opening process */
-	long pgrp;		/* pgrp of opening process */
 	unsigned char *xmit_buf;
 	int xmit_head;
 	int xmit_tail;
 	int xmit_cnt;
 	struct work_struct tqueue;
 	struct termios normal_termios;
-	struct termios callout_termios;
 	wait_queue_head_t open_wait;
 	wait_queue_head_t close_wait;
 	wait_queue_head_t delta_msr_wait;
@@ -294,7 +288,7 @@
 };
 
 
-static struct tty_driver mxvar_sdriver, mxvar_cdriver;
+static struct tty_driver mxvar_sdriver;
 static int mxvar_refcount;
 static struct mxser_struct mxvar_table[MXSER_PORTS];
 static struct tty_struct *mxvar_tty[MXSER_PORTS + 1];
@@ -374,8 +368,6 @@
 
 	if (verbose)
 		printk("Unloading module mxser ...\n");
-	if ((err |= tty_unregister_driver(&mxvar_cdriver)))
-		printk("Couldn't unregister MOXA Smartio family callout driver\n");
 	if ((err |= tty_unregister_driver(&mxvar_sdriver)))
 		printk("Couldn't unregister MOXA Smartio family serial driver\n");
 
@@ -428,7 +420,6 @@
 		info->close_delay = 5 * HZ / 10;
 		info->closing_wait = 30 * HZ;
 		INIT_WORK(&info->tqueue, mxser_do_softint, info);
-		info->callout_termios = mxvar_cdriver.init_termios;
 		info->normal_termios = mxvar_sdriver.init_termios;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
@@ -532,16 +523,7 @@
 	mxvar_sdriver.start = mxser_start;
 	mxvar_sdriver.hangup = mxser_hangup;
 
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	mxvar_cdriver = mxvar_sdriver;
-	mxvar_cdriver.name = "cum";
-	mxvar_cdriver.major = calloutmajor;
-	mxvar_cdriver.subtype = SERIAL_TYPE_CALLOUT;
-
-	printk("Tty devices major number = %d, callout devices major number = %d\n", ttymajor, calloutmajor);
+	printk("Tty devices major number = %d\n", ttymajor);
 
 	mxvar_diagflag = 0;
 	memset(mxvar_table, 0, MXSER_PORTS * sizeof(struct mxser_struct));
@@ -666,30 +648,17 @@
 	}
 
 
-	ret1 = 0;
-	ret2 = 0;
-	if (!(ret1 = tty_register_driver(&mxvar_sdriver))) {
-		if (!(ret2 = tty_register_driver(&mxvar_cdriver))) {
-			return 0;
-		} else {
-			tty_unregister_driver(&mxvar_sdriver);
-			printk("Couldn't install MOXA Smartio family callout driver !\n");
-		}
-	} else
-		printk("Couldn't install MOXA Smartio family driver !\n");
+	if (!tty_register_driver(&mxvar_sdriver))
+		return 0;
 
+	printk("Couldn't install MOXA Smartio family driver !\n");
 
-	if (ret1 || ret2) {
-		for (i = 0; i < MXSER_BOARDS; i++) {
-			if (mxsercfg[i].board_type == -1)
-				continue;
-			else {
-				free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
-			}
-		}
-		return -1;
+	for (i = 0; i < MXSER_BOARDS; i++) {
+		if (mxsercfg[i].board_type == -1)
+			continue;
+		free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
 	}
-	return (0);
+	return -1;
 }
 
 static void mxser_do_softint(void *private_)
@@ -758,15 +727,9 @@
 		return (retval);
 
 	if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->normal_termios;
-		else
-			*tty->termios = info->callout_termios;
+		*tty->termios = info->normal_termios;
 		mxser_change_speed(info, 0);
 	}
-	info->session = current->session;
-	info->pgrp = current->pgrp;
-
 	return (0);
 }
 
@@ -823,8 +786,6 @@
 	 */
 	if (info->flags & ASYNC_NORMAL_ACTIVE)
 		info->normal_termios = *tty->termios;
-	if (info->flags & ASYNC_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify
 	 * the line discipline to only process XON/XOFF characters.
@@ -872,8 +833,7 @@
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE |
-			 ASYNC_CLOSING);
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	restore_flags(flags);
 
@@ -1154,7 +1114,8 @@
 		return 0;
 
 	case MOXA_GET_CUMAJOR:
-		if(copy_to_user((int *) arg, &calloutmajor, sizeof(int)))
+		result = 0;
+		if(copy_to_user((int *) arg, &result, sizeof(int)))
 			return -EFAULT;
 		return 0;
 
@@ -1349,7 +1310,7 @@
 	mxser_shutdown(info);
 	info->event = 0;
 	info->count = 0;
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -1513,8 +1474,7 @@
 	if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
 		if (status & UART_MSR_DCD)
 			wake_up_interruptible(&info->open_wait);
-		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-			   (info->flags & ASYNC_CALLOUT_NOHUP)))
+		else
 			set_bit(MXSER_EVENT_HANGUP, &info->event);
 		schedule_work(&info->tqueue);
 	}
@@ -1563,41 +1523,16 @@
 #endif
 	}
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ASYNC_NORMAL_ACTIVE)
-			return (-EBUSY);
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-			return (-EBUSY);
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-			return (-EBUSY);
-		info->flags |= ASYNC_CALLOUT_ACTIVE;
-		return (0);
-	}
-	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & ASYNC_CALLOUT_ACTIVE)
-			return (-EBUSY);
 		info->flags |= ASYNC_NORMAL_ACTIVE;
 		return (0);
 	}
-	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
 
 	/*
 	 * Block waiting for the carrier detect and the line to become
@@ -1617,9 +1552,8 @@
 	while (1) {
 		save_flags(flags);
 		cli();
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE))
-			outb(inb(info->base + UART_MCR) | UART_MCR_DTR | UART_MCR_RTS,
-			     info->base + UART_MCR);
+		outb(inb(info->base + UART_MCR) | UART_MCR_DTR | UART_MCR_RTS,
+		     info->base + UART_MCR);
 		restore_flags(flags);
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) {
@@ -1633,8 +1567,7 @@
 #endif
 			break;
 		}
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(info->flags & ASYNC_CLOSING) &&
+		if (!(info->flags & ASYNC_CLOSING) &&
 		    (do_clocal || (inb(info->base + UART_MSR) & UART_MSR_DCD)))
 			break;
 		if (signal_pending(current)) {
diff -Nru a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
--- a/drivers/char/pcmcia/synclink_cs.c	Wed May 14 23:44:02 2003
+++ b/drivers/char/pcmcia/synclink_cs.c	Wed May 28 08:01:06 2003
@@ -155,14 +155,11 @@
 	struct mgsl_icount	icount;
 	
 	struct termios		normal_termios;
-	struct termios		callout_termios;
 	
 	struct tty_struct 	*tty;
 	int			timeout;
 	int			x_char;		/* xon/xoff character */
 	int			blocked_open;	/* # of blocked opens */
-	long			session;	/* Session of opening process */
-	long			pgrp;		/* pgrp of opening process */
 	unsigned char		read_status_mask;
 	unsigned char		ignore_status_mask;	
 
@@ -500,7 +497,7 @@
 static char *driver_name = "SyncLink PC Card driver";
 static char *driver_version = "$Revision: 4.10 $";
 
-static struct tty_driver serial_driver, callout_driver;
+static struct tty_driver serial_driver;
 static int serial_refcount;
 
 /* number of characters left in xmit buffer before we ask for more */
@@ -617,8 +614,7 @@
     memset(serial_table,0,sizeof(struct tty_struct*)*MAX_DEVICE_COUNT);
     memset(serial_termios,0,sizeof(struct termios*)*MAX_DEVICE_COUNT);
     memset(serial_termios_locked,0,sizeof(struct termios*)*MAX_DEVICE_COUNT);
-		
-    info->callout_termios = callout_driver.init_termios;
+
     info->normal_termios  = serial_driver.init_termios;
 
     return link;
@@ -1307,7 +1303,7 @@
 			       (info->serial_signals & SerialSignal_DCD) ? "on" : "off");
 		if (info->serial_signals & SerialSignal_DCD)
 			wake_up_interruptible(&info->open_wait);
-		else if (!(info->flags & (ASYNC_CALLOUT_ACTIVE | ASYNC_CALLOUT_NOHUP))) {
+		else if (!(info->flags & ASYNC_CALLOUT_NOHUP)) {
 			if (debug_level >= DEBUG_LEVEL_ISR)
 				printk("doing serial hangup...");
 			if (info->tty)
@@ -2589,9 +2585,7 @@
 	 */
 	if (info->flags & ASYNC_NORMAL_ACTIVE)
 		info->normal_termios = *tty->termios;
-	if (info->flags & ASYNC_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
-		
+
 	/* set tty->closing to notify line discipline to 
 	 * only process XON/XOFF characters. Only the N_TTY
 	 * discipline appears to use this (ppp does not).
@@ -2629,8 +2623,7 @@
 		wake_up_interruptible(&info->open_wait);
 	}
 	
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 			 
 	wake_up_interruptible(&info->close_wait);
 	
@@ -2723,7 +2716,7 @@
 	shutdown(info);
 	
 	info->count = 0;	
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->tty = 0;
 
 	wake_up_interruptible(&info->open_wait);
@@ -2744,40 +2737,16 @@
 		printk("%s(%d):block_til_ready on %s\n",
 			 __FILE__,__LINE__, tty->driver->name );
 
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		/* this is a callout device */
-		/* just verify that normal device is not in use */
-		if (info->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-	
 	if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
 		/* nonblock mode is set or port is not enabled */
 		/* just verify that callout device is not active */
-		if (info->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
+
 	/* Wait for carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
 	 * this loop, info->count is dropped by one, so that
@@ -2801,8 +2770,7 @@
 	info->blocked_open++;
 	
 	while (1) {
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
- 		    (tty->termios->c_cflag & CBAUD)) {
+		if ((tty->termios->c_cflag & CBAUD)) {
 			spin_lock_irqsave(&info->lock,flags);
 			info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
 		 	set_signals(info);
@@ -2821,8 +2789,7 @@
 	 	get_signals(info);
 		spin_unlock_irqrestore(&info->lock,flags);
 		
- 		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
- 		    !(info->flags & ASYNC_CLOSING) &&
+ 		if (!(info->flags & ASYNC_CLOSING) &&
  		    (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
  			break;
 		}
@@ -2926,16 +2893,10 @@
 
 	if ((info->count == 1) &&
 	    info->flags & ASYNC_SPLIT_TERMIOS) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->normal_termios;
-		else 
-			*tty->termios = info->callout_termios;
+		*tty->termios = info->normal_termios;
 		mgslpc_change_params(info);
 	}
 	
-	info->session = current->session;
-	info->pgrp    = current->pgrp;
-
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgslpc_open(%s) success\n",
 			 __FILE__,__LINE__, info->device_name);
@@ -3170,9 +3131,18 @@
 	}
 }
 
+static struct pcmcia_driver mgslpc_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "synclink_cs",
+	},
+	.attach		= mgslpc_attach,
+	.detach		= mgslpc_detach,
+};
+
 static int __init synclink_cs_init(void)
 {
-    servinfo_t serv;
+    int error;
 
     if (break_on_load) {
 	    mgslpc_get_text_ptr();
@@ -3181,13 +3151,9 @@
 
     printk("%s %s\n", driver_name, driver_version);
 
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	    printk(KERN_NOTICE "synclink_cs: Card Services release "
-		   "does not match!\n");
-	    return -1;
-    }
-    register_pccard_driver(&dev_info, &mgslpc_attach, &mgslpc_detach);
+    error = pcmcia_register_driver(&mgslpc_driver);
+    if (error)
+	    return error;
 
     /* Initialize the tty_driver structure */
 	
@@ -3232,28 +3198,13 @@
     serial_driver.tiocmget = tiocmget;
     serial_driver.tiocmset = tiocmset;
 	
-    /*
-     * The callout device is just like normal device except for
-     * major number and the subtype code.
-     */
-    callout_driver = serial_driver;
-    callout_driver.name = "cuaSLP";
-    callout_driver.major = cuamajor;
-    callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-    callout_driver.read_proc = 0;
-    callout_driver.proc_entry = 0;
-
     if (tty_register_driver(&serial_driver) < 0)
 	    printk("%s(%d):Couldn't register serial driver\n",
 		   __FILE__,__LINE__);
 			
-    if (tty_register_driver(&callout_driver) < 0)
-	    printk("%s(%d):Couldn't register callout driver\n",
-		   __FILE__,__LINE__);
-
-    printk("%s %s, tty major#%d callout major#%d\n",
+    printk("%s %s, tty major#%d\n",
 	   driver_name, driver_version,
-	   serial_driver.major, callout_driver.major);
+	   serial_driver.major);
 	
     return 0;
 }
@@ -3270,11 +3221,10 @@
 	if ((rc = tty_unregister_driver(&serial_driver)))
 		printk("%s(%d) failed to unregister tty driver err=%d\n",
 		       __FILE__,__LINE__,rc);
-	if ((rc = tty_unregister_driver(&callout_driver)))
-		printk("%s(%d) failed to unregister callout driver err=%d\n",
-		       __FILE__,__LINE__,rc);
 
-	unregister_pccard_driver(&dev_info);
+	pcmcia_unregister_driver(&mgslpc_driver);
+
+	/* XXX: this really needs to move into generic code.. */
 	while (dev_list != NULL) {
 		if (dev_list->state & DEV_CONFIG)
 			mgslpc_release((u_long)dev_list);
diff -Nru a/drivers/char/pcxx.c b/drivers/char/pcxx.c
--- a/drivers/char/pcxx.c	Wed May  7 07:24:09 2003
+++ b/drivers/char/pcxx.c	Mon May 26 15:29:16 2003
@@ -141,11 +141,9 @@
 
 #define FEPTIMEOUT 200000  
 #define SERIAL_TYPE_NORMAL	1
-#define SERIAL_TYPE_CALLOUT	2
 #define PCXE_EVENT_HANGUP   1
 
 struct tty_driver pcxe_driver;
-struct tty_driver pcxe_callout;
 static int pcxe_refcount;
 
 static struct timer_list pcxx_timer;
@@ -240,8 +238,6 @@
 
 	if ((e1 = tty_unregister_driver(&pcxe_driver)))
 		printk("SERIAL: failed to unregister serial driver (%d)\n", e1);
-	if ((e2 = tty_unregister_driver(&pcxe_callout)))
-		printk("SERIAL: failed to unregister callout driver (%d)\n",e2);
 
 	cleanup_board_resources();
 	kfree(digi_channels);
@@ -341,13 +337,8 @@
 	int	retval = 0;
 	int	do_clocal = 0;
 
-	if (info->asyncflags & ASYNC_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
 
 	/*
 	 * Block waiting for the carrier detect and the line to become free
@@ -360,12 +351,10 @@
 
 	for (;;) {
 		cli();
-		if ((info->asyncflags & ASYNC_CALLOUT_ACTIVE) == 0) {
-			globalwinon(info);
-			info->omodem |= DTR|RTS;
-			fepcmd(info, SETMODEM, DTR|RTS, 0, 10, 1);
-			memoff(info);
-		}
+		globalwinon(info);
+		info->omodem |= DTR|RTS;
+		fepcmd(info, SETMODEM, DTR|RTS, 0, 10, 1);
+		memoff(info);
 		sti();
 		set_current_state(TASK_INTERRUPTIBLE);
 		if(tty_hung_up_p(filp) || (info->asyncflags & ASYNC_INITIALIZED) == 0) {
@@ -375,8 +364,7 @@
 				retval = -ERESTARTSYS;	
 			break;
 		}
-		if ((info->asyncflags & ASYNC_CALLOUT_ACTIVE) == 0 &&
-		    (info->asyncflags & ASYNC_CLOSING) == 0 &&
+		if ((info->asyncflags & ASYNC_CLOSING) == 0 &&
 			(do_clocal || (info->imodem & info->dcd)))
 			break;
 		if(signal_pending(current)) {
@@ -476,56 +464,29 @@
 		else
 			return -ERESTARTSYS;
 	}
-	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) {
-			if ((ch->asyncflags & ASYNC_SESSION_LOCKOUT) &&
-		    		(ch->session != current->session))
-			    return -EBUSY;
-			if((ch->asyncflags & ASYNC_PGRP_LOCKOUT) &&
-			    (ch->pgrp != current->pgrp))
-			    return -EBUSY;
-		}
-		ch->asyncflags |= ASYNC_CALLOUT_ACTIVE;
-	}
-	else {
-		if (filp->f_flags & O_NONBLOCK) {
-			if(ch->asyncflags & ASYNC_CALLOUT_ACTIVE)
-				return -EBUSY;
-		}
-		else {
-			/* this has to be set in order for the "block until
-			 * CD" code to work correctly.  i'm not sure under
-			 * what circumstances asyncflags should be set to
-			 * ASYNC_NORMAL_ACTIVE though
-			 * brian@ilinx.com
-			 */
-			ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
-			if ((retval = pcxx_waitcarrier(tty, filp, ch)) != 0)
-				return retval;
-		}
+
+	if (!(filp->f_flags & O_NONBLOCK)) {
+		/* this has to be set in order for the "block until
+		 * CD" code to work correctly.  i'm not sure under
+		 * what circumstances asyncflags should be set to
+		 * ASYNC_NORMAL_ACTIVE though
+		 * brian@ilinx.com
+		 */
 		ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+		if ((retval = pcxx_waitcarrier(tty, filp, ch)) != 0)
+			return retval;
 	}
+	ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
  	
 	save_flags(flags);
 	cli();
 	if((ch->count == 1) && (ch->asyncflags & ASYNC_SPLIT_TERMIOS)) {
-		if(tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = ch->normal_termios;
-		else 
-			*tty->termios = ch->callout_termios;
+		*tty->termios = ch->normal_termios;
 		globalwinon(ch);
 		pcxxparam(tty,ch);
 		memoff(ch);
 	}
 
-	ch->session = current->session;
-	ch->pgrp = current->pgrp;
 	restore_flags(flags);
 	return 0;
 } 
@@ -605,8 +566,6 @@
 		*/
 		if(info->asyncflags & ASYNC_NORMAL_ACTIVE)
 			info->normal_termios = *tty->termios;
-		if(info->asyncflags & ASYNC_CALLOUT_ACTIVE)
-			info->callout_termios = *tty->termios;
 		tty->closing = 1;
 		if(info->asyncflags & ASYNC_INITIALIZED) {
 			setup_empty_event(tty,info);		
@@ -644,8 +603,7 @@
 			}
 			wake_up_interruptible(&info->open_wait);
 		}
-		info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|
-							  ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);
+		info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 		wake_up_interruptible(&info->close_wait);
 		restore_flags(flags);
 	}
@@ -665,7 +623,7 @@
 		ch->event = 0;
 		ch->count = 0;
 		ch->tty = NULL;
-		ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+		ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
 		wake_up_interruptible(&ch->open_wait);
 		restore_flags(flags);
 	}
@@ -1257,12 +1215,6 @@
 	pcxe_driver.start = pcxe_start;
 	pcxe_driver.hangup = pcxe_hangup;
 
-	pcxe_callout = pcxe_driver;
-	pcxe_callout.name = "cud";
-	pcxe_callout.major = DIGICU_MAJOR;
-	pcxe_callout.subtype = SERIAL_TYPE_CALLOUT;
-	pcxe_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-
 	for(crd=0; crd < numcards; crd++) {
 		bd = &boards[crd];
 		outb(FEPRST, bd->port);
@@ -1619,7 +1571,6 @@
 			ch->close_delay = 50;
 			ch->count = 0;
 			ch->blocked_open = 0;
-			ch->callout_termios = pcxe_callout.init_termios;
 			ch->normal_termios = pcxe_driver.init_termios;
 			init_waitqueue_head(&ch->open_wait);
 			init_waitqueue_head(&ch->close_wait);
@@ -1651,12 +1602,6 @@
 		goto cleanup_boards;
 	}
 
-	ret = tty_register_driver(&pcxe_callout);
-	if(ret) {
-		printk(KERN_ERR "Couldn't register PC/Xe callout\n");
-		goto cleanup_pcxe_driver;
-	}
-
 	/*
 	 * Start up the poller to check for events on all enabled boards
 	 */
@@ -1760,7 +1705,7 @@
 
 		if (event & MODEMCHG_IND) {
 			ch->imodem = mstat;
-			if (ch->asyncflags & (ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE)) {
+			if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) {
 				if (ch->asyncflags & ASYNC_CHECK_CD) {
 					if (mstat & ch->dcd) {
 						wake_up_interruptible(&ch->open_wait);
@@ -2377,7 +2322,7 @@
 			if(test_and_clear_bit(PCXE_EVENT_HANGUP, &info->event)) {
 				tty_hangup(tty);
 				wake_up_interruptible(&info->open_wait);
-				info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+				info->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
 			}
 		}
 	}
diff -Nru a/drivers/char/pcxx.h b/drivers/char/pcxx.h
--- a/drivers/char/pcxx.h	Mon Feb  4 23:40:22 2002
+++ b/drivers/char/pcxx.h	Mon May 26 15:29:16 2003
@@ -68,7 +68,6 @@
 
 #define FEPTIMEOUT 200000  
 #define SERIAL_TYPE_NORMAL	1
-#define SERIAL_TYPE_CALLOUT	2
 #define PCXE_EVENT_HANGUP   1
 #define PCXX_MAGIC	0x5c6df104L
 
@@ -78,8 +77,6 @@
 	unchar						boardnum;
 	unchar						channelnum;
 	uint						dev;
-	long						session;
-	long						pgrp;
 	struct tty_struct			*tty;
 	struct board_info			*board;
 	volatile struct board_chan	*brdchan;
@@ -127,7 +124,6 @@
 	ulong						c_lflag;
 	ulong						c_oflag;
 	struct termios				normal_termios;
-	struct termios				callout_termios;
 	struct digi_struct			digiext;
 	ulong						dummy[8];
 };
diff -Nru a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
--- a/drivers/char/rio/rio_linux.c	Wed May  7 07:23:59 2003
+++ b/drivers/char/rio/rio_linux.c	Mon May 26 15:29:26 2003
@@ -111,18 +111,11 @@
 of boards in rio.h.  You'll have to allocate more majors if you need
 more than 512 ports.... */
 
-
-/* Why the hell am I defining these here? */
-#define RIO_TYPE_NORMAL 1
-#define RIO_TYPE_CALLOUT 2
-
 #ifndef RIO_NORMAL_MAJOR0
 /* This allows overriding on the compiler commandline, or in a "major.h" 
    include or something like that */
 #define RIO_NORMAL_MAJOR0  154
-#define RIO_CALLOUT_MAJOR0 155
 #define RIO_NORMAL_MAJOR1  156
-#define RIO_CALLOUT_MAJOR1 157
 #endif
 
 #ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8
@@ -208,8 +201,7 @@
 
 void my_hd (void *addr, int len);
 
-static struct tty_driver rio_driver, rio_callout_driver;
-static struct tty_driver rio_driver2, rio_callout_driver2;
+static struct tty_driver rio_driver, rio_driver2;
 
 static struct tty_struct * rio_table[RIO_NPORTS];
 static struct termios ** rio_termios;
@@ -889,7 +881,7 @@
   rio_driver.major = RIO_NORMAL_MAJOR0;
   rio_driver.num = 256;
   rio_driver.type = TTY_DRIVER_TYPE_SERIAL;
-  rio_driver.subtype = RIO_TYPE_NORMAL;
+  rio_driver.subtype = SERIAL_TYPE_NORMAL;
   rio_driver.init_termios = tty_std_termios;
   rio_driver.init_termios.c_cflag =
     B9600 | CS8 | CREAD | HUPCL | CLOCAL;
@@ -920,28 +912,14 @@
   rio_driver2.termios += 256;
   rio_driver2.termios_locked += 256;
 
-  rio_callout_driver = rio_driver;
-  rio_callout_driver.name = "cusr";
-  rio_callout_driver.major = RIO_CALLOUT_MAJOR0;
-  rio_callout_driver.subtype = RIO_TYPE_CALLOUT;
-
-  rio_callout_driver2 = rio_callout_driver;
-  rio_callout_driver2.major = RIO_CALLOUT_MAJOR1;
-  rio_callout_driver2.termios += 256;
-  rio_callout_driver2.termios_locked += 256;
-
   rio_dprintk (RIO_DEBUG_INIT, "set_termios = %p\n", gs_set_termios);
 
   if ((error = tty_register_driver(&rio_driver))) goto bad1;
   if ((error = tty_register_driver(&rio_driver2))) goto bad2;
-  if ((error = tty_register_driver(&rio_callout_driver))) goto bad3;
-  if ((error = tty_register_driver(&rio_callout_driver2))) goto bad4;
 
   func_exit();
   return 0;
   /* 
- bad5:tty_unregister_driver (&rio_callout_driver2); */
- bad4:tty_unregister_driver (&rio_callout_driver);
  bad3:tty_unregister_driver (&rio_driver2);
  bad2:tty_unregister_driver (&rio_driver);
  bad1:printk(KERN_ERR "rio: Couldn't register a rio driver, error = %d\n",
@@ -1006,7 +984,6 @@
     }
     rio_dprintk (RIO_DEBUG_INIT, "initing port %d (%d)\n", i, port->Mapped);
     port->PortNum = i;
-    port->gs.callout_termios = tty_std_termios;
     port->gs.normal_termios  = tty_std_termios;
     port->gs.magic = RIO_MAGIC;
     port->gs.close_delay = HZ/2;
@@ -1051,8 +1028,6 @@
 static void  __exit rio_release_drivers(void)
 {
   func_enter();
-  tty_unregister_driver (&rio_callout_driver2);
-  tty_unregister_driver (&rio_callout_driver);
   tty_unregister_driver (&rio_driver2);
   tty_unregister_driver (&rio_driver);
   func_exit();
diff -Nru a/drivers/char/riscom8.c b/drivers/char/riscom8.c
--- a/drivers/char/riscom8.c	Wed May  7 07:24:02 2003
+++ b/drivers/char/riscom8.c	Mon May 26 15:29:26 2003
@@ -83,11 +83,8 @@
 
 static DECLARE_TASK_QUEUE(tq_riscom);
 
-#define RISCOM_TYPE_NORMAL	1
-#define RISCOM_TYPE_CALLOUT	2
-
 static struct riscom_board * IRQ_to_board[16];
-static struct tty_driver riscom_driver, riscom_callout_driver;
+static struct tty_driver riscom_driver;
 static int    riscom_refcount;
 static struct tty_struct * riscom_table[RC_NBOARD * RC_NPORT];
 static struct termios * riscom_termios[RC_NBOARD * RC_NPORT];
@@ -550,10 +547,8 @@
 	if (mcr & MCR_CDCHG)  {
 		if (rc_in(bp, CD180_MSVR) & MSVR_CD) 
 			wake_up_interruptible(&port->open_wait);
-		else if (!((port->flags & ASYNC_CALLOUT_ACTIVE) &&
-			   (port->flags & ASYNC_CALLOUT_NOHUP))) {
+		else
 			schedule_task(&port->tqueue_hangup);
-		}
 	}
 	
 #ifdef RISCOM_BRAIN_DAMAGED_CTS
@@ -986,44 +981,18 @@
 	}
 
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == RISCOM_TYPE_CALLOUT) {
-		if (port->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (port->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (port->session != current->session))
-		    return -EBUSY;
-		if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (port->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (port->pgrp != current->pgrp))
-		    return -EBUSY;
-		port->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-	
-	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (port->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		port->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (port->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (port->normal_termios.c_cflag & CLOCAL) 
-			do_clocal = 1;
-	} else {
-		if (C_CLOCAL(tty))  
-			do_clocal = 1;
-	}
-	
+	if (C_CLOCAL(tty))  
+		do_clocal = 1;
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -1042,11 +1011,9 @@
 		cli();
 		rc_out(bp, CD180_CAR, port_No(port));
 		CD = rc_in(bp, CD180_MSVR) & MSVR_CD;
-		if (!(port->flags & ASYNC_CALLOUT_ACTIVE))  {
-			rc_out(bp, CD180_MSVR, MSVR_RTS);
-			bp->DTR &= ~(1u << port_No(port));
-			rc_out(bp, RC_DTR, bp->DTR);
-		}
+		rc_out(bp, CD180_MSVR, MSVR_RTS);
+		bp->DTR &= ~(1u << port_No(port));
+		rc_out(bp, RC_DTR, bp->DTR);
 		sti();
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) ||
@@ -1057,8 +1024,7 @@
 				retval = -ERESTARTSYS;	
 			break;
 		}
-		if (!(port->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(port->flags & ASYNC_CLOSING) &&
+		if (!(port->flags & ASYNC_CLOSING) &&
 		    (do_clocal || CD))
 			break;
 		if (signal_pending(current)) {
@@ -1110,18 +1076,11 @@
 		return error;
 	
 	if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == RISCOM_TYPE_NORMAL)
-			*tty->termios = port->normal_termios;
-		else
-			*tty->termios = port->callout_termios;
+		*tty->termios = port->normal_termios;
 		save_flags(flags); cli();
 		rc_change_speed(bp, port);
 		restore_flags(flags);
 	}
-
-	port->session = current->session;
-	port->pgrp = current->pgrp;
-	
 	return 0;
 }
 
@@ -1161,8 +1120,6 @@
 	 */
 	if (port->flags & ASYNC_NORMAL_ACTIVE)
 		port->normal_termios = *tty->termios;
-	if (port->flags & ASYNC_CALLOUT_ACTIVE)
-		port->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -1210,8 +1167,7 @@
 		}
 		wake_up_interruptible(&port->open_wait);
 	}
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&port->close_wait);
 out:	restore_flags(flags);
 }
@@ -1689,7 +1645,7 @@
 	rc_shutdown_port(bp, port);
 	port->event = 0;
 	port->count = 0;
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	port->flags &= ~ASYNC_NORMAL_ACTIVE;
 	port->tty = 0;
 	wake_up_interruptible(&port->open_wait);
 }
@@ -1757,7 +1713,7 @@
 	riscom_driver.major = RISCOM8_NORMAL_MAJOR;
 	riscom_driver.num = RC_NBOARD * RC_NPORT;
 	riscom_driver.type = TTY_DRIVER_TYPE_SERIAL;
-	riscom_driver.subtype = RISCOM_TYPE_NORMAL;
+	riscom_driver.subtype = SERIAL_TYPE_NORMAL;
 	riscom_driver.init_termios = tty_std_termios;
 	riscom_driver.init_termios.c_cflag =
 		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
@@ -1783,11 +1739,6 @@
 	riscom_driver.start = rc_start;
 	riscom_driver.hangup = rc_hangup;
 
-	riscom_callout_driver = riscom_driver;
-	riscom_callout_driver.name = "cul";
-	riscom_callout_driver.major = RISCOM8_CALLOUT_MAJOR;
-	riscom_callout_driver.subtype = RISCOM_TYPE_CALLOUT;
-	
 	if ((error = tty_register_driver(&riscom_driver)))  {
 		free_page((unsigned long)tmp_buf);
 		printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
@@ -1795,18 +1746,9 @@
 		       error);
 		return 1;
 	}
-	if ((error = tty_register_driver(&riscom_callout_driver)))  {
-		free_page((unsigned long)tmp_buf);
-		tty_unregister_driver(&riscom_driver);
-		printk(KERN_ERR "rc: Couldn't register RISCom/8 callout "
-				"driver, error = %d\n",
-		       error);
-		return 1;
-	}
-	
+
 	memset(rc_port, 0, sizeof(rc_port));
 	for (i = 0; i < RC_NPORT * RC_NBOARD; i++)  {
-		rc_port[i].callout_termios = riscom_callout_driver.init_termios;
 		rc_port[i].normal_termios  = riscom_driver.init_termios;
 		rc_port[i].magic = RISCOM8_MAGIC;
 		rc_port[i].tqueue.routine = do_softint;
@@ -1831,7 +1773,6 @@
 	remove_bh(RISCOM8_BH);
 	free_page((unsigned long)tmp_buf);
 	tty_unregister_driver(&riscom_driver);
-	tty_unregister_driver(&riscom_callout_driver);
 	restore_flags(flags);
 }
 
diff -Nru a/drivers/char/riscom8.h b/drivers/char/riscom8.h
--- a/drivers/char/riscom8.h	Tue Feb  5 09:40:05 2002
+++ b/drivers/char/riscom8.h	Mon May 26 15:29:11 2003
@@ -74,15 +74,12 @@
 	long			event; /* long req'd for set_bit --RR */
 	int			timeout;
 	int			close_delay;
-	long			session;
-	long			pgrp;
 	unsigned char 		* xmit_buf;
 	int			custom_divisor;
 	int			xmit_head;
 	int			xmit_tail;
 	int			xmit_cnt;
 	struct termios          normal_termios;
-	struct termios		callout_termios;
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
 	struct tq_struct	tqueue;
diff -Nru a/drivers/char/rocket.c b/drivers/char/rocket.c
--- a/drivers/char/rocket.c	Wed May  7 07:23:51 2003
+++ b/drivers/char/rocket.c	Mon May 26 15:29:15 2003
@@ -120,7 +120,7 @@
 static void rp_wait_until_sent(struct tty_struct *tty, int timeout);
 static void rp_flush_buffer(struct tty_struct *tty);
 
-static struct tty_driver rocket_driver, callout_driver;
+static struct tty_driver rocket_driver;
 static int rocket_refcount;
 
 static int rp_num_ports_open;
@@ -410,10 +410,7 @@
 		printk("ttyR%d CD now %s...", info->line,
 		       (ChanStatus & CD_ACT) ? "on" : "off");
 #endif
-		if (!(ChanStatus & CD_ACT) &&
-		    info->cd_status &&
-		    !((info->flags & ROCKET_CALLOUT_ACTIVE) &&
-		      (info->flags & ROCKET_CALLOUT_NOHUP))) {
+		if (!(ChanStatus & CD_ACT) && info->cd_status) {
 #ifdef ROCKET_DEBUG_HANGUP
 			printk("CD drop, calling hangup.\n");
 #endif
@@ -551,7 +548,6 @@
 	info->chan = chan;
 	info->closing_wait = 3000;
 	info->close_delay = 50;
-	info->callout_termios =callout_driver.init_termios;
 	info->normal_termios = rocket_driver.init_termios;
 	init_waitqueue_head(&info->open_wait);
 	init_waitqueue_head(&info->close_wait);
@@ -707,44 +703,18 @@
 	}
 
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ROCKET_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ROCKET_CALLOUT_ACTIVE) &&
-		    (info->flags & ROCKET_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ROCKET_CALLOUT_ACTIVE) &&
-		    (info->flags & ROCKET_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ROCKET_CALLOUT_ACTIVE;
-		return 0;
-	}
-	
-	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & ROCKET_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ROCKET_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & ROCKET_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -766,8 +736,7 @@
 	restore_flags(flags);
 	info->blocked_open++;
 	while (1) {
-		if (!(info->flags & ROCKET_CALLOUT_ACTIVE) &&
-		    (tty->termios->c_cflag & CBAUD)) {
+		if ((tty->termios->c_cflag & CBAUD)) {
 			sSetDTR(&info->channel);
 			sSetRTS(&info->channel);
 		}
@@ -780,8 +749,7 @@
 				retval = -ERESTARTSYS;	
 			break;
 		}
-		if (!(info->flags & ROCKET_CALLOUT_ACTIVE) &&
-		    !(info->flags & ROCKET_CLOSING) &&
+		if (!(info->flags & ROCKET_CLOSING) &&
 		    (do_clocal || (sGetChanStatusLo(&info->channel) &
 				   CD_ACT)))
 			break;
@@ -885,8 +853,6 @@
 	/*
 	 * Info->count is now 1; so it's safe to sleep now.
 	 */
-	info->session = current->session;
-	info->pgrp = current->pgrp;
 	
 	cp = &info->channel;
 	sSetRxTrigger(cp, TRIG_1);
@@ -943,10 +909,7 @@
 	}
 
 	if ((info->count == 1) && (info->flags & ROCKET_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->normal_termios;
-		else 
-			*tty->termios = info->callout_termios;
+		*tty->termios = info->normal_termios;
 		configure_r_port(info);
 	}
 
@@ -1001,8 +964,6 @@
 	 */
 	if (info->flags & ROCKET_NORMAL_ACTIVE)
 		info->normal_termios = *tty->termios;
-	if (info->flags & ROCKET_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
 	
 	cp = &info->channel;
 
@@ -1063,8 +1024,7 @@
 			info->xmit_buf = 0;
 		}
 	}
-	info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING |
-			 ROCKET_CALLOUT_ACTIVE | ROCKET_NORMAL_ACTIVE);
+	info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING | ROCKET_NORMAL_ACTIVE);
 	tty->closing = 0;
 	wake_up_interruptible(&info->close_wait);
 	
@@ -1270,7 +1230,7 @@
 		return -EFAULT;
 	memset(&tmp, 0, sizeof(tmp));
 	tmp.tty_major = rocket_driver.major;
-	tmp.callout_major = callout_driver.major;
+	tmp.callout_major = 0;
 	for (board = 0; board < 4; board++) {
 		index = board << 5;
 		for (port = 0; port < 32; port++, index++) {
@@ -1503,7 +1463,7 @@
 	
 	xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f));
 	info->count = 0;
-	info->flags &= ~(ROCKET_NORMAL_ACTIVE|ROCKET_CALLOUT_ACTIVE);
+	info->flags &= ~ROCKET_NORMAL_ACTIVE;
 	info->tty = 0;
 
 	cp = &info->channel;
@@ -2041,28 +2001,6 @@
 	rocket_driver.send_xchar = rp_send_xchar;
 	rocket_driver.wait_until_sent = rp_wait_until_sent;
 
-	/*
-	 * The callout device is just like normal device except for
-	 * the minor number and the subtype code.
-	 */
-	callout_driver = rocket_driver;
-#ifdef CONFIG_DEVFS_FS
-	callout_driver.name = "cua/R";
-#else
-	callout_driver.name = "cur";
-#endif
-	callout_driver.major = CUA_ROCKET_MAJOR;
-	callout_driver.minor_start = 0;
-	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-	
-	retval = tty_register_driver(&callout_driver);
-	if (retval < 0) {
-		printk("Couldn't install Rocketport callout driver "
-		       "(error %d)\n", -retval);
-		release_region(controller, 4);
-		return -1;
-	}
-
 	retval = tty_register_driver(&rocket_driver);
 	if (retval < 0) {
 		printk("Couldn't install tty Rocketport driver "
@@ -2071,8 +2009,8 @@
 		return -1;
 	}
 #ifdef ROCKET_DEBUG_OPEN
-	printk("Rocketport driver is major %d, callout is %d\n",
-	       rocket_driver.major, callout_driver.major);
+	printk("Rocketport driver is major %d\n",
+	       rocket_driver.major);
 #endif
 
 	return 0;
@@ -2092,11 +2030,6 @@
 
 	del_timer_sync(&rocket_timer);
 
-	retval = tty_unregister_driver(&callout_driver);
-	if (retval) {
-		printk("Error %d while trying to unregister "
-		       "rocketport callout driver\n", -retval);
-	}
 	retval = tty_unregister_driver(&rocket_driver);
 	if (retval) {
 		printk("Error %d while trying to unregister "
diff -Nru a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h
--- a/drivers/char/rocket_int.h	Tue Feb 25 10:47:06 2003
+++ b/drivers/char/rocket_int.h	Mon May 26 15:29:16 2003
@@ -1135,14 +1135,11 @@
 	int			xmit_head;
 	int			xmit_tail;
 	int			xmit_cnt;
-	int			session;
-	int			pgrp;
 	int			cd_status;
 	int		        ignore_status_mask;
 	int			read_status_mask;
 	int			cps;
 	struct termios		normal_termios;
-	struct termios		callout_termios;
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
 };
@@ -1171,7 +1168,6 @@
  *
  */
 #define SERIAL_TYPE_NORMAL 1
-#define SERIAL_TYPE_CALLOUT 2
 
 /*
  * Assigned major numbers for the Comtrol Rocketport
diff -Nru a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c
--- a/drivers/char/ser_a2232.c	Fri May  9 03:21:31 2003
+++ b/drivers/char/ser_a2232.c	Mon May 26 15:29:26 2003
@@ -172,7 +172,6 @@
 
 /* TTY driver structs */
 static struct tty_driver a2232_driver;
-static struct tty_driver a2232_callout_driver;
 
 /* Variables used by the TTY driver */
 static int a2232_refcount;
@@ -474,16 +473,10 @@
 	}
 
 	if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)){
-		if (tty->driver->subtype == A2232_TTY_SUBTYPE_NORMAL)
-			*tty->termios = port->gs.normal_termios;
-		else 
-			*tty->termios = port->gs.callout_termios;
+		*tty->termios = port->gs.normal_termios;
 		a2232_set_real_termios (port);
 	}
 
-	port->gs.session = current->session;
-	port->gs.pgrp = current->pgrp;
-
 	a2232_enable_rx_interrupts(port);
 	
 	return 0;
@@ -649,18 +642,13 @@
 						if (!(port->gs.flags & ASYNC_CHECK_CD))
 							;	/* Don't report DCD changes */
 						else if (port->cd_status) { // if DCD on: DCD went UP!
-							if (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) ||
-							    ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) {
-								/* Are we blocking in open?*/
-								wake_up_interruptible(&port->gs.open_wait);
-							}
+							
+							/* Are we blocking in open?*/
+							wake_up_interruptible(&port->gs.open_wait);
 						}
 						else { // if DCD off: DCD went DOWN!
-							if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) &&
-							      (port->gs.flags & ASYNC_CALLOUT_NOHUP))) {
-								if (port->gs.tty)
-									tty_hangup (port->gs.tty);
-							}
+							if (port->gs.tty)
+								tty_hangup (port->gs.tty);
 						}
 						
 					} // if CD changed for this port
@@ -686,7 +674,6 @@
 		port->which_a2232 = i/NUMLINES;
 		port->which_port_on_a2232 = i%NUMLINES;
 		port->disable_rx = port->throttle_input = port->cd_status = 0;
-		port->gs.callout_termios = tty_std_termios;
 		port->gs.normal_termios = tty_std_termios;
 		port->gs.magic = A2232_MAGIC;
 		port->gs.close_delay = HZ/2;
@@ -712,7 +699,7 @@
 	a2232_driver.major = A2232_NORMAL_MAJOR;
 	a2232_driver.num = NUMLINES * nr_a2232;
 	a2232_driver.type = TTY_DRIVER_TYPE_SERIAL;
-	a2232_driver.subtype = A2232_TTY_SUBTYPE_NORMAL;
+	a2232_driver.subtype = SERIAL_TTY_NORMAL;
 	a2232_driver.init_termios = tty_std_termios;
 	a2232_driver.init_termios.c_cflag =
 		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
@@ -738,22 +725,11 @@
 	a2232_driver.start = gs_start;
 	a2232_driver.hangup = gs_hangup;
 
-	a2232_callout_driver = a2232_driver;
-	a2232_callout_driver.name = "cuy";
-	a2232_callout_driver.major = A2232_CALLOUT_MAJOR;
-	a2232_callout_driver.subtype = A2232_TTY_SUBTYPE_CALLOUT;
-
 	if ((error = tty_register_driver(&a2232_driver))) {
 		printk(KERN_ERR "A2232: Couldn't register A2232 driver, error = %d\n",
 		       error);
 		return 1;
 	}
-	if ((error = tty_register_driver(&a2232_callout_driver))) {
-		tty_unregister_driver(&a2232_driver);
-		printk(KERN_ERR "A2232: Couldn't register A2232 callout driver, error = %d\n",
-		       error);
-		return 1;
-	}
 	return 0;
 }
 
@@ -865,7 +841,6 @@
 	}
 
 	tty_unregister_driver(&a2232_driver);
-	tty_unregister_driver(&a2232_callout_driver);
 	free_irq(IRQ_AMIGA_VERTB, a2232_driver_ID);
 }
 #endif
diff -Nru a/drivers/char/ser_a2232.h b/drivers/char/ser_a2232.h
--- a/drivers/char/ser_a2232.h	Tue Feb  5 11:10:31 2002
+++ b/drivers/char/ser_a2232.h	Mon May 26 15:29:26 2003
@@ -49,10 +49,6 @@
 /* Some magic is always good - Who knows :) */
 #define A2232_MAGIC 0x000a2232
 
-/* for the tty_struct subtype field */
-#define A2232_TTY_SUBTYPE_NORMAL	1
-#define A2232_TTY_SUBTYPE_CALLOUT	2
-
 /* A2232 port structure to keep track of the
    status of every single line used */
 struct a2232_port{
diff -Nru a/drivers/char/serial167.c b/drivers/char/serial167.c
--- a/drivers/char/serial167.c	Fri May  9 03:21:31 2003
+++ b/drivers/char/serial167.c	Mon May 26 15:29:15 2003
@@ -97,12 +97,10 @@
 #define STD_COM_FLAGS (0)
 
 #define SERIAL_TYPE_NORMAL  1
-#define SERIAL_TYPE_CALLOUT 2
-
 
 DECLARE_TASK_QUEUE(tq_cyclades);
 
-struct tty_driver cy_serial_driver, cy_callout_driver;
+struct tty_driver cy_serial_driver;
 extern int serial_console;
 static struct cyclades_port *serial_console_info = NULL;
 static unsigned int serial_console_cflag = 0;
@@ -517,8 +515,7 @@
 	    if(mdm_status & CyDCD){
 /* CP('!'); */
 		cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP);
-	    }else if(!((info->flags & ASYNC_CALLOUT_ACTIVE)
-		     &&(info->flags & ASYNC_CALLOUT_NOHUP))){
+	    } else {
 /* CP('@'); */
 		cy_sched_event(info, Cy_EVENT_HANGUP);
 	    }
@@ -769,8 +766,7 @@
     if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
 	tty_hangup(info->tty);
 	wake_up_interruptible(&info->open_wait);
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|
-			     ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
     }
     if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) {
 	wake_up_interruptible(&info->open_wait);
@@ -1912,8 +1908,6 @@
      */
     if (info->flags & ASYNC_NORMAL_ACTIVE)
 	info->normal_termios = *tty->termios;
-    if (info->flags & ASYNC_CALLOUT_ACTIVE)
-	info->callout_termios = *tty->termios;
     if (info->flags & ASYNC_INITIALIZED)
 	tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
     shutdown(info);
@@ -1938,8 +1932,7 @@
 	}
 	wake_up_interruptible(&info->open_wait);
     }
-    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-		     ASYNC_CLOSING);
+    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
     wake_up_interruptible(&info->close_wait);
 
 #ifdef SERIAL_DEBUG_OTHER
@@ -1973,7 +1966,7 @@
 #endif
     info->tty = 0;
 #endif
-    info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+    info->flags &= ~ASYNC_NORMAL_ACTIVE;
     wake_up_interruptible(&info->open_wait);
 } /* cy_hangup */
 
@@ -2009,35 +2002,10 @@
     }
 
     /*
-     * If this is a callout device, then just make sure the normal
-     * device isn't being used.
-     */
-    if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-	if (info->flags & ASYNC_NORMAL_ACTIVE){
-	    return -EBUSY;
-	}
-	if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-	    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-	    (info->session != current->session)){
-	    return -EBUSY;
-	}
-	if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-	    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-	    (info->pgrp != current->pgrp)){
-	    return -EBUSY;
-	}
-	info->flags |= ASYNC_CALLOUT_ACTIVE;
-	return 0;
-    }
-
-    /*
      * If non-blocking mode is set, then make the check up front
      * and then exit.
      */
     if (filp->f_flags & O_NONBLOCK) {
-	if (info->flags & ASYNC_CALLOUT_ACTIVE){
-	    return -EBUSY;
-	}
 	info->flags |= ASYNC_NORMAL_ACTIVE;
 	return 0;
     }
@@ -2065,16 +2033,14 @@
 
     while (1) {
 	local_irq_save(flags);
-	    if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){
-		base_addr[CyCAR] = (u_char)channel;
-		base_addr[CyMSVR1] = CyRTS;
+	base_addr[CyCAR] = (u_char)channel;
+	base_addr[CyMSVR1] = CyRTS;
 /* CP('S');CP('4'); */
-		base_addr[CyMSVR2] = CyDTR;
+	base_addr[CyMSVR2] = CyDTR;
 #ifdef SERIAL_DEBUG_DTR
-                printk("cyc: %d: raising DTR\n", __LINE__);
-                printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
+	printk("cyc: %d: raising DTR\n", __LINE__);
+	printk("     status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);
 #endif
-	    }
 	local_irq_restore(flags);
 	set_current_state(TASK_INTERRUPTIBLE);
 	if (tty_hung_up_p(filp)
@@ -2089,8 +2055,7 @@
 	local_irq_save(flags);
 	    base_addr[CyCAR] = (u_char)channel;
 /* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */
-	    if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
-	    && !(info->flags & ASYNC_CLOSING)
+	    if (!(info->flags & ASYNC_CLOSING)
 	    && (C_CLOCAL(tty)
 	        || (base_addr[CyMSVR1] & CyDCD))) {
 		    local_irq_restore(flags);
@@ -2169,10 +2134,7 @@
     }
 
     if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
-	if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-	    *tty->termios = info->normal_termios;
-	else 
-	    *tty->termios = info->callout_termios;
+	*tty->termios = info->normal_termios;
     }
     /*
      * Start up serial port
@@ -2191,9 +2153,6 @@
 	return retval;
     }
 
-    info->session = current->session;
-    info->pgrp = current->pgrp;
-
 #ifdef SERIAL_DEBUG_OPEN
     printk("cy_open done\n");/**/
 #endif
@@ -2434,29 +2393,11 @@
     cy_serial_driver.start = cy_start;
     cy_serial_driver.hangup = cy_hangup;
 
-    /*
-     * The callout device is just like normal device except for
-     * major number and the subtype code.
-     */
-    cy_callout_driver = cy_serial_driver;
-#ifdef CONFIG_DEVFS_FS
-    cy_callout_driver.name = "cua/";
-#else
-    cy_callout_driver.name = "cua";
-#endif
-    cy_callout_driver.major = TTYAUX_MAJOR;
-    cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-
     ret = tty_register_driver(&cy_serial_driver);
     if (ret) {
 	    printk(KERN_ERR "Couldn't register MVME166/7 serial driver\n");
 	    return ret;
     }
-    ret = tty_register_driver(&cy_callout_driver);
-    if (ret) {
-	    printk(KERN_ERR "Couldn't register MVME166/7 callout driver\n");
-	    goto cleanup_serial_driver;
-    }
 
     init_bh(CYCLADES_BH, do_cyclades_bh);
 
@@ -2499,7 +2440,6 @@
 		info->default_timeout = 0;
 		info->tqueue.routine = do_softint;
 		info->tqueue.data = info;
-		info->callout_termios =cy_callout_driver.init_termios;
 		info->normal_termios = cy_serial_driver.init_termios;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
@@ -2530,7 +2470,7 @@
 				"cd2401_errors", cd2401_rxerr_interrupt);
     if (ret) {
 	    printk(KERN_ERR "Could't get cd2401_errors IRQ");
-	    goto cleanup_callout_driver;
+	    goto cleanup_serial_driver;
     }
 
     ret = request_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt, 0,
@@ -2569,9 +2509,6 @@
     free_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt);
 cleanup_irq_cd2401_errors:
     free_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt);
-cleanup_callout_driver:
-    if (tty_unregister_driver(&cy_callout_driver))
-	    printk(KERN_ERR "Couldn't unregister MVME166/7 callout driver\n");
 cleanup_serial_driver:
     if (tty_unregister_driver(&cy_serial_driver))
 	    printk(KERN_ERR "Couldn't unregister MVME166/7 serial driver\n");
@@ -2607,8 +2544,8 @@
              info->close_delay, info->event, info->count);
     printk("  x_char blocked_open = %x %x\n",
              info->x_char, info->blocked_open);
-    printk("  session pgrp open_wait = %lx %lx %lx\n",
-             info->session, info->pgrp, (long)info->open_wait);
+    printk("  open_wait = %lx %lx %lx\n",
+             (long)info->open_wait);
 
 
     local_irq_save(flags);
diff -Nru a/drivers/char/serial_tx3912.c b/drivers/char/serial_tx3912.c
--- a/drivers/char/serial_tx3912.c	Wed May  7 07:23:38 2003
+++ b/drivers/char/serial_tx3912.c	Mon May 26 15:29:12 2003
@@ -59,7 +59,7 @@
 /*
  * Structures and such for TTY sessions and usage counts
  */
-static struct tty_driver rs_driver, rs_callout_driver;
+static struct tty_driver rs_driver;
 static struct tty_struct * rs_table[TX3912_UART_NPORTS] = { NULL, };
 static struct termios ** rs_termios;
 static struct termios ** rs_termios_locked;
@@ -594,15 +594,10 @@
 	/* tty->low_latency = 1; */
 
 	if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = port->gs.normal_termios;
-		else 
-			*tty->termios = port->gs.callout_termios;
+		*tty->termios = port->gs.normal_termios;
 		rs_set_real_termios (port);
 	}
 
-	port->gs.session = current->session;
-	port->gs.pgrp = current->pgrp;
 	func_exit();
 
 	/* Jim */
@@ -773,7 +768,6 @@
 	port = rs_ports;
 	for (i=0; i < TX3912_UART_NPORTS;i++) {
 		rs_dprintk (TX3912_UART_DEBUG_INIT, "initing port %d\n", i);
-		port->gs.callout_termios = tty_std_termios;
 		port->gs.normal_termios	= tty_std_termios;
 		port->gs.magic = SERIAL_MAGIC;
 		port->gs.close_delay = HZ/2;
@@ -837,24 +831,11 @@
 	rs_driver.start = gs_start;
 	rs_driver.hangup = gs_hangup;
 
-	rs_callout_driver = rs_driver;
-	rs_callout_driver.name = "cua";
-	rs_callout_driver.major = TTYAUX_MAJOR;
-	rs_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-
 	if ((error = tty_register_driver(&rs_driver))) {
 		printk(KERN_ERR "Couldn't register serial driver, error = %d\n",
 		       error);
 		return 1;
 	}
-	if ((error = tty_register_driver(&rs_callout_driver))) {
-		tty_unregister_driver(&rs_driver);
-		printk(KERN_ERR "Couldn't register callout driver, error = %d\n",
-		       error);
-		return 1;
-	}
-
-	func_exit();
 	return 0;
 }
 
diff -Nru a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c
--- a/drivers/char/sh-sci.c	Wed May  7 07:23:41 2003
+++ b/drivers/char/sh-sci.c	Mon May 26 15:29:11 2003
@@ -76,7 +76,7 @@
 static void sci_free_irq(struct sci_port *port);
 static int sci_init_drivers(void);
 
-static struct tty_driver sci_driver, sci_callout_driver;
+static struct tty_driver sci_driver;
 
 static struct sci_port sci_ports[SCI_NPORTS] = SCI_INIT;
 static struct tty_struct *sci_table[SCI_NPORTS] = { NULL, };
@@ -844,10 +844,7 @@
 	}
 
 	if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = port->gs.normal_termios;
-		else 
-			*tty->termios = port->gs.callout_termios;
+		*tty->termios = port->gs.normal_termios;
 		sci_set_real_termios(port);
 	}
 
@@ -862,9 +859,6 @@
 
 	sci_enable_rx_interrupts(port);
 
-	port->gs.session = current->session;
-	port->gs.pgrp = current->pgrp;
-
 	return 0;
 
 failed_3:
@@ -1038,30 +1032,13 @@
 	sci_driver.read_proc = sci_read_proc;
 #endif
 
-	sci_callout_driver = sci_driver;
-#ifdef CONFIG_DEVFS_FS
-	sci_callout_driver.name = "cusc/";
-#else
-	sci_callout_driver.name = "cusc";
-#endif
-	sci_callout_driver.major = SCI_MAJOR+1;
-	sci_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-	sci_callout_driver.read_proc = NULL;
-
 	if ((error = tty_register_driver(&sci_driver))) {
 		printk(KERN_ERR "sci: Couldn't register SCI driver, error = %d\n",
 		       error);
 		return 1;
 	}
-	if ((error = tty_register_driver(&sci_callout_driver))) {
-		tty_unregister_driver(&sci_driver);
-		printk(KERN_ERR "sci: Couldn't register SCI callout driver, error = %d\n",
-		       error);
-		return 1;
-	}
 
 	for (port = &sci_ports[0]; port < &sci_ports[SCI_NPORTS]; port++) {
-		port->gs.callout_termios = sci_callout_driver.init_termios;
 		port->gs.normal_termios	= sci_driver.init_termios;
 		port->gs.magic = SCI_MAGIC;
 		port->gs.close_delay = HZ/2;
@@ -1142,7 +1119,6 @@
 void cleanup_module(void)
 {
 	tty_unregister_driver(&sci_driver);
-	tty_unregister_driver(&sci_callout_driver);
 }
 
 #include "generic_serial.c"
diff -Nru a/drivers/char/specialix.c b/drivers/char/specialix.c
--- a/drivers/char/specialix.c	Wed May  7 07:23:29 2003
+++ b/drivers/char/specialix.c	Mon May 26 15:29:26 2003
@@ -176,10 +176,7 @@
 #undef RS_EVENT_WRITE_WAKEUP
 #define RS_EVENT_WRITE_WAKEUP	0
 
-#define SPECIALIX_TYPE_NORMAL	1
-#define SPECIALIX_TYPE_CALLOUT	2
-
-static struct tty_driver specialix_driver, specialix_callout_driver;
+static struct tty_driver specialix_driver;
 static int    specialix_refcount;
 static struct tty_struct * specialix_table[SX_NBOARD * SX_NPORT];
 static struct termios * specialix_termios[SX_NBOARD * SX_NPORT];
@@ -827,17 +824,11 @@
 			printk ( "Waking up guys in open.\n");
 #endif
 			wake_up_interruptible(&port->open_wait);
-		}
-		else if (!((port->flags & ASYNC_CALLOUT_ACTIVE) &&
-		           (port->flags & ASYNC_CALLOUT_NOHUP))) {
+		} else {
 #ifdef SPECIALIX_DEBUG
 			printk ( "Sending HUP.\n");
 #endif
 			schedule_task(&port->tqueue_hangup);
-		} else {
-#ifdef SPECIALIX_DEBUG
-			printk ( "Don't need to send HUP.\n");
-#endif
 		}
 	}
 	
@@ -1341,25 +1332,6 @@
 		else
 			return -ERESTARTSYS;
 	}
-
-	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SPECIALIX_TYPE_CALLOUT) {
-		if (port->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (port->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (port->session != current->session))
-			return -EBUSY;
-		if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (port->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (port->pgrp != current->pgrp))
-			return -EBUSY;
-		port->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
 	
 	/*
 	 * If non-blocking mode is set, or the port is not enabled,
@@ -1367,20 +1339,13 @@
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (port->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		port->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (port->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (port->normal_termios.c_cflag & CLOCAL) 
-			do_clocal = 1;
-	} else {
-		if (C_CLOCAL(tty))
-			do_clocal = 1;
-	}
-	
+	if (C_CLOCAL(tty))
+		do_clocal = 1;
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -1399,17 +1364,15 @@
 		cli();
 		sx_out(bp, CD186x_CAR, port_No(port));
 		CD = sx_in(bp, CD186x_MSVR) & MSVR_CD;
-		if (!(port->flags & ASYNC_CALLOUT_ACTIVE)) {
-			if (SX_CRTSCTS (tty)) {
-				/* Activate RTS */
-				port->MSVR |= MSVR_DTR;
-				sx_out (bp, CD186x_MSVR, port->MSVR);
-			} else {
-				/* Activate DTR */
-				port->MSVR |= MSVR_DTR;
-				sx_out (bp, CD186x_MSVR, port->MSVR);
-			} 
-		}
+		if (SX_CRTSCTS (tty)) {
+			/* Activate RTS */
+			port->MSVR |= MSVR_DTR;		/* WTF? */
+			sx_out (bp, CD186x_MSVR, port->MSVR);
+		} else {
+			/* Activate DTR */
+			port->MSVR |= MSVR_DTR;
+			sx_out (bp, CD186x_MSVR, port->MSVR);
+		} 
 		sti();
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) ||
@@ -1420,8 +1383,7 @@
 				retval = -ERESTARTSYS;	
 			break;
 		}
-		if (!(port->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(port->flags & ASYNC_CLOSING) &&
+		if (!(port->flags & ASYNC_CLOSING) &&
 		    (do_clocal || CD))
 			break;
 		if (signal_pending(current)) {
@@ -1481,17 +1443,11 @@
 		return error;
 
 	if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SPECIALIX_TYPE_NORMAL)
-			*tty->termios = port->normal_termios;
-		else
-			*tty->termios = port->callout_termios;
+		*tty->termios = port->normal_termios;
 		save_flags(flags); cli();
 		sx_change_speed(bp, port);
 		restore_flags(flags);
 	}
-
-	port->session = current->session;
-	port->pgrp = current->pgrp;
 	return 0;
 }
 
@@ -1535,8 +1491,6 @@
 	 */
 	if (port->flags & ASYNC_NORMAL_ACTIVE)
 		port->normal_termios = *tty->termios;
-	if (port->flags & ASYNC_CALLOUT_ACTIVE)
-		port->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -1587,8 +1541,7 @@
 		}
 		wake_up_interruptible(&port->open_wait);
 	}
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&port->close_wait);
 	restore_flags(flags);
 }
@@ -2162,7 +2115,7 @@
 	sx_shutdown_port(bp, port);
 	port->event = 0;
 	port->count = 0;
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	port->flags &= ~ASYNC_NORMAL_ACTIVE;
 	port->tty = 0;
 	wake_up_interruptible(&port->open_wait);
 }
@@ -2233,7 +2186,7 @@
 	specialix_driver.major = SPECIALIX_NORMAL_MAJOR;
 	specialix_driver.num = SX_NBOARD * SX_NPORT;
 	specialix_driver.type = TTY_DRIVER_TYPE_SERIAL;
-	specialix_driver.subtype = SPECIALIX_TYPE_NORMAL;
+	specialix_driver.subtype = SERIAL_TYPE_NORMAL;
 	specialix_driver.init_termios = tty_std_termios;
 	specialix_driver.init_termios.c_cflag =
 		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
@@ -2259,28 +2212,14 @@
 	specialix_driver.start = sx_start;
 	specialix_driver.hangup = sx_hangup;
 
-	specialix_callout_driver = specialix_driver;
-	specialix_callout_driver.name = "cuw";
-	specialix_callout_driver.major = SPECIALIX_CALLOUT_MAJOR;
-	specialix_callout_driver.subtype = SPECIALIX_TYPE_CALLOUT;
-	
 	if ((error = tty_register_driver(&specialix_driver))) {
 		free_page((unsigned long)tmp_buf);
 		printk(KERN_ERR "sx: Couldn't register specialix IO8+ driver, error = %d\n",
 		       error);
 		return 1;
 	}
-	if ((error = tty_register_driver(&specialix_callout_driver))) {
-		free_page((unsigned long)tmp_buf);
-		tty_unregister_driver(&specialix_driver);
-		printk(KERN_ERR "sx: Couldn't register specialix IO8+ callout driver, error = %d\n",
-		       error);
-		return 1;
-	}
-	
 	memset(sx_port, 0, sizeof(sx_port));
 	for (i = 0; i < SX_NPORT * SX_NBOARD; i++) {
-		sx_port[i].callout_termios = specialix_callout_driver.init_termios;
 		sx_port[i].normal_termios  = specialix_driver.init_termios;
 		sx_port[i].magic = SPECIALIX_MAGIC;
 		sx_port[i].tqueue.routine = do_softint;
@@ -2301,7 +2240,6 @@
 {
 	free_page((unsigned long)tmp_buf);
 	tty_unregister_driver(&specialix_driver);
-	tty_unregister_driver(&specialix_callout_driver);
 }
 
 
diff -Nru a/drivers/char/specialix_io8.h b/drivers/char/specialix_io8.h
--- a/drivers/char/specialix_io8.h	Sun Jul 21 08:35:45 2002
+++ b/drivers/char/specialix_io8.h	Mon May 26 15:29:10 2003
@@ -113,15 +113,12 @@
 	ulong			event;
 	int			timeout;
 	int			close_delay;
-	long			session;
-	long			pgrp;
 	unsigned char 		* xmit_buf;
 	int			custom_divisor;
 	int			xmit_head;
 	int			xmit_tail;
 	int			xmit_cnt;
 	struct termios          normal_termios;
-	struct termios		callout_termios;
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
 	struct tq_struct	tqueue;
diff -Nru a/drivers/char/stallion.c b/drivers/char/stallion.c
--- a/drivers/char/stallion.c	Wed May  7 23:16:25 2003
+++ b/drivers/char/stallion.c	Mon May 26 15:29:26 2003
@@ -120,9 +120,6 @@
 #define	STL_CALLOUTMAJOR	25
 #endif
 
-#define	STL_DRVTYPSERIAL	1
-#define	STL_DRVTYPCALLOUT	2
-
 /*
  *	Set the TX buffer size. Bigger is better, but we don't want
  *	to chew too much memory with buffers!
@@ -141,14 +138,11 @@
 static char	*stl_drvversion = "5.6.0";
 #ifdef CONFIG_DEVFS_FS
 static char	*stl_serialname = "tts/E%d";
-static char	*stl_calloutname = "cua/E%d";
 #else
 static char	*stl_serialname = "ttyE";
-static char	*stl_calloutname = "cue";
 #endif
 
 static struct tty_driver	stl_serial;
-static struct tty_driver	stl_callout;
 static struct tty_struct	*stl_ttys[STL_MAXDEVS];
 static struct termios		*stl_termios[STL_MAXDEVS];
 static struct termios		*stl_termioslocked[STL_MAXDEVS];
@@ -799,10 +793,9 @@
  *	hanging onto ports.
  */
 	i = tty_unregister_driver(&stl_serial);
-	j = tty_unregister_driver(&stl_callout);
-	if (i || j) {
+	if (i) {
 		printk("STALLION: failed to un-register tty driver, "
-			"errno=%d,%d\n", -i, -j);
+			"errno=%d\n", -i);
 		restore_flags(flags);
 		return;
 	}
@@ -1087,39 +1080,16 @@
  *	previous opens still in effect. If we are a normal serial device
  *	then also we might have to wait for carrier.
  */
-	if (tty->driver->subtype == STL_DRVTYPCALLOUT) {
-		if (portp->flags & ASYNC_NORMAL_ACTIVE)
-			return(-EBUSY);
-		if (portp->flags & ASYNC_CALLOUT_ACTIVE) {
-			if ((portp->flags & ASYNC_SESSION_LOCKOUT) &&
-			    (portp->session != current->session))
-				return(-EBUSY);
-			if ((portp->flags & ASYNC_PGRP_LOCKOUT) &&
-			    (portp->pgrp != current->pgrp))
-				return(-EBUSY);
-		}
-		portp->flags |= ASYNC_CALLOUT_ACTIVE;
-	} else {
-		if (filp->f_flags & O_NONBLOCK) {
-			if (portp->flags & ASYNC_CALLOUT_ACTIVE)
-				return(-EBUSY);
-		} else {
-			if ((rc = stl_waitcarrier(portp, filp)) != 0)
-				return(rc);
-		}
-		portp->flags |= ASYNC_NORMAL_ACTIVE;
+	if (!(filp->f_flags & O_NONBLOCK)) {
+		if ((rc = stl_waitcarrier(portp, filp)) != 0)
+			return(rc);
 	}
+	portp->flags |= ASYNC_NORMAL_ACTIVE;
 
 	if ((portp->refcount == 1) && (portp->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == STL_DRVTYPSERIAL)
-			*tty->termios = portp->normaltermios;
-		else
-			*tty->termios = portp->callouttermios;
+		*tty->termios = portp->normaltermios;
 		stl_setport(portp, tty->termios);
 	}
-
-	portp->session = current->session;
-	portp->pgrp = current->pgrp;
 	return(0);
 }
 
@@ -1142,13 +1112,8 @@
 	rc = 0;
 	doclocal = 0;
 
-	if (portp->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (portp->normaltermios.c_cflag & CLOCAL)
-			doclocal++;
-	} else {
-		if (portp->tty->termios->c_cflag & CLOCAL)
-			doclocal++;
-	}
+	if (portp->tty->termios->c_cflag & CLOCAL)
+		doclocal++;
 
 	save_flags(flags);
 	cli();
@@ -1157,8 +1122,7 @@
 		portp->refcount--;
 
 	for (;;) {
-		if ((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0)
-			stl_setsignals(portp, 1, 1);
+		stl_setsignals(portp, 1, 1);
 		if (tty_hung_up_p(filp) ||
 		    ((portp->flags & ASYNC_INITIALIZED) == 0)) {
 			if (portp->flags & ASYNC_HUP_NOTIFY)
@@ -1167,8 +1131,7 @@
 				rc = -ERESTARTSYS;
 			break;
 		}
-		if (((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) &&
-		    ((portp->flags & ASYNC_CLOSING) == 0) &&
+		if (((portp->flags & ASYNC_CLOSING) == 0) &&
 		    (doclocal || (portp->sigs & TIOCM_CD))) {
 			break;
 		}
@@ -1220,8 +1183,6 @@
 
 	if (portp->flags & ASYNC_NORMAL_ACTIVE)
 		portp->normaltermios = *tty->termios;
-	if (portp->flags & ASYNC_CALLOUT_ACTIVE)
-		portp->callouttermios = *tty->termios;
 
 /*
  *	May want to wait for any data to drain before closing. The BUSY
@@ -1260,8 +1221,7 @@
 		wake_up_interruptible(&portp->open_wait);
 	}
 
-	portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE |
-		ASYNC_CLOSING);
+	portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&portp->close_wait);
 	restore_flags(flags);
 }
@@ -1838,7 +1798,7 @@
 		portp->tx.tail = (char *) NULL;
 	}
 	portp->tty = (struct tty_struct *) NULL;
-	portp->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+	portp->flags &= ~ASYNC_NORMAL_ACTIVE;
 	portp->refcount = 0;
 	wake_up_interruptible(&portp->open_wait);
 }
@@ -2256,12 +2216,8 @@
 		if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0))
 			wake_up_interruptible(&portp->open_wait);
 		if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) {
-			if (portp->flags & ASYNC_CHECK_CD) {
-				if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) &&
-				    (portp->flags & ASYNC_CALLOUT_NOHUP))) {
-					tty_hangup(tty);	/* FIXME: module removal race here - AKPM */
-				}
-			}
+			if (portp->flags & ASYNC_CHECK_CD)
+				tty_hangup(tty);	/* FIXME: module removal race here - AKPM */
 		}
 	}
 	unlock_kernel();
@@ -2340,7 +2296,6 @@
 		portp->close_delay = STL_CLOSEDELAY;
 		portp->closing_wait = 30 * HZ;
 		portp->normaltermios = stl_deftermios;
-		portp->callouttermios = stl_deftermios;
 		INIT_WORK(&portp->tqueue, stl_offintr, portp);
 		init_waitqueue_head(&portp->open_wait);
 		init_waitqueue_head(&portp->close_wait);
@@ -3218,7 +3173,6 @@
 
 /*
  *	Set up the tty driver structure and register us as a driver.
- *	Also setup the callout tty device.
  */
 	memset(&stl_serial, 0, sizeof(struct tty_driver));
 	stl_serial.magic = TTY_DRIVER_MAGIC;
@@ -3229,7 +3183,7 @@
 	stl_serial.minor_start = 0;
 	stl_serial.num = STL_MAXBRDS * STL_MAXPORTS;
 	stl_serial.type = TTY_DRIVER_TYPE_SERIAL;
-	stl_serial.subtype = STL_DRVTYPSERIAL;
+	stl_serial.subtype = SERIAL_TYPE_NORMAL;
 	stl_serial.init_termios = stl_deftermios;
 	stl_serial.flags = TTY_DRIVER_REAL_RAW;
 	stl_serial.refcount = &stl_refcount;
@@ -3257,16 +3211,8 @@
 	stl_serial.send_xchar = stl_sendxchar;
 	stl_serial.read_proc = stl_readproc;
 
-	stl_callout = stl_serial;
-	stl_callout.name = stl_calloutname;
-	stl_callout.major = STL_CALLOUTMAJOR;
-	stl_callout.subtype = STL_DRVTYPCALLOUT;
-	stl_callout.read_proc = 0;
-
 	if (tty_register_driver(&stl_serial))
 		printk("STALLION: failed to register serial driver\n");
-	if (tty_register_driver(&stl_callout))
-		printk("STALLION: failed to register callout driver\n");
 
 	return(0);
 }
diff -Nru a/drivers/char/sx.c b/drivers/char/sx.c
--- a/drivers/char/sx.c	Sun May 25 23:18:34 2003
+++ b/drivers/char/sx.c	Mon May 26 15:29:26 2003
@@ -249,12 +249,6 @@
    one machine. You'll have to increase the number of boards in sx.h
    if you want more than 4 boards.  */
 
-
-/* Why the hell am I defining these here? */
-#define SX_TYPE_NORMAL 1
-#define SX_TYPE_CALLOUT 2
-
-
 #ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8
 #define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
 #endif
@@ -314,7 +308,7 @@
 static int sx_init_drivers(void);
 
 
-static struct tty_driver sx_driver, sx_callout_driver;
+static struct tty_driver sx_driver;
 
 static struct tty_struct * sx_table[SX_NPORTS];
 static struct termios ** sx_termios;
@@ -1168,9 +1162,7 @@
 			port->c_dcd = c_dcd;
 			if (sx_get_CD (port)) {
 				/* DCD went UP */
-				if( (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) || 
-						 ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) &&
-						(sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED) &&
+				if ((sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED) &&
 						!(port->gs.tty->termios->c_cflag & CLOCAL) ) {
 					/* Are we blocking in open?*/
 					sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD active, unblocking open\n");
@@ -1180,9 +1172,7 @@
 				}
 			} else {
 				/* DCD went down! */
-				if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) &&
-				      (port->gs.flags & ASYNC_CALLOUT_NOHUP)) &&
-				    !(port->gs.tty->termios->c_cflag & CLOCAL) ) {
+				if (!(port->gs.tty->termios->c_cflag & CLOCAL) ) {
 					sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. hanging up....\n");
 					tty_hangup (port->gs.tty);
 				} else {
@@ -1497,15 +1487,10 @@
 	/* tty->low_latency = 1; */
 
 	if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = port->gs.normal_termios;
-		else 
-			*tty->termios = port->gs.callout_termios;
+		*tty->termios = port->gs.normal_termios;
 		sx_set_real_termios (port);
 	}
 
-	port->gs.session = current->session;
-	port->gs.pgrp = current->pgrp;
 	port->c_dcd = sx_get_CD (port);
 	sx_dprintk (SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd);
 	func_exit();
@@ -2250,7 +2235,7 @@
 	sx_driver.major = SX_NORMAL_MAJOR;
 	sx_driver.num = sx_nports;
 	sx_driver.type = TTY_DRIVER_TYPE_SERIAL;
-	sx_driver.subtype = SX_TYPE_NORMAL;
+	sx_driver.subtype = SERIAL_TYPE_NORMAL;
 	sx_driver.init_termios = tty_std_termios;
 	sx_driver.init_termios.c_cflag =
 	  B9600 | CS8 | CREAD | HUPCL | CLOCAL;
@@ -2277,23 +2262,11 @@
 	sx_driver.start = gs_start;
 	sx_driver.hangup = gs_hangup;
 
-	sx_callout_driver = sx_driver;
-	sx_callout_driver.name = "cux";
-	sx_callout_driver.major = SX_CALLOUT_MAJOR;
-	sx_callout_driver.subtype = SX_TYPE_CALLOUT;
-
 	if ((error = tty_register_driver(&sx_driver))) {
 		printk(KERN_ERR "sx: Couldn't register sx driver, error = %d\n",
 		       error);
 		return 1;
 	}
-	if ((error = tty_register_driver(&sx_callout_driver))) {
-		tty_unregister_driver(&sx_driver);
-		printk(KERN_ERR "sx: Couldn't register sx callout driver, error = %d\n",
-		       error);
-		return 1;
-	}
-
 	func_exit();
 	return 0;
 }
@@ -2349,7 +2322,6 @@
 		board->ports = port;
 		for (j=0; j < boards[i].nports;j++) {
 			sx_dprintk (SX_DEBUG_INIT, "initing port %d\n", j);
-			port->gs.callout_termios = tty_std_termios;
 			port->gs.normal_termios	= tty_std_termios;
 			port->gs.magic = SX_MAGIC;
 			port->gs.close_delay = HZ/2;
@@ -2410,7 +2382,6 @@
 {
 	func_enter();
 	tty_unregister_driver(&sx_driver);
-	tty_unregister_driver(&sx_callout_driver);
 	func_exit();
 }
 
diff -Nru a/drivers/char/synclink.c b/drivers/char/synclink.c
--- a/drivers/char/synclink.c	Tue May  6 14:29:47 2003
+++ b/drivers/char/synclink.c	Mon May 26 15:29:15 2003
@@ -200,14 +200,11 @@
 	struct mgsl_icount	icount;
 	
 	struct termios		normal_termios;
-	struct termios		callout_termios;
-	
+
 	struct tty_struct 	*tty;
 	int			timeout;
 	int			x_char;		/* xon/xoff character */
 	int			blocked_open;	/* # of blocked opens */
-	long			session;	/* Session of opening process */
-	long			pgrp;		/* pgrp of opening process */
 	u16			read_status_mask;
 	u16			ignore_status_mask;	
 	unsigned char 		*xmit_buf;
@@ -891,8 +888,6 @@
  */
 static int ttymajor;
 
-static int cuamajor;
-
 /*
  * Array of user specified options for ISA adapters.
  */
@@ -907,7 +902,6 @@
 	
 MODULE_PARM(break_on_load,"i");
 MODULE_PARM(ttymajor,"i");
-MODULE_PARM(cuamajor,"i");
 MODULE_PARM(io,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i");
 MODULE_PARM(irq,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i");
 MODULE_PARM(dma,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i");
@@ -940,7 +934,7 @@
 	.remove		= __devexit_p(synclink_remove_one),
 };
 
-static struct tty_driver serial_driver, callout_driver;
+static struct tty_driver serial_driver;
 static int serial_refcount;
 
 /* number of characters left in xmit buffer before we ask for more */
@@ -1377,8 +1371,7 @@
 				       (status & MISCSTATUS_DCD) ? "on" : "off");
 			if (status & MISCSTATUS_DCD)
 				wake_up_interruptible(&info->open_wait);
-			else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-				   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+			else {
 				if ( debug_level >= DEBUG_LEVEL_ISR )
 					printk("doing serial hangup...");
 				if (info->tty)
@@ -3218,9 +3211,7 @@
 	 */
 	if (info->flags & ASYNC_NORMAL_ACTIVE)
 		info->normal_termios = *tty->termios;
-	if (info->flags & ASYNC_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
-		
+
 	/* set tty->closing to notify line discipline to 
 	 * only process XON/XOFF characters. Only the N_TTY
 	 * discipline appears to use this (ppp does not).
@@ -3258,8 +3249,7 @@
 		wake_up_interruptible(&info->open_wait);
 	}
 	
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 			 
 	wake_up_interruptible(&info->close_wait);
 	
@@ -3369,7 +3359,7 @@
 	shutdown(info);
 	
 	info->count = 0;	
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->tty = 0;
 
 	wake_up_interruptible(&info->open_wait);
@@ -3401,40 +3391,15 @@
 		printk("%s(%d):block_til_ready on %s\n",
 			 __FILE__,__LINE__, tty->driver->name );
 
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		/* this is a callout device */
-		/* just verify that normal device is not in use */
-		if (info->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-	
 	if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
 		/* nonblock mode is set or port is not enabled */
-		/* just verify that callout device is not active */
-		if (info->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
+
 	/* Wait for carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
 	 * this loop, info->count is dropped by one, so that
@@ -3458,8 +3423,7 @@
 	info->blocked_open++;
 	
 	while (1) {
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
- 		    (tty->termios->c_cflag & CBAUD)) {
+		if (tty->termios->c_cflag & CBAUD) {
 			spin_lock_irqsave(&info->irq_spinlock,flags);
 			info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
 		 	usc_set_serial_signals(info);
@@ -3478,8 +3442,7 @@
 	 	usc_get_serial_signals(info);
 		spin_unlock_irqrestore(&info->irq_spinlock,flags);
 		
- 		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
- 		    !(info->flags & ASYNC_CLOSING) &&
+ 		if (!(info->flags & ASYNC_CLOSING) &&
  		    (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
  			break;
 		}
@@ -3607,16 +3570,10 @@
 
 	if ((info->count == 1) &&
 	    info->flags & ASYNC_SPLIT_TERMIOS) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->normal_termios;
-		else 
-			*tty->termios = info->callout_termios;
+		*tty->termios = info->normal_termios;
 		mgsl_change_params(info);
 	}
 	
-	info->session = current->session;
-	info->pgrp    = current->pgrp;
-
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgsl_open(%s) success\n",
 			 __FILE__,__LINE__, info->device_name);
@@ -4548,34 +4505,18 @@
 	serial_driver.tiocmget = tiocmget;
 	serial_driver.tiocmset = tiocmset;
 	
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	callout_driver = serial_driver;
-	callout_driver.name = "cuaSL";
-	callout_driver.major = cuamajor;
-	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-	callout_driver.read_proc = 0;
-	callout_driver.proc_entry = 0;
-
 	if (tty_register_driver(&serial_driver) < 0)
 		printk("%s(%d):Couldn't register serial driver\n",
 			__FILE__,__LINE__);
 			
-	if (tty_register_driver(&callout_driver) < 0)
-		printk("%s(%d):Couldn't register callout driver\n",
-			__FILE__,__LINE__);
-
- 	printk("%s %s, tty major#%d callout major#%d\n",
+ 	printk("%s %s, tty major#%d\n",
 		driver_name, driver_version,
-		serial_driver.major, callout_driver.major);
+		serial_driver.major);
 		
 	/* Propagate these values to all device instances */
 	
 	info = mgsl_device_list;
 	while(info){
-		info->callout_termios = callout_driver.init_termios;
 		info->normal_termios  = serial_driver.init_termios;
 		info = info->next_device;
 	}
@@ -4670,9 +4611,6 @@
 
 	if ((rc = tty_unregister_driver(&serial_driver)))
 		printk("%s(%d) failed to unregister tty driver err=%d\n",
-		       __FILE__,__LINE__,rc);
-	if ((rc = tty_unregister_driver(&callout_driver)))
-		printk("%s(%d) failed to unregister callout driver err=%d\n",
 		       __FILE__,__LINE__,rc);
 
 	info = mgsl_device_list;
diff -Nru a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
--- a/drivers/char/synclinkmp.c	Thu Apr 24 05:17:30 2003
+++ b/drivers/char/synclinkmp.c	Mon May 26 15:29:15 2003
@@ -167,14 +167,11 @@
 	struct mgsl_icount	icount;
 
 	struct termios		normal_termios;
-	struct termios		callout_termios;
 
 	struct tty_struct 	*tty;
 	int			timeout;
 	int			x_char;		/* xon/xoff character */
 	int			blocked_open;	/* # of blocked opens */
-	long			session;	/* Session of opening process */
-	long			pgrp;		/* pgrp of opening process */
 	u16			read_status_mask1;  /* break detection (SR1 indications) */
 	u16			read_status_mask2;  /* parity/framing/overun (SR2 indications) */
 	unsigned char 		ignore_status_mask1;  /* break detection (SR1 indications) */
@@ -524,7 +521,7 @@
 };
 
 
-static struct tty_driver serial_driver, callout_driver;
+static struct tty_driver serial_driver;
 static int serial_refcount;
 
 /* number of characters left in xmit buffer before we ask for more */
@@ -807,16 +804,10 @@
 
 	if ((info->count == 1) &&
 	    info->flags & ASYNC_SPLIT_TERMIOS) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->normal_termios;
-		else
-			*tty->termios = info->callout_termios;
+		*tty->termios = info->normal_termios;
 		change_params(info);
 	}
 
-	info->session = current->session;
-	info->pgrp    = current->pgrp;
-
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):%s open() success\n",
 			 __FILE__,__LINE__, info->device_name);
@@ -873,8 +864,6 @@
 	 */
 	if (info->flags & ASYNC_NORMAL_ACTIVE)
 		info->normal_termios = *tty->termios;
-	if (info->flags & ASYNC_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
 
 	/* set tty->closing to notify line discipline to
 	 * only process XON/XOFF characters. Only the N_TTY
@@ -913,8 +902,7 @@
 		wake_up_interruptible(&info->open_wait);
 	}
 
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 
 	wake_up_interruptible(&info->close_wait);
 
@@ -942,7 +930,7 @@
 	shutdown(info);
 
 	info->count = 0;
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->tty = 0;
 
 	wake_up_interruptible(&info->open_wait);
@@ -2402,8 +2390,7 @@
 				       (status & SerialSignal_DCD) ? "on" : "off");
 			if (status & SerialSignal_DCD)
 				wake_up_interruptible(&info->open_wait);
-			else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-				   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+			else {
 				if ( debug_level >= DEBUG_LEVEL_ISR )
 					printk("doing serial hangup...");
 				if (info->tty)
@@ -3202,39 +3189,15 @@
 		printk("%s(%d):%s block_til_ready()\n",
 			 __FILE__,__LINE__, tty->driver->name );
 
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		/* this is a callout device */
-		/* just verify that normal device is not in use */
-		if (info->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-
 	if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
 		/* nonblock mode is set or port is not enabled */
 		/* just verify that callout device is not active */
-		if (info->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
 
 	/* Wait for carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -3259,8 +3222,7 @@
 	info->blocked_open++;
 
 	while (1) {
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
- 		    (tty->termios->c_cflag & CBAUD)) {
+		if ((tty->termios->c_cflag & CBAUD)) {
 			spin_lock_irqsave(&info->lock,flags);
 			info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
 		 	set_signals(info);
@@ -3279,8 +3241,7 @@
 	 	get_signals(info);
 		spin_unlock_irqrestore(&info->lock,flags);
 
- 		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
- 		    !(info->flags & ASYNC_CLOSING) &&
+ 		if (!(info->flags & ASYNC_CLOSING) &&
  		    (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
  			break;
 		}
@@ -3873,34 +3834,18 @@
 	serial_driver.tiocmget = tiocmget;
 	serial_driver.tiocmset = tiocmset;
 
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	callout_driver = serial_driver;
-	callout_driver.name = "cuaSLM";
-	callout_driver.major = cuamajor;
-	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-	callout_driver.read_proc = 0;
-	callout_driver.proc_entry = 0;
-
 	if (tty_register_driver(&serial_driver) < 0)
 		printk("%s(%d):Couldn't register serial driver\n",
 			__FILE__,__LINE__);
 
-	if (tty_register_driver(&callout_driver) < 0)
-		printk("%s(%d):Couldn't register callout driver\n",
-			__FILE__,__LINE__);
-
- 	printk("%s %s, tty major#%d callout major#%d\n",
+ 	printk("%s %s, tty major#%d\n",
 		driver_name, driver_version,
-		serial_driver.major, callout_driver.major);
+		serial_driver.major);
 
 	/* Propagate these values to all device instances */
 
 	info = synclinkmp_device_list;
 	while(info){
-		info->callout_termios = callout_driver.init_termios;
 		info->normal_termios  = serial_driver.init_termios;
 		info = info->next_device;
 	}
@@ -3919,9 +3864,6 @@
 
 	if ((rc = tty_unregister_driver(&serial_driver)))
 		printk("%s(%d) failed to unregister tty driver err=%d\n",
-		       __FILE__,__LINE__,rc);
-	if ((rc = tty_unregister_driver(&callout_driver)))
-		printk("%s(%d) failed to unregister callout driver err=%d\n",
 		       __FILE__,__LINE__,rc);
 
 	info = synclinkmp_device_list;
diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Mon May 26 12:20:47 2003
+++ b/drivers/char/tty_io.c	Mon May 26 15:29:29 2003
@@ -1305,7 +1305,6 @@
 	int index;
 	kdev_t device;
 	unsigned short saved_flags;
-	char	buf[64];
 
 	saved_flags = filp->f_flags;
 retry_open:
@@ -1379,7 +1378,7 @@
 	    tty->driver->subtype == PTY_TYPE_MASTER)
 		noctty = 1;
 #ifdef TTY_DEBUG_HANGUP
-	printk(KERN_DEBUG "opening %s...", tty_name(tty, buf));
+	printk(KERN_DEBUG "opening %s...", tty->name);
 #endif
 	if (tty->driver->open)
 		retval = tty->driver->open(tty, filp);
@@ -1393,7 +1392,7 @@
 	if (retval) {
 #ifdef TTY_DEBUG_HANGUP
 		printk(KERN_DEBUG "error %d in opening %s...", retval,
-		       tty_name(tty, buf));
+		       tty->name);
 #endif
 
 		release_dev(filp);
@@ -1418,19 +1417,6 @@
 		current->tty_old_pgrp = 0;
 		tty->session = current->session;
 		tty->pgrp = current->pgrp;
-	}
-	if ((tty->driver->type == TTY_DRIVER_TYPE_SERIAL) &&
-	    (tty->driver->subtype == SERIAL_TYPE_CALLOUT) &&
-	    (tty->count == 1)) {
-		static int nr_warns;
-		if (nr_warns < 5) {
-			printk(KERN_WARNING "tty_io.c: "
-				"process %d (%s) used obsolete /dev/%s - "
-				"update software to use /dev/ttyS%d\n",
-				current->pid, current->comm,
-				tty_name(tty, buf), TTY_NUMBER(tty));
-			nr_warns++;
-		}
 	}
 	return 0;
 }
diff -Nru a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
--- a/drivers/char/vme_scc.c	Fri May  9 03:21:31 2003
+++ b/drivers/char/vme_scc.c	Mon May 26 15:29:12 2003
@@ -90,7 +90,7 @@
 static void scc_setsignals(struct scc_port *port, int dtr, int rts);
 static void scc_break_ctl(struct tty_struct *tty, int break_state);
 
-static struct tty_driver scc_driver, scc_callout_driver;
+static struct tty_driver scc_driver;
 
 static struct tty_struct *scc_table[2] = { NULL, };
 static struct termios * scc_termios[2];
@@ -167,26 +167,11 @@
 	scc_driver.hangup = gs_hangup;
 	scc_driver.break_ctl = scc_break_ctl;
 
-	scc_callout_driver = scc_driver;
-#ifdef CONFIG_DEVFS_FS
-	scc_callout_driver.name = "cua/";
-#else
-	scc_callout_driver.name = "cua";
-#endif
-	scc_callout_driver.major = TTYAUX_MAJOR;
-	scc_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-
 	if ((error = tty_register_driver(&scc_driver))) {
 		printk(KERN_ERR "scc: Couldn't register scc driver, error = %d\n",
 		       error);
 		return 1;
 	}
-	if ((error = tty_register_driver(&scc_callout_driver))) {
-		tty_unregister_driver(&scc_driver);
-		printk(KERN_ERR "scc: Couldn't register scc callout driver, error = %d\n",
-		       error);
-		return 1;
-	}
 
 	return 0;
 }
@@ -202,7 +187,6 @@
 
 	for (i = 0; i < 2; i++) {
 		port = scc_ports + i;
-		port->gs.callout_termios = tty_std_termios;
 		port->gs.normal_termios = tty_std_termios;
 		port->gs.magic = SCC_MAGIC;
 		port->gs.close_delay = HZ/2;
@@ -599,18 +583,11 @@
 		if (!(port->gs.flags & ASYNC_CHECK_CD))
 			;	/* Don't report DCD changes */
 		else if (port->c_dcd) {
-			if (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) ||
-				~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) {
-				/* Are we blocking in open?*/
-				wake_up_interruptible(&port->gs.open_wait);
-			}
+			wake_up_interruptible(&port->gs.open_wait);
 		}
 		else {
-			if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) &&
-					(port->gs.flags & ASYNC_CALLOUT_NOHUP))) {
-				if (port->gs.tty)
-					tty_hangup (port->gs.tty);
-			}
+			if (port->gs.tty)
+				tty_hangup (port->gs.tty);
 		}
 	}
 	SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET);
@@ -949,15 +926,10 @@
 	}
 
 	if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = port->gs.normal_termios;
-		else 
-			*tty->termios = port->gs.callout_termios;
+		*tty->termios = port->gs.normal_termios;
 		scc_set_real_termios (port);
 	}
 
-	port->gs.session = current->session;
-	port->gs.pgrp = current->pgrp;
 	port->c_dcd = scc_get_CD (port);
 
 	scc_enable_rx_interrupts(port);
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Wed May 14 03:16:09 2003
+++ b/drivers/ide/ide-cd.c	Thu May  8 01:39:34 2003
@@ -2993,12 +2993,6 @@
 	long block = (long)rq->hard_sector / (hard_sect >> 9);
 	unsigned long blocks = rq->hard_nr_sectors / (hard_sect >> 9);
 
-	BUG_ON(sizeof(rq->hard_sector) > 4 && (rq->hard_sector >> 32));
-
-	if (rq->hard_nr_sectors != rq->nr_sectors) {
-		printk(KERN_ERR "ide-cd: hard_nr_sectors differs from nr_sectors! %lu %lu\n",
-				rq->nr_sectors, rq->hard_nr_sectors);
-	}
 	memset(rq->cmd, 0, sizeof(rq->cmd));
 
 	if (rq_data_dir(rq) == READ)
diff -Nru a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
--- a/drivers/ide/legacy/ide-cs.c	Sat Apr 26 09:16:19 2003
+++ b/drivers/ide/legacy/ide-cs.c	Sun May 18 13:57:37 2003
@@ -470,28 +470,25 @@
     return 0;
 } /* ide_event */
 
-/*====================================================================*/
+static struct pcmcia_driver ide_cs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "ide_cs",
+	},
+	.attach		= ide_attach,
+	.detach		= ide_detach,
+};
 
 static int __init init_ide_cs(void)
 {
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "ide-cs: Card Services release "
-	       "does not match!\n");
-	return -EINVAL;
-    }
-    register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
-    return 0;
+	return pcmcia_register_driver(&ide_cs_driver);
 }
 
 static void __exit exit_ide_cs(void)
 {
-    DEBUG(0, "ide-cs: unloading\n");
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL)
-	ide_detach(dev_list);
+	pcmcia_unregister_driver(&ide_cs_driver);
+	while (dev_list != NULL)
+		ide_detach(dev_list);
 }
 
 module_init(init_ide_cs);
diff -Nru a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
--- a/drivers/ieee1394/eth1394.c	Mon May 19 07:50:28 2003
+++ b/drivers/ieee1394/eth1394.c	Mon May 19 19:56:23 2003
@@ -3,6 +3,7 @@
  * 
  * Copyright (C) 2001 Ben Collins <bcollins@debian.org>
  *               2000 Bonin Franck <boninf@free.fr>
+ *               2003 Steve Kinneberg <kinnebergsteve@acmsystems.com>
  *
  * Mainly based on work by Emanuel Pirker and Andreas E. Bombe
  *
@@ -21,22 +22,28 @@
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-/* State of this driver:
- *
- * This driver intends to support RFC 2734, which describes a method for
+/* This driver intends to support RFC 2734, which describes a method for
  * transporting IPv4 datagrams over IEEE-1394 serial busses. This driver
  * will ultimately support that method, but currently falls short in
- * several areas. A few issues are:
+ * several areas.
+ *
+ * TODO:
+ * RFC 2734 related:
+ * - Add support for broadcast messages
+ * - Use EUI instead of node id in internal ARP tables
+ * - Add Config ROM entry
+ * - Add MCAP and multicast
  *
- *   - Does not support send/recv over Async streams using GASP
- *     packet formats, as per the RFC for ARP requests.
- *   - Does not yet support fragmented packets.
- *   - Relies on hardware address being equal to the nodeid for some things.
- *   - Does not support multicast
- *   - Hardcoded address for sending packets, instead of using discovery
- *     (ARP, see first item)
+ * Non-RFC 2734 related:
+ * - Move generic GASP reception to core 1394 code
+ * - Convert kmalloc/kfree for link fragments to use kmem_cache_* instead
+ * - Stability improvements
+ * - Performance enhancements
+ * - Change hardcoded 1394 bus address region to a dynamic memory space allocation
+ * - Consider garbage collecting old partial datagrams after X amount of time
  */
 
+
 #include <linux/module.h>
 
 #include <linux/sched.h>
@@ -56,7 +63,6 @@
 #include <linux/tcp.h>
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
-#include <linux/workqueue.h>
 #include <asm/delay.h>
 #include <asm/semaphore.h>
 #include <net/arp.h>
@@ -76,10 +82,27 @@
 	printk(level ETHER1394_DRIVER_NAME": %s: " fmt, dev_name, ## args)
 
 #define DEBUG(fmt, args...) \
-	printk(KERN_ERR fmt, ## args)
+	printk(KERN_ERR "eth1394:%s[%d]: "fmt"\n", __FUNCTION__, __LINE__, ## args)
+#define TRACE() printk(KERN_ERR "eth1394:%s[%d] ---- TRACE\n", __FUNCTION__, __LINE__)
 
 static char version[] __devinitdata =
-	"$Rev: 931 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 938 $ Ben Collins <bcollins@debian.org>";
+
+struct fragment_info {
+	struct list_head list;
+	int offset;
+	int len;
+};
+
+struct partial_datagram {
+	struct list_head list;
+	u16 dgl;
+	u16 dg_size;
+	u16 ether_type;
+	struct sk_buff *skb;
+	char *pbuf;
+	struct list_head frag_info;
+};
 
 /* Our ieee1394 highlevel driver */
 #define ETHER1394_DRIVER_NAME "ether1394"
@@ -89,7 +112,7 @@
 static struct hpsb_highlevel eth1394_highlevel;
 
 /* Use common.lf to determine header len */
-static int hdr_type_len[] = {
+static const int hdr_type_len[] = {
 	sizeof (struct eth1394_uf_hdr),
 	sizeof (struct eth1394_ff_hdr),
 	sizeof (struct eth1394_sf_hdr),
@@ -100,16 +123,111 @@
 MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)");
 MODULE_LICENSE("GPL");
 
+/* The max_partial_datagrams parameter is the maximum number of fragmented datagrams
+ * per node that eth1394 will keep in memory.  Providing an upper bound allows us to
+ * limit the amount of memory that partial datagrams consume in the event that some
+ * partial datagrams are never completed.  This should probably change to a sysctl
+ * item or the like if possible.
+ */
+MODULE_PARM(max_partial_datagrams, "i");
+MODULE_PARM_DESC(max_partial_datagrams,
+                 "Maximum number of partially received fragmented datagrams (default = 25).");
+static int max_partial_datagrams = 25;
+
+
+static inline void purge_partial_datagram(struct list_head *old);
+static int ether1394_tx(struct sk_buff *skb, struct net_device *dev);
 static void ether1394_iso(struct hpsb_iso *iso);
 
 
+static int ether1394_init_bc(struct net_device *dev)
+{
+	int ret = 0;
+	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
+
+	/* First time sending?  Need a broadcast channel for ARP and for
+	 * listening on */
+	if(priv->bc_state == ETHER1394_BC_CHECK) {
+		quadlet_t bc;
+
+		/* Get the local copy of the broadcast channel and check its
+		 * validity (the IRM should validate it for us) */
+
+		bc = priv->host->csr.broadcast_channel;
+
+		if((bc & 0xc0000000) != 0xc0000000) {
+			/* broadcast channel not validated yet */
+			ETH1394_PRINT(KERN_WARNING, dev->name,
+				      "Error BROADCAST_CHANNEL register valid "
+				      "bit not set, can't send IP traffic\n");
+			if(!in_interrupt()) {
+				hpsb_iso_shutdown(priv->iso);
+				priv->bc_state = ETHER1394_BC_CLOSED;
+			}
+			ret = -EAGAIN;
+			goto fail;
+		}
+		if(priv->broadcast_channel != (bc & 0x3f)) {
+			/* This really shouldn't be possible, but just in case
+			 * the IEEE 1394 spec changes regarding broadcast
+			 * channels in the future. */
+
+			if(in_interrupt()) {
+				ret = -EAGAIN;
+				goto fail;
+
+			}
+
+			hpsb_iso_shutdown(priv->iso);
+
+			priv->broadcast_channel = bc & 0x3f;
+			ETH1394_PRINT(KERN_INFO, dev->name,
+				      "Changing to broadcast channel %d...\n",
+				      priv->broadcast_channel);
+
+			priv->iso = hpsb_iso_recv_init(priv->host, 16 * 4096,
+						       16, priv->broadcast_channel,
+						       1, ether1394_iso);
+			if(priv->iso == NULL) {
+				ETH1394_PRINT(KERN_ERR, dev->name,
+					      "failed to change broadcast "
+					      "channel\n");
+				ret = -EAGAIN;
+				goto fail;
+			}
+		}
+		if(hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) {
+			ETH1394_PRINT(KERN_ERR, dev->name,
+				      "Could not start data stream reception\n");
+			if(!in_interrupt()) {
+				hpsb_iso_shutdown(priv->iso);
+				priv->bc_state = ETHER1394_BC_CLOSED;
+			}
+			ret = -EAGAIN;
+			goto fail;
+		}
+		priv->bc_state = ETHER1394_BC_OPENED;
+	}
+    
+fail:
+	return ret;
+}
+
 /* This is called after an "ifup" */
 static int ether1394_open (struct net_device *dev)
 {
 	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
+	unsigned long flags;
+	int ret;
 
 	/* Set the spinlock before grabbing IRQ! */
 	priv->lock = SPIN_LOCK_UNLOCKED;
+	spin_lock_irqsave(&priv->lock, flags);
+	ret = ether1394_init_bc(dev);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if(ret)
+		return ret;
 
 	netif_start_queue (dev);
 	return 0;
@@ -140,34 +258,6 @@
 	netif_wake_queue (dev);
 }
 
-/* We need to encapsulate the standard header with our own. We use the
- * ethernet header's proto for our own.
- *
- * XXX: This is where we need to create a list of skb's for fragmented
- * packets.  */
-static inline void ether1394_encapsulate (struct sk_buff *skb, struct net_device *dev,
-                                          int proto, struct packet_task *ptask)
-{
-	union eth1394_hdr *hdr =
-		(union eth1394_hdr *)skb_push (skb, hdr_type_len[ETH1394_HDR_LF_UF]);
-
-	hdr->words.word1 = 0;
-	hdr->common.lf = ETH1394_HDR_LF_UF;
-	hdr->words.word1 = htons(hdr->words.word1);
-	hdr->uf.ether_type = proto;
-
-	/* Set the transmission type for the packet.  Right now only ARP
-	 * packets are sent via GASP.  IP broadcast and IP multicast are not
-	 * yet supported properly, they too should use GASP. */
-	switch(proto) {
-	case __constant_htons(ETH_P_ARP):
-		ptask->tx_type = ETH1394_GASP;
-		break;
-	default:
-		ptask->tx_type = ETH1394_WRREQ;
-	}
-	return;
-}
 
 /* Convert a standard ARP packet to 1394 ARP. The first 8 bytes (the
  * entire arphdr) is the same format as the ip1394 header, so they
@@ -223,8 +313,6 @@
 				       unsigned char sspd, u64 eui, u16 fifo_hi,
 				       u32 fifo_lo, struct eth1394_priv *priv)
 {
-	int i;
-
 	if (nodeid < 0 || nodeid >= ALL_NODES) {
 		ETH1394_PRINT_G (KERN_ERR, "Cannot register invalid nodeid %d\n", nodeid);
 		return;
@@ -236,20 +324,8 @@
 	priv->fifo_lo[nodeid]	= fifo_lo;
 	priv->eui[nodeid]	= eui;
 
-	/* 63 is used for broadcasts to all hosts. It is equal to the
-	 * minimum of all registered nodes. A registered node is one with
-	 * a nonzero offset. Set the values rediculously high to start. We
-	 * know we have atleast one to change the default to.  */
-	sspd = 0xff;
-	max_rec = 0xff;
-	for (i = 0; i < ALL_NODES; i++) {
-		if (!priv->fifo_hi && !priv->fifo_lo) continue; /* Unregistered */
-		if (priv->max_rec[i] < max_rec) max_rec = priv->max_rec[i];
-		if (priv->sspd[i] < sspd) sspd = priv->sspd[i];
-	}
-
-	priv->max_rec[ALL_NODES] = max_rec;
-	priv->sspd[ALL_NODES] = sspd;
+	priv->max_rec[ALL_NODES] = min(priv->max_rec[ALL_NODES], max_rec);
+	priv->sspd[ALL_NODES] = min(priv->sspd[ALL_NODES], sspd);
 
 	return;
 }
@@ -257,6 +333,7 @@
 static void ether1394_reset_priv (struct net_device *dev, int set_mtu)
 {
 	unsigned long flags;
+	int i;
 	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
 	int phy_id = NODEID_TO_NODE(priv->host->node_id);
 	struct hpsb_host *host = priv->host;
@@ -264,7 +341,7 @@
 	spin_lock_irqsave (&priv->lock, flags);
 
 	/* Clear the speed/payload/offset tables */
-	memset (priv->max_rec, 0, sizeof (priv->max_rec));
+	memset (priv->max_rec, 8, sizeof (priv->max_rec));
 	memset (priv->sspd, 0, sizeof (priv->sspd));
 	memset (priv->fifo_hi, 0, sizeof (priv->fifo_hi));
 	memset (priv->fifo_lo, 0, sizeof (priv->fifo_lo));
@@ -281,16 +358,28 @@
 
 	/* We'll use our max_rec as the default mtu */
 	if (set_mtu)
-		dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - /* mtu = max_rec - */
-			(sizeof (union eth1394_hdr) + 8);	/* (hdr + GASP) */
+		dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) -
+			(sizeof (union eth1394_hdr) + ETHER1394_OVERHEAD);
 
 	/* Set our hardware address while we're at it */
 	*(nodeid_t *)dev->dev_addr = htons (host->node_id);
 
 	spin_unlock_irqrestore (&priv->lock, flags);
-}
 
-static int ether1394_tx (struct sk_buff *skb, struct net_device *dev);
+	for(i = 0; i < ALL_NODES; i++) {
+		struct list_head *lh, *n;
+
+		spin_lock_irqsave(&priv->pdg[i].lock, flags);
+		if(!set_mtu) {
+			list_for_each_safe(lh, n, &priv->pdg[i].list) {
+				purge_partial_datagram(lh);
+			}
+		}
+		INIT_LIST_HEAD(&(priv->pdg[i].list));
+		priv->pdg[i].sz = 0;
+		spin_unlock_irqrestore(&priv->pdg[i].lock, flags);
+	}
+}
 
 /* This function is called by register_netdev */
 static int ether1394_init_dev (struct net_device *dev)
@@ -321,6 +410,7 @@
  */
 static void ether1394_add_host (struct hpsb_host *host)
 {
+	int i;
 	struct host_info *hi = NULL;
 	struct net_device *dev = NULL;
 	struct eth1394_priv *priv;
@@ -343,6 +433,12 @@
 	priv->host = host;
 	spin_lock_init(&priv->lock);
 
+	for(i = 0; i < ALL_NODES; i++) {
+                spin_lock_init(&priv->pdg[i].lock);
+		INIT_LIST_HEAD(&priv->pdg[i].list);
+		priv->pdg[i].sz = 0;
+	}
+
 	hi = hpsb_create_hostinfo(&eth1394_highlevel, host, sizeof(*hi));
 
 	if (hi == NULL)
@@ -360,10 +456,10 @@
 	hi->dev = dev;
 
 	/* Ignore validity in hopes that it will be set in the future.  It'll
-	 * check it on transmit. */
+	 * be checked when the eth device is opened. */
 	priv->broadcast_channel = host->csr.broadcast_channel & 0x3f;
 
-	priv->iso = hpsb_iso_recv_init(host, 8 * 4096, 8, priv->broadcast_channel,
+	priv->iso = hpsb_iso_recv_init(host, 16 * 4096, 16, priv->broadcast_channel,
 				       1, ether1394_iso);
 	if (priv->iso == NULL) {
 		priv->bc_state = ETHER1394_BC_CLOSED;
@@ -372,7 +468,7 @@
 
 out:
 	if (dev != NULL)
-		kfree (dev);
+		kfree (dev); dev = NULL;
 	if (hi)
 		hpsb_destroy_hostinfo(&eth1394_highlevel, host);
 
@@ -393,7 +489,7 @@
 		unregister_netdev (hi->dev);
 		hpsb_iso_shutdown(priv->iso);
 
-		kfree (hi->dev);
+		kfree (hi->dev); hi->dev = NULL;
 	}
 
 	return;
@@ -417,6 +513,11 @@
 	netif_wake_queue (dev);
 }
 
+
+/******************************************
+ * Datagram reception code
+ ******************************************/
+
 /* Copied from net/ethernet/eth.c */
 static inline unsigned short ether1394_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
@@ -451,9 +552,8 @@
 /* Parse an encapsulated IP1394 header into an ethernet frame packet.
  * We also perform ARP translation here, if need be.  */
 static inline unsigned short ether1394_parse_encap (struct sk_buff *skb, struct net_device *dev,
-					     nodeid_t srcid, nodeid_t destid)
+						    nodeid_t srcid, nodeid_t destid, u16 ether_type)
 {
-	union eth1394_hdr *hdr = (union eth1394_hdr *)skb->data;
 	unsigned char src_hw[ETH_ALEN], dest_hw[ETH_ALEN];
 	unsigned short ret = 0;
 
@@ -462,14 +562,10 @@
 	*(u16 *)dest_hw = htons(destid);
 	*(u16 *)src_hw = htons(srcid);
 
-	/* Remove the encapsulation header */
-	hdr->words.word1 = ntohs(hdr->words.word1);
-	skb_pull (skb, hdr_type_len[hdr->common.lf]);
-
 	/* If this is an ARP packet, convert it. First, we want to make
 	 * use of some of the fields, since they tell us a little bit
 	 * about the sending machine.  */
-	if (hdr->uf.ether_type == __constant_htons (ETH_P_ARP)) {
+	if (ether_type == __constant_htons (ETH_P_ARP)) {
 		unsigned long flags;
 		u16 phy_id = NODEID_TO_NODE(srcid);
 		struct eth1394_priv *priv =
@@ -503,49 +599,318 @@
 	}
 
 	/* Now add the ethernet header. */
-	if (dev->hard_header (skb, dev, __constant_ntohs (hdr->uf.ether_type),
+	if (dev->hard_header (skb, dev, __constant_ntohs (ether_type),
 			      dest_hw, src_hw, skb->len) >= 0)
 		ret = ether1394_type_trans(skb, dev);
 
 	return ret;
 }
 
+static inline int fragment_overlap(struct list_head *frag_list, int offset, int len)
+{
+	struct list_head *lh;
+	struct fragment_info *fi;
+
+	list_for_each(lh, frag_list) {
+		fi = list_entry(lh, struct fragment_info, list);
+
+		if( ! ((offset > (fi->offset + fi->len - 1)) ||
+		       ((offset + len - 1) < fi->offset)))
+			return 1;
+	}
+	return 0;
+}
+
+static inline struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl)
+{
+	struct list_head *lh;
+	struct partial_datagram *pd;
+
+	list_for_each(lh, pdgl) {
+		pd = list_entry(lh, struct partial_datagram, list);
+		if(pd->dgl == dgl)
+			return lh;
+	}
+	return NULL;
+}
+
+/* Assumes that new fragment does not overlap any existing fragments */
+static inline int new_fragment(struct list_head *frag_info, int offset, int len)
+{
+	struct list_head *lh;
+	struct fragment_info *fi, *fi2, *new;
+
+	list_for_each(lh, frag_info) {
+		fi = list_entry(lh, struct fragment_info, list);
+		if((fi->offset + fi->len) == offset) {
+			/* The new fragment can be tacked on to the end */
+			fi->len += len;
+			/* Did the new fragment plug a hole? */
+			fi2 = list_entry(lh->next, struct fragment_info, list);
+			if((fi->offset + fi->len) == fi2->offset) {
+				/* glue fragments together */
+				fi->len += fi2->len;
+				list_del(lh->next);
+				kfree(fi2); fi2 = NULL;
+			}
+			return 0;
+		} else if((offset + len) == fi->offset) {
+			/* The new fragment can be tacked on to the beginning */
+			fi->offset = offset;
+			fi->len += len;
+			/* Did the new fragment plug a hole? */
+			fi2 = list_entry(lh->prev, struct fragment_info, list);
+			if((fi2->offset + fi2->len) == fi->offset) {
+				/* glue fragments together */
+				fi2->len += fi->len;
+				list_del(lh);
+				kfree(fi); fi = NULL;
+			}
+			return 0;
+		} else if(offset > (fi->offset + fi->len)) {
+			break;
+		} else if ((offset + len) < fi->offset) {
+			lh = lh->prev;
+			break;
+		}
+	}
+
+	new = kmalloc(sizeof(struct fragment_info), GFP_ATOMIC);
+	if(!new) 
+		return -ENOMEM;
+
+	new->offset = offset;
+	new->len = len;
+
+	list_add(&new->list, lh);
+
+	return 0;
+}
+
+static inline int new_partial_datagram(struct net_device *dev,
+				       struct list_head *pdgl, int dgl,
+				       int dg_size, char *frag_buf,
+				       int frag_off, int frag_len)
+{
+	struct partial_datagram *new;
+
+	new = kmalloc(sizeof(struct partial_datagram), GFP_ATOMIC);
+	if(!new)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&new->frag_info);
+
+	if(new_fragment(&new->frag_info, frag_off, frag_len) < 0) {
+		kfree(new); new = NULL;
+		return -ENOMEM;
+	}
+
+	new->dgl = dgl;
+	new->dg_size = dg_size;
+
+	new->skb = dev_alloc_skb(dg_size + dev->hard_header_len + 15);
+	if(!new->skb) {
+		struct fragment_info *fi = list_entry(new->frag_info.next,
+						      struct fragment_info,
+						      list);
+		kfree(fi); fi = NULL;
+		kfree(new); new = NULL;
+		return -ENOMEM;
+	}
+
+	skb_reserve(new->skb, (dev->hard_header_len + 15) & ~15);
+	new->pbuf = skb_put(new->skb, dg_size);
+	memcpy(new->pbuf + frag_off, frag_buf, frag_len);
+
+	list_add(&new->list, pdgl);
+
+	return 0;
+}
+
+static inline int update_partial_datagram(struct list_head *pdgl, struct list_head *lh,
+					  char *frag_buf, int frag_off, int frag_len)
+{
+	struct partial_datagram *pd = list_entry(lh, struct partial_datagram, list);
+
+	if(new_fragment(&pd->frag_info, frag_off, frag_len) < 0) {
+		return -ENOMEM;
+	}
+
+	memcpy(pd->pbuf + frag_off, frag_buf, frag_len);
+
+	/* Move list entry to beginnig of list so that oldest partial
+	 * datagrams percolate to the end of the list */
+	list_del(lh);
+	list_add(lh, pdgl);
+
+	return 0;
+}
+
+static inline void purge_partial_datagram(struct list_head *old)
+{
+	struct partial_datagram *pd = list_entry(old, struct partial_datagram, list);
+	struct list_head *lh, *n;
+
+	list_for_each_safe(lh, n, &pd->frag_info) {
+		struct fragment_info *fi = list_entry(lh, struct fragment_info, list);
+		list_del(lh);
+		kfree(fi); fi = NULL;
+	}
+	list_del(old);
+	kfree_skb(pd->skb); pd->skb = NULL;
+	kfree(pd); pd = NULL;
+}
+
+static inline int is_datagram_complete(struct list_head *lh, int dg_size)
+{
+	struct partial_datagram *pd = list_entry(lh, struct partial_datagram, list);
+	struct fragment_info *fi = list_entry(pd->frag_info.next,
+					      struct fragment_info, list);
+
+	return (fi->len == dg_size);
+}
+
 /* Packet reception. We convert the IP1394 encapsulation header to an
  * ethernet header, and fill it with some of our other fields. This is
  * an incoming packet from the 1394 bus.  */
-static int ether1394_write (struct hpsb_host *host, int srcid, int destid,
-			    quadlet_t *data, u64 addr, unsigned int len, u16 fl)
+static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
+				  char *buf, int len)
 {
 	struct sk_buff *skb;
-	char *buf = (char *)data;
 	unsigned long flags;
-	struct host_info *hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
-	struct net_device *dev;
 	struct eth1394_priv *priv;
+	union eth1394_hdr *hdr = (union eth1394_hdr *)buf;
+	u16 ether_type = 0;  /* initialized to clear warning */
+	int hdr_len;
 
-	if (hi == NULL) {
-		ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %p\n",
-				 host);
-		return RCODE_ADDRESS_ERROR;
-	}
+	priv = (struct eth1394_priv *)dev->priv;
 
-	dev = hi->dev;
+	/* First, did we receive a fragmented or unfragmented datagram? */
+	hdr->words.word1 = ntohs(hdr->words.word1);
 
-	priv = (struct eth1394_priv *)dev->priv;
+	hdr_len = hdr_type_len[hdr->common.lf];
 
-	/* A packet has been received by the ieee1394 bus. Build an skbuff
-	 * around it so we can pass it to the high level network layer. */
+	if(hdr->common.lf == ETH1394_HDR_LF_UF) {
+		/* An unfragmented datagram has been received by the ieee1394
+		 * bus. Build an skbuff around it so we can pass it to the
+		 * high level network layer. */
 
-	skb = dev_alloc_skb (len + dev->hard_header_len + 15);
-	if (!skb) {
-		HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n");
-		priv->stats.rx_dropped++;
-		return RCODE_ADDRESS_ERROR;
+		skb = dev_alloc_skb(len + dev->hard_header_len + 15);
+		if (!skb) {
+			HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n");
+			priv->stats.rx_dropped++;
+			return -1;
+		}
+		skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+		memcpy(skb_put(skb, len - hdr_len), buf + hdr_len, len - hdr_len);
+		ether_type = hdr->uf.ether_type;
+	} else {
+#if 0
+		return 0;
 	}
+	if(0) {
+#endif
+		/* A datagram fragment has been received, now the fun begins. */
+
+		struct list_head *pdgl, *lh;
+		struct partial_datagram *pd;
+		int fg_off;
+		int fg_len = len - hdr_len;
+		int dg_size;
+		int dgl;
+		int retval;
+		int sid = NODEID_TO_NODE(srcid);
+                struct pdg_list *pdg = &(priv->pdg[sid]);
+
+		hdr->words.word3 = ntohs(hdr->words.word3);
+		/* The 4th header word is reserved so no need to do ntohs() */
+
+		if(hdr->common.lf == ETH1394_HDR_LF_FF) {
+			ether_type = hdr->ff.ether_type;
+			dgl = hdr->ff.dgl;
+			dg_size = hdr->ff.dg_size;
+			fg_off = 0;
+		} else {
+			hdr->words.word2 = ntohs(hdr->words.word2);
+			dgl = hdr->sf.dgl;
+			dg_size = hdr->sf.dg_size;
+			fg_off = hdr->sf.fg_off;
+		}
 
-	skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+		spin_lock_irqsave(&pdg->lock, flags);
 
-	memcpy (skb_put (skb, len), buf, len);
+		pdgl = &(pdg->list);
+		lh = find_partial_datagram(pdgl, dgl);
+
+		if(lh == NULL) {
+			if(pdg->sz == max_partial_datagrams) {
+				/* remove the oldest */
+				purge_partial_datagram(pdgl->prev);
+				pdg->sz--;
+			}
+            
+			retval = new_partial_datagram(dev, pdgl, dgl, dg_size,
+						      buf + hdr_len, fg_off,
+						      fg_len);
+			if(retval < 0) {
+				spin_unlock_irqrestore(&pdg->lock, flags);
+				goto bad_proto;
+			}
+			pdg->sz++;
+			lh = find_partial_datagram(pdgl, dgl);
+		} else {
+			struct partial_datagram *pd;
+
+			pd = list_entry(lh, struct partial_datagram, list);
+
+			if(fragment_overlap(&pd->frag_info, fg_off, fg_len)) {
+				/* Overlapping fragments, obliterate old
+				 * datagram and start new one. */
+				purge_partial_datagram(lh);
+				retval = new_partial_datagram(dev, pdgl, dgl,
+							      dg_size,
+							      buf + hdr_len,
+							      fg_off, fg_len);
+				if(retval < 0) {
+					pdg->sz--;
+					spin_unlock_irqrestore(&pdg->lock, flags);
+					goto bad_proto;
+				}
+			} else {
+				retval = update_partial_datagram(pdgl, lh,
+								 buf + hdr_len,
+								 fg_off, fg_len);
+				if(retval < 0) {
+					/* Couldn't save off fragment anyway
+					 * so might as well obliterate the
+					 * datagram now. */
+					purge_partial_datagram(lh);
+					pdg->sz--;
+					spin_unlock_irqrestore(&pdg->lock, flags);
+					goto bad_proto;
+				}
+			} /* fragment overlap */
+		} /* new datagram or add to existing one */
+
+		pd = list_entry(lh, struct partial_datagram, list);
+
+		if(hdr->common.lf == ETH1394_HDR_LF_FF) {
+			pd->ether_type = ether_type;
+		}
+
+		if(is_datagram_complete(lh, dg_size)) {
+			ether_type = pd->ether_type;
+			pdg->sz--;
+			skb = skb_get(pd->skb);
+			purge_partial_datagram(lh);
+			spin_unlock_irqrestore(&pdg->lock, flags);
+		} else {
+			/* Datagram is not complete, we're done for the
+			 * moment. */
+			spin_unlock_irqrestore(&pdg->lock, flags);
+			return 0;
+		}
+	} /* unframgented datagram or fragmented one */
 
 	/* Write metadata, and then pass to the receive level */
 	skb->dev = dev;
@@ -555,18 +920,19 @@
 	 * converting to an ethernet frame header, aswell as arp
 	 * conversion if needed. ARP conversion is easier in this
 	 * direction, since we are using ethernet as our backend.  */
-	skb->protocol = ether1394_parse_encap (skb, dev, srcid, destid);
+	skb->protocol = ether1394_parse_encap(skb, dev, srcid, destid,
+					      ether_type);
 
-	spin_lock_irqsave (&priv->lock, flags);
-	if (!skb->protocol) {
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if(!skb->protocol) {
 		priv->stats.rx_errors++;
 		priv->stats.rx_dropped++;
 		dev_kfree_skb_any(skb);
 		goto bad_proto;
 	}
 
-	netif_stop_queue(dev);
-	if (netif_rx (skb) == NET_RX_DROP) {
+	if(netif_rx(skb) == NET_RX_DROP) {
 		priv->stats.rx_errors++;
 		priv->stats.rx_dropped++;
 		goto bad_proto;
@@ -577,20 +943,36 @@
 	priv->stats.rx_bytes += skb->len;
 
 bad_proto:
-	netif_start_queue(dev);
-	spin_unlock_irqrestore (&priv->lock, flags);
+	if(netif_queue_stopped(dev))
+		netif_wake_queue(dev);
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 	dev->last_rx = jiffies;
 
-	return RCODE_COMPLETE;
+	return 0;
+}
+
+static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
+			   quadlet_t *data, u64 addr, unsigned int len, u16 flags)
+{
+	struct host_info *hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
+
+	if(hi == NULL) {
+		ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n",
+				host->driver->name);
+		return RCODE_ADDRESS_ERROR;
+	}
+
+	if(ether1394_data_handler(hi->dev, srcid, destid, (char*)data, len))
+		return RCODE_ADDRESS_ERROR;
+	else
+		return RCODE_COMPLETE;
 }
 
 static void ether1394_iso(struct hpsb_iso *iso)
 {
-	struct sk_buff *skb;
 	quadlet_t *data;
 	char *buf;
-	unsigned long flags;
 	struct host_info *hi = hpsb_get_hostinfo(&eth1394_highlevel, iso->host);
 	struct net_device *dev;
 	struct eth1394_priv *priv;
@@ -600,9 +982,9 @@
 	int i;
 	int nready;
 
-	if (hi == NULL) {
-		ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %s\n",
-				 iso->host->driver->name);
+	if(hi == NULL) {
+		ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n",
+				iso->host->driver->name);
 		return;
 	}
 
@@ -623,186 +1005,289 @@
 
 		priv = (struct eth1394_priv *)dev->priv;
 
-		if (info->channel != priv->broadcast_channel ||
-		    specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
+		if(info->channel != (iso->host->csr.broadcast_channel & 0x3f) ||
+		   specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
 			/* This packet is not for us */
 			continue;
 		}
+		ether1394_data_handler(dev, source_id, iso->host->node_id, buf, len);
+	}
 
-		/* A packet has been received by the ieee1394 bus. Build an skbuff
-		 * around it so we can pass it to the high level network layer. */
-		skb = dev_alloc_skb (len + dev->hard_header_len + 15);
-		if (!skb) {
-			HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n");
-			priv->stats.rx_dropped++;
-			break;
-		}
+	hpsb_iso_recv_release_packets(iso, i);
 
-		skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+	dev->last_rx = jiffies;
+}
 
-		memcpy (skb_put (skb, len), buf, len);
+/******************************************
+ * Datagram transmission code
+ ******************************************/
 
-		/* Write metadata, and then pass to the receive level */
-		skb->dev = dev;
-		skb->ip_summed = CHECKSUM_UNNECESSARY;	/* don't check it */
-
-		/* Parse the encapsulation header. This actually does the job of
-		 * converting to an ethernet frame header, aswell as arp
-		 * conversion if needed. ARP conversion is easier in this
-		 * direction, since we are using ethernet as our backend.  */
-		skb->protocol = ether1394_parse_encap (skb, dev, source_id,
-						       LOCAL_BUS | ALL_NODES);
+/* We need to encapsulate the standard header with our own. We use the
+ * ethernet header's proto for our own. */
+static inline unsigned int ether1394_encapsulate_prep(unsigned int max_payload,
+						      int proto,
+						      union eth1394_hdr *hdr,
+						      u16 dg_size, u16 dgl)
+{
+	unsigned int adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_UF];
 
-		spin_lock_irqsave (&priv->lock, flags);
-		if (!skb->protocol) {
-			priv->stats.rx_errors++;
-			priv->stats.rx_dropped++;
-			dev_kfree_skb_any(skb);
-			goto bad_proto;
-		}
+	/* Does it all fit in one packet? */
+	if(dg_size <= adj_max_payload) {
+		hdr->uf.lf = ETH1394_HDR_LF_UF;
+		hdr->uf.ether_type = proto;
+	} else {
+		hdr->ff.lf = ETH1394_HDR_LF_FF;
+		hdr->ff.ether_type = proto;
+		hdr->ff.dg_size = dg_size;
+		hdr->ff.dgl = dgl;
+		adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_FF];
+	}
 
-		netif_stop_queue(dev);
-		if (netif_rx (skb) == NET_RX_DROP) {
-			priv->stats.rx_errors++;
-			priv->stats.rx_dropped++;
-			goto bad_proto;
-		}
+	return((dg_size + (adj_max_payload - 1)) / adj_max_payload);
+}
 
-		/* Statistics */
-		priv->stats.rx_packets++;
-		priv->stats.rx_bytes += skb->len;
+static inline unsigned int ether1394_encapsulate(struct sk_buff *skb,
+						 unsigned int max_payload,
+						 union eth1394_hdr *hdr)
+{
+	union eth1394_hdr *bufhdr;
+	int ftype = hdr->common.lf;
+	int hdrsz = hdr_type_len[ftype];
+	unsigned int adj_max_payload = max_payload - hdrsz;
+
+	switch(ftype) {
+	case ETH1394_HDR_LF_UF:
+		bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz);
+		bufhdr->words.word1 = htons(hdr->words.word1);
+		bufhdr->words.word2 = hdr->words.word2;
+		break;
 
-	bad_proto:
-		spin_unlock_irqrestore (&priv->lock, flags);
+	case ETH1394_HDR_LF_FF:
+		bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz);
+		bufhdr->words.word1 = htons(hdr->words.word1);
+		bufhdr->words.word2 = hdr->words.word2;
+		bufhdr->words.word3 = htons(hdr->words.word3);
+		bufhdr->words.word4 = 0;
+
+		/* Set frag type here for future interior fragments */
+		hdr->common.lf = ETH1394_HDR_LF_IF;
+		hdr->sf.fg_off = 0;
+		break;
+		
+	default:
+		hdr->sf.fg_off += adj_max_payload;
+		bufhdr = (union eth1394_hdr *)skb_pull(skb, adj_max_payload);
+		if(max_payload >= skb->len)
+			hdr->common.lf = ETH1394_HDR_LF_LF;
+		bufhdr->words.word1 = htons(hdr->words.word1);
+		bufhdr->words.word2 = htons(hdr->words.word2);
+		bufhdr->words.word3 = htons(hdr->words.word3);
+		bufhdr->words.word4 = 0;
 	}
 
-	hpsb_iso_recv_release_packets(iso, i);
+	return min(max_payload, skb->len);
+}
 
-	netif_start_queue(dev);
-	
-	dev->last_rx = jiffies;
+static inline struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host)
+{
+	struct hpsb_packet *p;
 
-	return;
+	p = alloc_hpsb_packet(0);
+	if(p) {
+		p->host = host;
+		p->data = NULL;
+		p->generation = get_hpsb_generation(host);
+		p->type = hpsb_async;
+	}
+	return p;
 }
 
+static inline int ether1394_prep_write_packet(struct hpsb_packet *p,
+					      struct hpsb_host *host,
+					      nodeid_t node, u64 addr,
+					      void * data, int tx_len)
+{
+	p->node_id = node;
+	p->data = NULL;
+
+	p->tcode = TCODE_WRITEB;
+	p->header[1] = (host->node_id << 16) | (addr >> 32);
+	p->header[2] = addr & 0xffffffff;
+
+	p->header_size = 16;
+	p->expect_response = 1;
+
+	if(hpsb_get_tlabel(p, !in_interrupt())) {
+		ETH1394_PRINT_G(KERN_ERR, "No more tlabels left");
+		return -1;
+	}		
+	p->header[0] = (p->node_id << 16) | (p->tlabel << 10)
+		| (1 << 8) | (TCODE_WRITEB << 4);
+
+	p->header[3] = tx_len << 16;
+	p->data_size = tx_len + (tx_len % 4 ? 4 - (tx_len % 4) : 0);
+	p->data = (quadlet_t*)data;
+
+	return 0;
+}
 
-/* This function is our scheduled write */
-static void hpsb_write_sched (void *__ptask)
+static inline void ether1394_prep_gasp_packet(struct hpsb_packet *p,
+					      struct hpsb_host *host,
+					      struct sk_buff *skb, int length)
 {
-	struct packet_task *ptask = (struct packet_task *)__ptask;
-	struct sk_buff *skb = ptask->skb;
-	struct net_device *dev = ptask->skb->dev;
-	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
-	unsigned long flags;
-	int status;
- 
-	if (ptask->tx_type == ETH1394_GASP) {
-		status  = hpsb_send_gasp(priv->host, priv->broadcast_channel,
-					 get_hpsb_generation(priv->host),
-					 (quadlet_t *)skb->data, skb->len,
-					 ETHER1394_GASP_SPECIFIER_ID,
-					 ETHER1394_GASP_VERSION);
+	p->header_size = 4;
+	p->tcode = TCODE_STREAM_DATA;
+
+	p->header[0] = (length << 16) | (3 << 14)
+		| ((host->csr.broadcast_channel & 0x3f) << 8)
+		| (TCODE_STREAM_DATA << 4);
+	p->data_size = length;
+	p->data = (quadlet_t*)skb_push(skb, 2 * sizeof(quadlet_t));
+	p->data[0] = cpu_to_be32((host->node_id << 16) |
+				      ETHER1394_GASP_SPECIFIER_ID_HI);
+	p->data[1] = cpu_to_be32((ETHER1394_GASP_SPECIFIER_ID_LO << 24) |
+				      ETHER1394_GASP_VERSION);
+}
+
+static inline void ether1394_free_packet(struct hpsb_packet *packet)
+{
+	packet->data = NULL;
+	free_hpsb_packet(packet); packet = NULL;
+}
+
+static void ether1394_complete_cb(void *__ptask);
+static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len)
+{
+	struct eth1394_priv *priv = ptask->priv;
+	struct hpsb_packet *packet;
+
+	packet = ether1394_alloc_common_packet(priv->host);
+	if(!packet)
+		return -1;
+
+	if(ptask->tx_type == ETH1394_GASP) {
+		int length = tx_len + (2 * sizeof(quadlet_t));
+
+		ether1394_prep_gasp_packet(packet, priv->host,
+						    ptask->skb, length);
+
 	} else {
-		status = hpsb_write(priv->host, ptask->dest_node,
-				    get_hpsb_generation(priv->host),
-				    ptask->addr, (quadlet_t *)skb->data,
-				    skb->len);
+		if(ether1394_prep_write_packet(packet, priv->host,
+					       ptask->dest_node,
+					       ptask->addr, ptask->skb->data,
+					       tx_len))
+			goto fail;
 	}
 
+	ptask->packet = packet;
+	hpsb_set_packet_complete_task(ptask->packet, ether1394_complete_cb,
+				      ptask);
 
+	if(hpsb_send_packet(packet)) {
+		return 0;
+	}
+fail:
+	return -1;
+}
+
+
+/* Task function to be run when a datagram transmission is completed */
+static inline void ether1394_dg_complete(struct packet_task *ptask, int fail)
+{
+	struct sk_buff *skb = ptask->skb;
+	struct net_device *dev = skb->dev;
+	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
+        unsigned long flags;
+		
 	/* Statistics */
-	spin_lock_irqsave (&priv->lock, flags);
-	if (!status) {
-		priv->stats.tx_bytes += skb->len;
-		priv->stats.tx_packets++;
-	} else {
-		//printk("Failed in hpsb_write_sched\n");
+	if(fail) {
+		spin_lock_irqsave(&priv->lock, flags);
 		priv->stats.tx_dropped++;
 		priv->stats.tx_errors++;
-		if (netif_queue_stopped (dev))
-			netif_wake_queue (dev);
+		spin_unlock_irqrestore(&priv->lock, flags);
+	} else {
+		spin_lock_irqsave(&priv->lock, flags);
+		priv->stats.tx_bytes += skb->len;
+		priv->stats.tx_packets++;
+		spin_unlock_irqrestore(&priv->lock, flags);
 	}
-	spin_unlock_irqrestore (&priv->lock, flags);
 
-	dev->trans_start = jiffies;
-	dev_kfree_skb(skb);
-	kmem_cache_free(packet_task_cache, ptask);
+	dev_kfree_skb_any(skb); skb = NULL;
+	kmem_cache_free(packet_task_cache, ptask); ptask = NULL;
+}
 
-	return;
+
+/* Callback for when a packet has been sent and the status of that packet is
+ * known */
+static void ether1394_complete_cb(void *__ptask)
+{
+	struct packet_task *ptask = (struct packet_task *)__ptask;
+	struct hpsb_packet *packet = ptask->packet;
+	int fail = 0;
+
+	if(packet->tcode != TCODE_STREAM_DATA) {
+		fail = hpsb_packet_success(packet);
+		hpsb_free_tlabel(packet);
+	}
+
+	ether1394_free_packet(packet); packet = ptask->packet = NULL;
+
+	ptask->outstanding_pkts--;
+	if(ptask->outstanding_pkts > 0 && !fail)
+	{
+		int tx_len;
+
+		/* Add the encapsulation header to the fragment */
+		tx_len = ether1394_encapsulate(ptask->skb, ptask->max_payload,
+					       &ptask->hdr);
+		if(ether1394_send_packet(ptask, tx_len))
+			ether1394_dg_complete(ptask, 1);
+	} else {
+		ether1394_dg_complete(ptask, fail);
+	}
 }
 
+
+
 /* Transmit a packet (called by kernel) */
 static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
 {
-	int kmflags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL;
+	int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
 	struct ethhdr *eth;
 	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
 	int proto;
 	unsigned long flags;
 	nodeid_t dest_node;
-	u64 addr;
-	struct packet_task *ptask = NULL;
+	eth1394_tx_type tx_type;
 	int ret = 0;
+	unsigned int tx_len;
+	unsigned int max_payload;
+	u16 dg_size;
+	u16 dgl;
+	struct packet_task *ptask;
+
+	ptask = kmem_cache_alloc(packet_task_cache, kmflags);
+	if(ptask == NULL) {
+		ret = -ENOMEM;
+		goto fail;
+	}
 
 	spin_lock_irqsave (&priv->lock, flags);
 	if (priv->bc_state == ETHER1394_BC_CLOSED) {
 		ETH1394_PRINT(KERN_ERR, dev->name,
-			      "Cannot send packet, no broadcast channel available.");
+			      "Cannot send packet, no broadcast channel available.\n");
 		ret = -EAGAIN;
+		spin_unlock_irqrestore (&priv->lock, flags);
 		goto fail;
 	}
 
-	/* First time sending?  Need a broadcast channel for ARP and for
-	 * listening on */
 	if (priv->bc_state == ETHER1394_BC_CHECK) {
-		quadlet_t bc;
-
-		/* Get the local copy of the broadcast channel and check its
-		 * validity (the IRM should validate it for us) */
-
-		bc = priv->host->csr.broadcast_channel;
-
-		if ((bc & 0xc0000000) != 0xc0000000) {
-			/* broadcast channel not validated yet */
-			ETH1394_PRINT(KERN_WARNING, dev->name,
-				      "Error BROADCAST_CHANNEL register valid "
-				      "bit not set, can't send IP traffic\n");
-			hpsb_iso_shutdown(priv->iso);
-			priv->bc_state = ETHER1394_BC_CLOSED;
-			ret = -EAGAIN;
+		if(ether1394_init_bc(dev)) {
 			spin_unlock_irqrestore (&priv->lock, flags);
 			goto fail;
 		}
-		if (priv->broadcast_channel != (bc & 0x3f)) {
-			/* This really shouldn't be possible, but just in case
-			 * the IEEE 1394 spec changes regarding broadcast
-			 * channels in the future. */
-			hpsb_iso_shutdown(priv->iso);
-
-			priv->broadcast_channel = bc & 0x3f;
-			ETH1394_PRINT(KERN_WARNING, dev->name,
-				      "Changing to broadcast channel %d...\n",
-				      priv->broadcast_channel);
-
-			priv->iso = hpsb_iso_recv_init(priv->host, 8 * 4096,
-						       8, priv->broadcast_channel,
-						       1, ether1394_iso);
-			if (priv->iso == NULL) {
-				ret = -EAGAIN;
-				goto fail;
-			}
-		}
-		if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) {
-			ETH1394_PRINT(KERN_ERR, dev->name,
-				      "Could not start async reception\n");
-			hpsb_iso_shutdown(priv->iso);
-			priv->bc_state = ETHER1394_BC_CLOSED;
-			ret = -EAGAIN;
-			spin_unlock_irqrestore (&priv->lock, flags);
-			goto fail;
-		}
-		priv->bc_state = ETHER1394_BC_OPENED;
 	}
+
 	spin_unlock_irqrestore (&priv->lock, flags);
 
 	if ((skb = skb_share_check (skb, kmflags)) == NULL) {
@@ -823,53 +1308,82 @@
 	if (proto == __constant_htons (ETH_P_ARP))
 		ether1394_arp_to_1394arp (skb, dev);
 
-	ptask = kmem_cache_alloc(packet_task_cache, kmflags);
-	if (ptask == NULL) {
-		ret = -ENOMEM;
-		goto fail;
-	}
+	max_payload = 1 << (min(priv->max_rec[NODEID_TO_NODE(priv->host->node_id)],
+                                priv->max_rec[NODEID_TO_NODE(dest_node)]) + 1);
 
-	/* Now add our encapsulation header */
-	ether1394_encapsulate (skb, dev, proto, ptask);
+	if(max_payload < 512)
+		max_payload = 512;
 
-	/* TODO: The above encapsulate function needs to recognize when a
-	 * packet needs to be split for a specified node. It should create
-	 * a list of skb's that we could then iterate over for the below
-	 * call to schedule our writes.  */
-
-	/* XXX: Right now we accept that we don't exactly follow RFC. When
-	 * we do, we will send ARP requests via GASP format, and so we won't
-	 * need this hack.  */
+	/* Set the transmission type for the packet.  Right now only ARP
+	 * packets are sent via GASP.  IP broadcast and IP multicast are not
+	 * yet supported properly, they too should use GASP. */
+	switch(proto) {
+	case __constant_htons(ETH_P_ARP):
+		tx_type = ETH1394_GASP;
+                max_payload -= ETHER1394_OVERHEAD;
+		break;
+	default:
+		tx_type = ETH1394_WRREQ;
+	}
+
+	dg_size = skb->len;
 
 	spin_lock_irqsave (&priv->lock, flags);
-	addr = (u64)priv->fifo_hi[NODEID_TO_NODE(dest_node)] << 32 |
-		priv->fifo_lo[NODEID_TO_NODE(dest_node)];
+	dgl = priv->dgl[NODEID_TO_NODE(dest_node)];
+	if(max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
+		priv->dgl[NODEID_TO_NODE(dest_node)]++;
 	spin_unlock_irqrestore (&priv->lock, flags);
 
-	if (!addr)
-		addr = ETHER1394_REGION_ADDR;
-
+	ptask->hdr.words.word1 = 0;
+	ptask->hdr.words.word2 = 0;
+	ptask->hdr.words.word3 = 0;
+	ptask->hdr.words.word4 = 0;
 	ptask->skb = skb;
-	ptask->addr = addr;
-	ptask->dest_node = dest_node;
-	/* TODO: When 2.4 is out of the way, give each of our ethernet
-	 * dev's a workqueue to handle these.  */
-	INIT_WORK(&ptask->tq, hpsb_write_sched, ptask);
-	schedule_work(&ptask->tq);
+	ptask->priv = priv;
+	ptask->tx_type = tx_type;
+
+	if(tx_type != ETH1394_GASP) {
+		u64 addr;
 
+		spin_lock_irqsave(&priv->lock, flags);
+		addr = (u64)priv->fifo_hi[NODEID_TO_NODE(dest_node)] << 32 |
+			priv->fifo_lo[NODEID_TO_NODE(dest_node)];
+		spin_unlock_irqrestore(&priv->lock, flags);
+
+		ptask->addr = addr;
+		ptask->dest_node = dest_node;
+	}
+
+	ptask->tx_type = tx_type;
+	ptask->max_payload = max_payload;
+        ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload, proto,
+							     &ptask->hdr, dg_size,
+							     dgl);
+
+	/* Add the encapsulation header to the fragment */
+	tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr);
+	dev->trans_start = jiffies;
+	if(ether1394_send_packet(ptask, tx_len))
+		goto fail;
+
+	netif_wake_queue(dev);
 	return 0;
 fail:
-	printk("Failed in ether1394_tx\n");
-
-	if (skb != NULL)
-		dev_kfree_skb (skb);
+	if(ptask->packet)
+		ether1394_free_packet(ptask->packet); ptask->packet = NULL;
+	if(ptask)
+		kmem_cache_free(packet_task_cache, ptask); ptask = NULL;
+	if(skb != NULL) {
+		dev_kfree_skb(skb); skb = NULL;
+	}
 
 	spin_lock_irqsave (&priv->lock, flags);
 	priv->stats.tx_dropped++;
 	priv->stats.tx_errors++;
-	if (netif_queue_stopped (dev))
-		netif_wake_queue (dev);
 	spin_unlock_irqrestore (&priv->lock, flags);
+
+	if (netif_queue_stopped(dev))
+		netif_wake_queue(dev);
 
 	return 0;  /* returning non-zero causes serious problems */
 }
diff -Nru a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h
--- a/drivers/ieee1394/eth1394.h	Fri May  2 05:50:36 2003
+++ b/drivers/ieee1394/eth1394.h	Mon May 19 19:56:24 2003
@@ -24,6 +24,8 @@
 #ifndef __ETH1394_H
 #define __ETH1394_H
 
+#include "ieee1394.h"
+
 /* Register for incoming packets. This is 8192 bytes, which supports up to
  * 1600mbs. We'll need to change this if that ever becomes "small" :)  */
 #define ETHER1394_REGION_ADDR_LEN	8192
@@ -32,14 +34,24 @@
 
 /* GASP identifier numbers for IPv4 over IEEE 1394 */
 #define ETHER1394_GASP_SPECIFIER_ID	0x00005E
+#define ETHER1394_GASP_SPECIFIER_ID_HI	((ETHER1394_GASP_SPECIFIER_ID >> 8) & 0xffff)
+#define ETHER1394_GASP_SPECIFIER_ID_LO	(ETHER1394_GASP_SPECIFIER_ID & 0xff)
 #define ETHER1394_GASP_VERSION		1
 
+#define ETHER1394_OVERHEAD (2 * sizeof(quadlet_t))  /* GASP header overhead */
+
 /* Node set == 64 */
 #define NODE_SET			(ALL_NODES + 1)
 
 enum eth1394_bc_states { ETHER1394_BC_CLOSED, ETHER1394_BC_OPENED,
 			 ETHER1394_BC_CHECK };
 
+struct pdg_list {
+	struct list_head list;		/* partial datagram list per node */
+	unsigned int sz;		/* partial datagram list size per node	*/
+	spinlock_t lock;		/* partial datagram lock		*/
+};
+
 /* Private structure for our ethernet driver */
 struct eth1394_priv {
 	struct net_device_stats stats;	/* Device stats			 */
@@ -53,6 +65,8 @@
 	int broadcast_channel;		/* Async stream Broadcast Channel */
 	enum eth1394_bc_states bc_state; /* broadcast channel state	 */
 	struct hpsb_iso *iso;		/* Async stream recv handle	 */
+	struct pdg_list pdg[ALL_NODES]; /* partial RX datagram lists     */
+	int dgl[NODE_SET];              /* Outgoing datagram label per node */
 };
 
 struct host_info {
@@ -62,29 +76,20 @@
 
 typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type;
 
-/* This is our task struct. It's used for the packet complete callback.  */
-struct packet_task {
-	struct sk_buff *skb;	/* Socket buffer we are sending */
-	nodeid_t dest_node;	/* Destination of the packet */
-	u64 addr;		/* Address */
-	struct work_struct tq;	/* The task */
-	eth1394_tx_type tx_type;	/* Send data via GASP or Write Req. */
-};
-
 /* IP1394 headers */
 #include <asm/byteorder.h>
 
 /* Unfragmented */
 #if defined __BIG_ENDIAN_BITFIELD
 struct eth1394_uf_hdr {
-	u8 lf:2;
+	u16 lf:2;
 	u16 res:14;
 	u16 ether_type;		/* Ethernet packet type */
 } __attribute__((packed));
 #elif defined __LITTLE_ENDIAN_BITFIELD
 struct eth1394_uf_hdr {
 	u16 res:14;
-	u8 lf:2;
+	u16 lf:2;
 	u16 ether_type;
 } __attribute__((packed));
 #else
@@ -94,8 +99,8 @@
 /* First fragment */
 #if defined __BIG_ENDIAN_BITFIELD
 struct eth1394_ff_hdr {
-	u8 lf:2;
-	u8 res1:2;
+	u16 lf:2;
+	u16 res1:2;
 	u16 dg_size:12;		/* Datagram size */
 	u16 ether_type;		/* Ethernet packet type */
 	u16 dgl;		/* Datagram label */
@@ -104,8 +109,8 @@
 #elif defined __LITTLE_ENDIAN_BITFIELD
 struct eth1394_ff_hdr {
 	u16 dg_size:12;
-	u8 res1:2;
-	u8 lf:2;
+	u16 res1:2;
+	u16 lf:2;
 	u16 ether_type;
 	u16 dgl;
 	u16 res2;
@@ -117,21 +122,21 @@
 /* XXX: Subsequent fragments, including last */
 #if defined __BIG_ENDIAN_BITFIELD
 struct eth1394_sf_hdr {
-	u8 lf:2;
-	u8 res1:2;
+	u16 lf:2;
+	u16 res1:2;
 	u16 dg_size:12;		/* Datagram size */
-	u8 res2:6;
-	u16 fg_off:10;		/* Fragment offset */
+	u16 res2:4;
+	u16 fg_off:12;		/* Fragment offset */
 	u16 dgl;		/* Datagram label */
 	u16 res3;
 } __attribute__((packed));
 #elif defined __LITTLE_ENDIAN_BITFIELD
 struct eth1394_sf_hdr {
 	u16 dg_size:12;
-	u8 res1:2;
-	u8 lf:2;
-	u16 fg_off:10;
-	u8 res2:6;
+	u16 res1:2;
+	u16 lf:2;
+	u16 fg_off:12;
+	u16 res2:4;
 	u16 dgl;
 	u16 res3;
 } __attribute__((packed));
@@ -141,13 +146,13 @@
 
 #if defined __BIG_ENDIAN_BITFIELD
 struct eth1394_common_hdr {
-	u8 lf:2;
+	u16 lf:2;
 	u16 pad1:14;
 } __attribute__((packed));
 #elif defined __LITTLE_ENDIAN_BITFIELD
 struct eth1394_common_hdr {
 	u16 pad1:14;
-	u8 lf:2;
+	u16 lf:2;
 } __attribute__((packed));
 #else
 #error Unknown bit field type
@@ -198,5 +203,18 @@
 
 /* Network timeout */
 #define ETHER1394_TIMEOUT	100000
+
+/* This is our task struct. It's used for the packet complete callback.  */
+struct packet_task {
+	struct sk_buff *skb;
+	int outstanding_pkts;
+	eth1394_tx_type tx_type;
+	int max_payload;
+	struct hpsb_packet *packet;
+	struct eth1394_priv *priv;
+	union eth1394_hdr hdr;
+	u64 addr;
+	u16 dest_node;
+};
 
 #endif /* __ETH1394_H */
diff -Nru a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
--- a/drivers/ieee1394/ieee1394_core.c	Fri May  2 05:58:06 2003
+++ b/drivers/ieee1394/ieee1394_core.c	Mon May 19 19:56:20 2003
@@ -80,9 +80,12 @@
 static void run_packet_complete(struct hpsb_packet *packet)
 {
 	if (packet->complete_routine != NULL) {
-		packet->complete_routine(packet->complete_data);
+		void (*complete_routine)(void*) = packet->complete_routine;
+		void *complete_data = packet->complete_data;
+
 		packet->complete_routine = NULL;
 		packet->complete_data = NULL;
+		complete_routine(complete_data);
 	}
 	return;
 }
@@ -938,7 +941,7 @@
 {
         unsigned long flags;
         struct hpsb_packet *packet;
-        struct list_head *lh;
+        struct list_head *lh, *tlh;
         LIST_HEAD(llist);
 
         host->driver->devctl(host, CANCEL_REQUESTS, 0);
@@ -948,8 +951,9 @@
         INIT_LIST_HEAD(&host->pending_packets);
         spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
 
-        list_for_each(lh, &llist) {
+        list_for_each_safe(lh, tlh, &llist) {
                 packet = list_entry(lh, struct hpsb_packet, list);
+                list_del(&packet->list);
                 packet->state = hpsb_complete;
                 packet->ack_code = ACKX_ABORTED;
                 up(&packet->state_change);
@@ -962,7 +966,7 @@
         unsigned long flags;
         struct hpsb_packet *packet;
         unsigned long expire;
-        struct list_head *lh, *next;
+        struct list_head *lh, *next, *tlh;
         LIST_HEAD(expiredlist);
 
         spin_lock_irqsave(&host->csr.lock, flags);
@@ -990,8 +994,9 @@
 
         spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
 
-        list_for_each(lh, &expiredlist) {
+        list_for_each_safe(lh, tlh, &expiredlist) {
                 packet = list_entry(lh, struct hpsb_packet, list);
+                list_del(&packet->list);
                 packet->state = hpsb_complete;
                 packet->ack_code = ACKX_TIMEOUT;
                 up(&packet->state_change);
diff -Nru a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
--- a/drivers/ieee1394/ieee1394_transactions.c	Wed Mar  5 08:01:26 2003
+++ b/drivers/ieee1394/ieee1394_transactions.c	Mon May 19 19:56:22 2003
@@ -147,6 +147,8 @@
 	spin_lock_irqsave(&tp->lock, flags);
 	
 	packet->tlabel = find_next_zero_bit(tp->pool, 64, tp->next);
+	if(packet->tlabel > 63)
+		packet->tlabel = find_first_zero_bit(tp->pool, 64);
 	tp->next = (packet->tlabel + 1) % 64;
 	/* Should _never_ happen */
 	BUG_ON(test_and_set_bit(packet->tlabel, tp->pool));
@@ -573,10 +575,6 @@
 		   quadlet_t *buffer, size_t length, u32 specifier_id,
 		   unsigned int version)
 {
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-	int i;
-#endif
-
 	struct hpsb_packet *packet;
 	int retval = 0;
 	u16 specifier_id_hi = (specifier_id & 0x00ffff00) >> 8;
@@ -603,14 +601,6 @@
 	packet->data[1] = cpu_to_be32((specifier_id_lo << 24) | (version & 0x00ffffff));
 
 	memcpy(&(packet->data[2]), buffer, length - 4);
-
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-	HPSB_DEBUG("GASP: packet->header_size = %d", packet->header_size);
-	HPSB_DEBUG("GASP: packet->data_size = %d", packet->data_size);
-
-	for(i=0; i<(packet->data_size/4); i++)
-		HPSB_DEBUG("GASP: data[%d]: 0x%08x", i*4, be32_to_cpu(packet->data[i]));
-#endif
 
 	packet->generation = generation;
 
diff -Nru a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
--- a/drivers/ieee1394/ohci1394.c	Mon May 19 07:50:25 2003
+++ b/drivers/ieee1394/ohci1394.c	Tue May 20 11:46:12 2003
@@ -164,7 +164,7 @@
 printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 931 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 938 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 static int phys_dma = 1;
@@ -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, OHCI_CONFIG_ROM_LEN);
 
 	cr.data = ohci->csr_config_rom_cpu;
 
@@ -3530,6 +3530,16 @@
 	}
 }
 
+
+#ifdef  CONFIG_PM
+static int ohci1394_pci_resume (struct pci_dev *dev)
+{
+	pci_enable_device(dev);
+	return 0;
+}
+#endif
+
+
 #define PCI_CLASS_FIREWIRE_OHCI     ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
 
 static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = {
@@ -3551,6 +3561,10 @@
 	.id_table =	ohci1394_pci_tbl,
 	.probe =	ohci1394_pci_probe,
 	.remove =	ohci1394_pci_remove,
+
+#ifdef  CONFIG_PM
+	.resume =	ohci1394_pci_resume,
+#endif  /* PM */
 };
 
 
diff -Nru a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
--- a/drivers/ieee1394/sbp2.c	Mon May 19 07:50:28 2003
+++ b/drivers/ieee1394/sbp2.c	Mon May 19 19:56:24 2003
@@ -79,7 +79,7 @@
 #include "sbp2.h"
 
 static char version[] __devinitdata =
-	"$Rev: 931 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 938 $ Ben Collins <bcollins@debian.org>";
 
 /*
  * Module load parameter definitions
@@ -2845,11 +2845,10 @@
 #define SPRINTF(args...) \
         do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
 
-static int sbp2scsi_proc_info(char *buffer, char **start, off_t offset,
-			      int length, int hostno, int inout)
+static int sbp2scsi_proc_info(struct Scsi_Host *scsi_host, char *buffer, char **start, off_t offset,
+			      int length, int inout)
 {
 	Scsi_Device *scd;
-	struct Scsi_Host *scsi_host;
 	struct hpsb_host *host;
 	char *pos = buffer;
 
@@ -2857,16 +2856,12 @@
 	if (inout)
 		return length;
 
-	scsi_host = scsi_host_hn_get(hostno);
-	if (!scsi_host)  /* if we couldn't find it, we return an error */
-		return -ESRCH;
-
 	host = hpsb_get_host_bykey(&sbp2_highlevel, (unsigned long)scsi_host);
 	if (!host) /* shouldn't happen, but... */
 		return -ESRCH;
 
-	SPRINTF("Host scsi%d             : SBP-2 IEEE-1394 (%s)\n", hostno,
-		host->driver->name);
+	SPRINTF("Host scsi%d             : SBP-2 IEEE-1394 (%s)\n",
+		scsi_host->host_no, host->driver->name);
 	SPRINTF("Driver version         : %s\n", version);
 
 	SPRINTF("\nModule options         :\n");
@@ -2899,8 +2894,6 @@
 
 	SPRINTF("\n");
 
-	/* release the reference count on this host */
-	scsi_host_put(scsi_host);
 	/* Calculate start of next buffer, and return value. */
 	*start = buffer + offset;
 
diff -Nru a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
--- a/drivers/isdn/hardware/avm/avm_cs.c	Sun May 25 17:00:00 2003
+++ b/drivers/isdn/hardware/avm/avm_cs.c	Wed May 28 08:01:07 2003
@@ -510,29 +510,30 @@
     return 0;
 } /* avmcs_event */
 
-/*====================================================================*/
+static struct pcmcia_driver avmcs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "avmcs_cs",
+	},
+	.attach		= avmcs_attach,
+	.detach		= avmcs_detach,
+};
 
 static int __init avmcs_init(void)
 {
-    servinfo_t serv;
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "avm_cs: Card Services release "
-	       "does not match!\n");
-	return -1;
-    }
-    register_pccard_driver(&dev_info, &avmcs_attach, &avmcs_detach);
-    return 0;
+	return pcmcia_register_driver(&avmcs_driver);
 }
 
 static void __exit avmcs_exit(void)
 {
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL) {
-	if (dev_list->state & DEV_CONFIG)
-	    avmcs_release((u_long)dev_list);
-	avmcs_detach(dev_list);
-    }
+	pcmcia_unregister_driver(&avmcs_driver);
+
+	/* XXX: this really needs to move into generic code.. */
+	while (dev_list != NULL) {
+		if (dev_list->state & DEV_CONFIG)
+			avmcs_release((u_long)dev_list);
+		avmcs_detach(dev_list);
+	}
 }
 
 module_init(avmcs_init);
diff -Nru a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c
--- a/drivers/isdn/hardware/eicon/divamnt.c	Wed May  7 08:47:30 2003
+++ b/drivers/isdn/hardware/eicon/divamnt.c	Thu May 29 22:42:48 2003
@@ -421,7 +421,7 @@
 		return (0);
 	}
 
-	devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DivasMAINT);
+	devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, "DivasMAINT");
 	return (1);
 }
 
diff -Nru a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
--- a/drivers/isdn/hisax/avma1_cs.c	Sun May 25 17:00:00 2003
+++ b/drivers/isdn/hisax/avma1_cs.c	Wed May 28 08:01:08 2003
@@ -515,30 +515,30 @@
     return 0;
 } /* avma1cs_event */
 
-/*====================================================================*/
+static struct pcmcia_driver avma1cs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "avma1_cs",
+	},
+	.attach		= avma1cs_attach,
+	.detach		= avma1cs_detach,
+};
 
 static int __init init_avma1_cs(void)
 {
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-        printk(KERN_NOTICE "avma1_cs: Card Services release "
-               "does not match!\n");
-        return -1;
-    }
-    register_pccard_driver(&dev_info, &avma1cs_attach, &avma1cs_detach);
-    return 0;
+	return pcmcia_register_driver(&avma1cs_driver);
 }
 
 static void __exit exit_avma1_cs(void)
 {
-    DEBUG(0, "avma1_cs: unloading\n");
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL)
-	if (dev_list->state & DEV_CONFIG)
-	    avma1cs_release((u_long)dev_list);
-        avma1cs_detach(dev_list);
+	pcmcia_unregister_driver(&avma1cs_driver);
+
+	/* XXX: this really needs to move into generic code.. */
+	while (dev_list != NULL) {
+		if (dev_list->state & DEV_CONFIG)
+			avma1cs_release((u_long)dev_list);
+		avma1cs_detach(dev_list);
+	}
 }
 
 module_init(init_avma1_cs);
diff -Nru a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
--- a/drivers/isdn/hisax/elsa_cs.c	Sat Apr 26 09:16:20 2003
+++ b/drivers/isdn/hisax/elsa_cs.c	Sun May 18 13:57:37 2003
@@ -531,28 +531,27 @@
     return 0;
 } /* elsa_cs_event */
 
-/*====================================================================*/
+static struct pcmcia_driver elsa_cs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "elsa_cs",
+	},
+	.attach		= elsa_cs_attach,
+	.detach		= elsa_cs_detach,
+};
 
 static int __init init_elsa_cs(void)
 {
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-        printk(KERN_NOTICE "elsa_cs: Card Services release "
-               "does not match!\n");
-        return -1;
-    }
-    register_pccard_driver(&dev_info, &elsa_cs_attach, &elsa_cs_detach);
-    return 0;
+	return pcmcia_register_driver(&elsa_cs_driver);
 }
 
 static void __exit exit_elsa_cs(void)
 {
-    DEBUG(0, "elsa_cs: unloading\n");
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL)
-        elsa_cs_detach(dev_list);
+	pcmcia_unregister_driver(&elsa_cs_driver);
+
+	/* XXX: this really needs to move into generic code.. */
+	while (dev_list != NULL)
+		elsa_cs_detach(dev_list);
 }
 
 module_init(init_elsa_cs);
diff -Nru a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
--- a/drivers/isdn/hisax/sedlbauer_cs.c	Sat Apr 26 09:16:20 2003
+++ b/drivers/isdn/hisax/sedlbauer_cs.c	Sun May 18 13:57:37 2003
@@ -633,34 +633,32 @@
     return 0;
 } /* sedlbauer_event */
 
-/*====================================================================*/
+static struct pcmcia_driver sedlbauer_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "sedlbauer_cs",
+	},
+	.attach		= sedlbauer_attach,
+	.detach		= sedlbauer_detach,
+};
 
 static int __init init_sedlbauer_cs(void)
 {
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "sedlbauer_cs: Card Services release "
-	       "does not match!\n");
-	return -1;
-    }
-    register_pccard_driver(&dev_info, &sedlbauer_attach, &sedlbauer_detach);
-    return 0;
+	return pcmcia_register_driver(&sedlbauer_driver);
 }
 
 static void __exit exit_sedlbauer_cs(void)
 {
-    DEBUG(0, "sedlbauer_cs: unloading\n");
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL) {
-	del_timer(&dev_list->release);
-	if (dev_list->state & DEV_CONFIG)
-	    sedlbauer_release((u_long)dev_list);
-	sedlbauer_detach(dev_list);
-    }
+	pcmcia_unregister_driver(&sedlbauer_driver);
+
+	/* XXX: this really needs to move into generic code.. */
+	while (dev_list != NULL) {
+		del_timer(&dev_list->release);
+		if (dev_list->state & DEV_CONFIG)
+			sedlbauer_release((u_long)dev_list);
+		sedlbauer_detach(dev_list);
+	}
 }
 
 module_init(init_sedlbauer_cs);
 module_exit(exit_sedlbauer_cs);
-
diff -Nru a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
--- a/drivers/isdn/i4l/isdn_tty.c	Mon Apr 21 20:58:42 2003
+++ b/drivers/isdn/i4l/isdn_tty.c	Mon May 26 15:29:23 2003
@@ -64,10 +64,8 @@
 
 #ifdef CONFIG_DEVFS_FS
 static char *isdn_ttyname_ttyI = "isdn/ttyI%d";
-static char *isdn_ttyname_cui = "isdn/cui%d";
 #else
 static char *isdn_ttyname_ttyI = "ttyI";
-static char *isdn_ttyname_cui = "cui";
 #endif
 
 struct isdn_modem isdn_mdm;
@@ -1652,41 +1650,16 @@
 #endif
 	}
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == ISDN_SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ISDN_ASYNC_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-			return -EBUSY;
-		if ((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ISDN_ASYNC_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-			return -EBUSY;
-		info->flags |= ISDN_ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-	/*
 	 * If non-blocking mode is set, then make the check up front
 	 * and then exit.
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
-	if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -1720,8 +1693,7 @@
 #endif
 			break;
 		}
-		if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
-		    !(info->flags & ISDN_ASYNC_CLOSING) &&
+		if (!(info->flags & ISDN_ASYNC_CLOSING) &&
 		    (do_clocal || (info->msr & UART_MSR_DCD))) {
 			break;
 		}
@@ -1797,14 +1769,9 @@
 		return retval;
 	}
 	if ((info->count == 1) && (info->flags & ISDN_ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == ISDN_SERIAL_TYPE_NORMAL)
-			*tty->termios = info->normal_termios;
-		else
-			*tty->termios = info->callout_termios;
+		*tty->termios = info->normal_termios;
 		isdn_tty_change_speed(info);
 	}
-	info->session = current->session;
-	info->pgrp = current->pgrp;
 #ifdef ISDN_DEBUG_MODEM_OPEN
 	printk(KERN_DEBUG "isdn_tty_open ttyi%d successful...\n", info->line);
 #endif
@@ -1865,8 +1832,6 @@
 	 */
 	if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
 		info->normal_termios = *tty->termios;
-	if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
 
 	tty->closing = 1;
 	/*
@@ -1904,8 +1869,7 @@
 		schedule_timeout(HZ/2);
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE |
-			 ISDN_ASYNC_CLOSING);
+	info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	restore_flags(flags);
 #ifdef ISDN_DEBUG_MODEM_OPEN
@@ -1927,7 +1891,7 @@
 		return;
 	isdn_tty_shutdown(info);
 	info->count = 0;
-	info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ISDN_ASYNC_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -2054,7 +2018,7 @@
 	m->tty_modem.minor_start = 0;
 	m->tty_modem.num = ISDN_MAX_CHANNELS;
 	m->tty_modem.type = TTY_DRIVER_TYPE_SERIAL;
-	m->tty_modem.subtype = ISDN_SERIAL_TYPE_NORMAL;
+	m->tty_modem.subtype = SERIAL_TYPE_NORMAL;
 	m->tty_modem.init_termios = tty_std_termios;
 	m->tty_modem.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 	m->tty_modem.flags = TTY_DRIVER_REAL_RAW;
@@ -2078,26 +2042,12 @@
 	m->tty_modem.start = NULL;
 	m->tty_modem.hangup = isdn_tty_hangup;
 	m->tty_modem.driver_name = "isdn_tty";
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	m->cua_modem = m->tty_modem;
-	m->cua_modem.name = isdn_ttyname_cui;
-	m->cua_modem.major = ISDN_TTYAUX_MAJOR;
-	m->tty_modem.minor_start = 0;
-	m->cua_modem.subtype = ISDN_SERIAL_TYPE_CALLOUT;
 
 	retval = tty_register_driver(&m->tty_modem);
 	if (retval) {
 		printk(KERN_WARNING "isdn_tty: Couldn't register modem-device\n");
 		goto err;
 	}
-	retval = tty_register_driver(&m->cua_modem);
-	if (retval) {
-		printk(KERN_WARNING "isdn_tty: Couldn't register modem-callout-device\n");
-		goto err_unregister_tty;
-	}
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 		info = &m->info[i];
 #ifdef CONFIG_ISDN_TTY_FAX
@@ -2121,7 +2071,6 @@
 		info->x_char = 0;
 		info->count = 0;
 		info->blocked_open = 0;
-		info->callout_termios = m->cua_modem.init_termios;
 		info->normal_termios = m->tty_modem.init_termios;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
@@ -2167,7 +2116,6 @@
 #endif
 		kfree(info->xmit_buf - 4);
 	}
-	tty_unregister_driver(&isdn_mdm.cua_modem);
  err_unregister_tty:
 	tty_unregister_driver(&isdn_mdm.tty_modem);
  err:
@@ -2189,7 +2137,6 @@
 #endif
 		kfree(info->xmit_buf - 4);
 	}
-	tty_unregister_driver(&isdn_mdm.cua_modem);
 	tty_unregister_driver(&isdn_mdm.tty_modem);
 }
 
@@ -2334,7 +2281,7 @@
 }
 
 #define TTY_IS_ACTIVE(info) \
-	(info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
+	(info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
 
 static int
 isdn_tty_stat_callback(struct isdn_slot *slot, isdn_ctrl *c)
@@ -2833,9 +2780,7 @@
 		}
 		if (info->tty->ldisc.flush_buffer)
 			info->tty->ldisc.flush_buffer(info->tty);
-		if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
-		    (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
-		       (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
+		if (info->flags & ISDN_ASYNC_CHECK_CD) {
 			tty_hangup(info->tty);
 		}
 		restore_flags(flags);
diff -Nru a/drivers/isdn/i4l/isdn_tty.h b/drivers/isdn/i4l/isdn_tty.h
--- a/drivers/isdn/i4l/isdn_tty.h	Tue Oct 29 19:01:05 2002
+++ b/drivers/isdn/i4l/isdn_tty.h	Mon May 26 15:29:24 2003
@@ -116,7 +116,6 @@
 struct isdn_modem {
   int                refcount;			   /* Number of opens        */
   struct tty_driver  tty_modem;			   /* tty-device             */
-  struct tty_driver  cua_modem;			   /* cua-device             */
   struct tty_struct  *modem_table[ISDN_MAX_CHANNELS]; /* ?? copied from Orig */
   struct termios     *modem_termios[ISDN_MAX_CHANNELS];
   struct termios     *modem_termios_locked[ISDN_MAX_CHANNELS];
diff -Nru a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c
--- a/drivers/macintosh/macserial.c	Wed May  7 07:11:08 2003
+++ b/drivers/macintosh/macserial.c	Mon May 26 15:29:14 2003
@@ -105,12 +105,11 @@
 #endif
 #define ZS_CLOCK         3686400 	/* Z8530 RTxC input clock rate */
 
-static struct tty_driver serial_driver, callout_driver;
+static struct tty_driver serial_driver;
 static int serial_refcount;
 
 /* serial subtype definitions */
 #define SERIAL_TYPE_NORMAL	1
-#define SERIAL_TYPE_CALLOUT	2
 
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
@@ -492,7 +491,7 @@
 	    && info->tty && !C_CLOCAL(info->tty)) {
 		if (status & DCD) {
 			wake_up_interruptible(&info->open_wait);
-		} else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
+		} else {
 			if (info->tty)
 				tty_hangup(info->tty);
 		}
@@ -1965,8 +1964,6 @@
 	 */
 	if (info->flags & ZILOG_NORMAL_ACTIVE)
 		info->normal_termios = *tty->termios;
-	if (info->flags & ZILOG_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -2021,8 +2018,7 @@
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
-			 ZILOG_CLOSING);
+	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 }
 
@@ -2087,7 +2083,7 @@
 	shutdown(info);
 	info->event = 0;
 	info->count = 0;
-	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE);
+	info->flags &= ~ZILOG_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -2119,43 +2115,17 @@
 	}
 
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ZILOG_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
-		    (info->flags & ZILOG_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
-		    (info->flags & ZILOG_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ZILOG_CALLOUT_ACTIVE;
-		return 0;
-	}
-
-	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & ZILOG_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ZILOG_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & ZILOG_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
 
 	/*
 	 * Block waiting for the carrier detect and the line to become
@@ -2175,8 +2145,7 @@
 	info->blocked_open++;
 	while (1) {
 		spin_lock_irq(&info->lock);
-		if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
-		    (tty->termios->c_cflag & CBAUD) &&
+		if ((tty->termios->c_cflag & CBAUD) &&
 		    !info->is_irda)
 			zs_rtsdtr(info, 1);
 		spin_unlock_irq(&info->lock);
@@ -2193,8 +2162,7 @@
 #endif
 			break;
 		}
-		if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
-		    !(info->flags & ZILOG_CLOSING) &&
+		if (!(info->flags & ZILOG_CLOSING) &&
 		    (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD)))
 			break;
 		if (signal_pending(current)) {
@@ -2291,10 +2259,7 @@
 	}
 
 	if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->normal_termios;
-		else 
-			*tty->termios = info->callout_termios;
+		*tty->termios = info->normal_termios;
 		change_speed(info, 0);
 	}
 #ifdef CONFIG_SERIAL_CONSOLE
@@ -2305,9 +2270,6 @@
 	}
 #endif
 
-	info->session = current->session;
-	info->pgrp = current->pgrp;
-
 	OPNDBG("rs_open %s successful...\n", tty->name);
 	return 0;
 }
@@ -2644,25 +2606,8 @@
 	serial_driver.wait_until_sent = rs_wait_until_sent;
 	serial_driver.read_proc = macserial_read_proc;
 
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	callout_driver = serial_driver;
-#ifdef CONFIG_DEVFS_FS
-	callout_driver.name = "cua/";
-#else
-	callout_driver.name = "cua";
-#endif /* CONFIG_DEVFS_FS */
-	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(&serial_driver))
 		printk(KERN_ERR "Error: couldn't register serial driver\n");
-	if (tty_register_driver(&callout_driver))
-		printk(KERN_ERR "Error: couldn't register callout driver\n");
 
 	for (channel = 0; channel < zs_channels_found; ++channel) {
 #ifdef CONFIG_KGDB
@@ -2713,7 +2658,6 @@
 		info->blocked_open = 0;
 		INIT_WORK(&info->tqueue, do_softint, info);
 		spin_lock_init(&info->lock);
-		info->callout_termios = callout_driver.init_termios;
 		info->normal_termios = serial_driver.init_termios;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
@@ -2758,7 +2702,6 @@
 		}
 	}
 	spin_unlock_irqrestore(&info->lock, flags);
-	tty_unregister_driver(&callout_driver);
 	tty_unregister_driver(&serial_driver);
 
 	if (tmp_buf) {
diff -Nru a/drivers/macintosh/macserial.h b/drivers/macintosh/macserial.h
--- a/drivers/macintosh/macserial.h	Sun Mar 16 15:21:50 2003
+++ b/drivers/macintosh/macserial.h	Mon May 26 15:29:14 2003
@@ -156,15 +156,12 @@
 	int			line;
 	int			count;	    /* # of fd on device */
 	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
 	unsigned char 		*xmit_buf;
 	int			xmit_head;
 	int			xmit_tail;
 	int			xmit_cnt;
 	struct work_struct	tqueue;
 	struct termios		normal_termios;
-	struct termios		callout_termios;
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
 
diff -Nru a/drivers/md/linear.c b/drivers/md/linear.c
--- a/drivers/md/linear.c	Thu Apr  3 17:21:33 2003
+++ b/drivers/md/linear.c	Mon May 26 19:01:37 2003
@@ -20,7 +20,6 @@
 
 #include <linux/raid/md.h>
 #include <linux/slab.h>
-#include <linux/bio.h>
 #include <linux/raid/linear.h>
 
 #define MAJOR_NR MD_MAJOR
@@ -67,7 +66,18 @@
 	dev0 = which_dev(mddev, bio->bi_sector);
 	maxsectors = (dev0->size << 1) - (bio->bi_sector - (dev0->offset<<1));
 
-	return (maxsectors - bio_sectors) << 9;
+	if (maxsectors < bio_sectors)
+		maxsectors = 0;
+	else
+		maxsectors -= bio_sectors;
+
+	if (maxsectors <= (PAGE_SIZE >> 9 ) && bio_sectors == 0)
+		return biovec->bv_len;
+	/* The bytes available at this offset could be really big,
+	 * so we cap at 2^31 to avoid overflow */
+	if (maxsectors > (1 << (31-9)))
+		return 1<<31;
+	return maxsectors << 9;
 }
 
 static int linear_run (mddev_t *mddev)
@@ -79,7 +89,8 @@
 	unsigned int curr_offset;
 	struct list_head *tmp;
 
-	conf = kmalloc (sizeof (*conf), GFP_KERNEL);
+	conf = kmalloc (sizeof (*conf) + mddev->raid_disks*sizeof(dev_info_t),
+			GFP_KERNEL);
 	if (!conf)
 		goto out;
 	memset(conf, 0, sizeof(*conf));
@@ -209,6 +220,23 @@
 		bio_io_error(bio, bio->bi_size);
 		return 0;
 	}
+	if (unlikely(bio->bi_sector + (bio->bi_size >> 9) >
+		     (tmp_dev->offset + tmp_dev->size)<<1)) {
+		/* This bio crosses a device boundary, so we have to
+		 * split it.
+		 */
+		struct bio_pair *bp;
+		bp = bio_split(bio, bio_split_pool, 
+			       (bio->bi_sector + (bio->bi_size >> 9) -
+				(tmp_dev->offset + tmp_dev->size))<<1);
+		if (linear_make_request(q, &bp->bio1))
+			generic_make_request(&bp->bio1);
+		if (linear_make_request(q, &bp->bio2))
+			generic_make_request(&bp->bio2);
+		bio_pair_release(bp);
+		return 0;
+	}
+		    
 	bio->bi_bdev = tmp_dev->rdev->bdev;
 	bio->bi_sector = bio->bi_sector - (tmp_dev->offset << 1) + tmp_dev->rdev->data_offset;
 
@@ -226,12 +254,13 @@
 	seq_printf(seq, "      ");
 	for (j = 0; j < conf->nr_zones; j++)
 	{
+		char b[BDEVNAME_SIZE];
 		seq_printf(seq, "[%s",
-			bdev_partition_name(conf->hash_table[j].dev0->rdev->bdev));
+			   bdevname(conf->hash_table[j].dev0->rdev->bdev,b));
 
 		if (conf->hash_table[j].dev1)
 			seq_printf(seq, "/%s] ",
-			  bdev_partition_name(conf->hash_table[j].dev1->rdev->bdev));
+				   bdevname(conf->hash_table[j].dev1->rdev->bdev,b));
 		else
 			seq_printf(seq, "] ");
 	}
diff -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	Sun May 25 02:45:06 2003
+++ b/drivers/md/md.c	Mon May 26 19:01:37 2003
@@ -33,7 +33,6 @@
 #include <linux/linkage.h>
 #include <linux/raid/md.h>
 #include <linux/sysctl.h>
-#include <linux/bio.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/buffer_head.h> /* for invalidate_bdev */
 #include <linux/suspend.h>
@@ -350,7 +349,7 @@
 
 static int read_disk_sb(mdk_rdev_t * rdev)
 {
-
+	char b[BDEVNAME_SIZE];
 	if (!rdev->sb_page) {
 		MD_BUG();
 		return -EINVAL;
@@ -366,7 +365,7 @@
 
 fail:
 	printk(KERN_ERR "md: disabled device %s, could not read superblock.\n",
-		bdev_partition_name(rdev->bdev));
+		bdevname(rdev->bdev,b));
 	return -EINVAL;
 }
 
@@ -474,6 +473,7 @@
  */
 static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
 {
+	char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
 	mdp_super_t *sb;
 	int ret;
 	sector_t sb_offset;
@@ -492,11 +492,12 @@
 
 	ret = -EINVAL;
 
+	bdevname(rdev->bdev, b);
 	sb = (mdp_super_t*)page_address(rdev->sb_page);
 
 	if (sb->md_magic != MD_SB_MAGIC) {
 		printk(KERN_ERR "md: invalid raid superblock magic on %s\n",
-			bdev_partition_name(rdev->bdev));
+		       b);
 		goto abort;
 	}
 
@@ -504,13 +505,13 @@
 	    sb->minor_version != 90) {
 		printk(KERN_WARNING "Bad version number %d.%d on %s\n",
 			sb->major_version, sb->minor_version,
-			bdev_partition_name(rdev->bdev));
+			b);
 		goto abort;
 	}
 
 	if (sb->md_minor >= MAX_MD_DEVS) {
 		printk(KERN_ERR "md: %s: invalid raid minor (%x)\n",
-			bdev_partition_name(rdev->bdev), sb->md_minor);
+			b, sb->md_minor);
 		goto abort;
 	}
 	if (sb->raid_disks <= 0)
@@ -518,7 +519,7 @@
 
 	if (calc_sb_csum(sb) != sb->sb_csum) {
 		printk(KERN_WARNING "md: invalid superblock checksum on %s\n",
-			bdev_partition_name(rdev->bdev));
+			b);
 		goto abort;
 	}
 
@@ -537,15 +538,13 @@
 		mdp_super_t *refsb = (mdp_super_t*)page_address(refdev->sb_page);
 		if (!uuid_equal(refsb, sb)) {
 			printk(KERN_WARNING "md: %s has different UUID to %s\n",
-				bdev_partition_name(rdev->bdev),
-				bdev_partition_name(refdev->bdev));
+				b, bdevname(refdev->bdev,b2));
 			goto abort;
 		}
 		if (!sb_equal(refsb, sb)) {
 			printk(KERN_WARNING "md: %s has same UUID"
-				" but different superblock to %s\n",
-				bdev_partition_name(rdev->bdev),
-				bdev_partition_name(refdev->bdev));
+			       " but different superblock to %s\n",
+			       b, bdevname(refdev->bdev, b2));
 			goto abort;
 		}
 		ev1 = md_event(sb);
@@ -757,6 +756,7 @@
 	struct mdp_superblock_1 *sb;
 	int ret;
 	sector_t sb_offset;
+	char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
 
 	/*
 	 * Calculate the position of the superblock.
@@ -800,7 +800,7 @@
 
 	if (calc_sb_1_csum(sb) != sb->sb_csum) {
 		printk("md: invalid superblock checksum on %s\n",
-			bdev_partition_name(rdev->bdev));
+			bdevname(rdev->bdev,b));
 		return -EINVAL;
 	}
 	rdev->preferred_minor = 0xffff;
@@ -819,8 +819,8 @@
 		    sb->chunksize != refsb->chunksize) {
 			printk(KERN_WARNING "md: %s has strangely different"
 				" superblock to %s\n",
-				bdev_partition_name(rdev->bdev),
-				bdev_partition_name(refdev->bdev));
+				bdevname(rdev->bdev,b),
+				bdevname(refdev->bdev,b2));
 			return -EINVAL;
 		}
 		ev1 = le64_to_cpu(sb->events);
@@ -988,6 +988,7 @@
 static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
 {
 	mdk_rdev_t *same_pdev;
+	char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
 
 	if (rdev->mddev) {
 		MD_BUG();
@@ -999,8 +1000,8 @@
 			"md%d: WARNING: %s appears to be on the same physical"
 	 		" disk as %s. True\n     protection against single-disk"
 			" failure might be compromised.\n",
-			mdidx(mddev), bdev_partition_name(rdev->bdev),
-			bdev_partition_name(same_pdev->bdev));
+			mdidx(mddev), bdevname(rdev->bdev,b),
+			bdevname(same_pdev->bdev,b2));
 
 	/* Verify rdev->desc_nr is unique.
 	 * If it is -1, assign a free number, else
@@ -1019,18 +1020,19 @@
 			
 	list_add(&rdev->same_set, &mddev->disks);
 	rdev->mddev = mddev;
-	printk(KERN_INFO "md: bind<%s>\n", bdev_partition_name(rdev->bdev));
+	printk(KERN_INFO "md: bind<%s>\n", bdevname(rdev->bdev,b));
 	return 0;
 }
 
 static void unbind_rdev_from_array(mdk_rdev_t * rdev)
 {
+	char b[BDEVNAME_SIZE];
 	if (!rdev->mddev) {
 		MD_BUG();
 		return;
 	}
 	list_del_init(&rdev->same_set);
-	printk(KERN_INFO "md: unbind<%s>\n", bdev_partition_name(rdev->bdev));
+	printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
 	rdev->mddev = NULL;
 }
 
@@ -1072,8 +1074,9 @@
 
 static void export_rdev(mdk_rdev_t * rdev)
 {
+	char b[BDEVNAME_SIZE];
 	printk(KERN_INFO "md: export_rdev(%s)\n",
-		bdev_partition_name(rdev->bdev));
+		bdevname(rdev->bdev,b));
 	if (rdev->mddev)
 		MD_BUG();
 	free_disk_sb(rdev);
@@ -1154,8 +1157,9 @@
 
 static void print_rdev(mdk_rdev_t *rdev)
 {
+	char b[BDEVNAME_SIZE];
 	printk(KERN_INFO "md: rdev %s, SZ:%08llu F:%d S:%d DN:%u\n",
-		bdev_partition_name(rdev->bdev), (unsigned long long)rdev->size,
+		bdevname(rdev->bdev,b), (unsigned long long)rdev->size,
 	       	rdev->faulty, rdev->in_sync, rdev->desc_nr);
 	if (rdev->sb_loaded) {
 		printk(KERN_INFO "md: rdev superblock:\n");
@@ -1169,6 +1173,7 @@
 	struct list_head *tmp, *tmp2;
 	mdk_rdev_t *rdev;
 	mddev_t *mddev;
+	char b[BDEVNAME_SIZE];
 
 	printk("\n");
 	printk("md:	**********************************\n");
@@ -1178,7 +1183,7 @@
 		printk("md%d: ", mdidx(mddev));
 
 		ITERATE_RDEV(mddev,rdev,tmp2)
-			printk("<%s>", bdev_partition_name(rdev->bdev));
+			printk("<%s>", bdevname(rdev->bdev,b));
 		printk("\n");
 
 		ITERATE_RDEV(mddev,rdev,tmp2)
@@ -1191,7 +1196,7 @@
 
 static int write_disk_sb(mdk_rdev_t * rdev)
 {
-
+	char b[BDEVNAME_SIZE];
 	if (!rdev->sb_loaded) {
 		MD_BUG();
 		return 1;
@@ -1202,14 +1207,14 @@
 	}
 
 	dprintk(KERN_INFO "(write) %s's sb offset: %llu\n",
-		bdev_partition_name(rdev->bdev),
+		bdevname(rdev->bdev,b),
 	       (unsigned long long)rdev->sb_offset);
   
 	if (sync_page_io(rdev->bdev, rdev->sb_offset<<1, MD_SB_BYTES, rdev->sb_page, WRITE))
 		return 0;
 
 	printk("md: write_disk_sb failed for device %s\n", 
-		bdev_partition_name(rdev->bdev));
+		bdevname(rdev->bdev,b));
 	return 1;
 }
 
@@ -1260,11 +1265,12 @@
 
 	err = 0;
 	ITERATE_RDEV(mddev,rdev,tmp) {
+		char b[BDEVNAME_SIZE];
 		dprintk(KERN_INFO "md: ");
 		if (rdev->faulty)
 			dprintk("(skipping faulty ");
 
-		dprintk("%s ", bdev_partition_name(rdev->bdev));
+		dprintk("%s ", bdevname(rdev->bdev,b));
 		if (!rdev->faulty) {
 			err += write_disk_sb(rdev);
 		} else
@@ -1328,7 +1334,7 @@
 	if (!size) {
 		printk(KERN_WARNING 
 			"md: %s has zero or unknown size, marking faulty!\n",
-			bdev_partition_name(rdev->bdev));
+			bdevname(rdev->bdev,b));
 		err = -EINVAL;
 		goto abort_free;
 	}
@@ -1339,13 +1345,13 @@
 		if (err == -EINVAL) {
 			printk(KERN_WARNING 
 				"md: %s has invalid sb, not importing!\n",
-				bdev_partition_name(rdev->bdev));
+				bdevname(rdev->bdev,b));
 			goto abort_free;
 		}
 		if (err < 0) {
 			printk(KERN_WARNING 
 				"md: could not read %s's sb, not importing!\n",
-				bdev_partition_name(rdev->bdev));
+				bdevname(rdev->bdev,b));
 			goto abort_free;
 		}
 	}
@@ -1373,6 +1379,7 @@
 	int i;
 	struct list_head *tmp;
 	mdk_rdev_t *rdev, *freshest;
+	char b[BDEVNAME_SIZE];
 
 	freshest = NULL;
 	ITERATE_RDEV(mddev,rdev,tmp)
@@ -1387,7 +1394,7 @@
 			printk( KERN_ERR \
 				"md: fatal superblock inconsistency in %s"
 				" -- removing from array\n", 
-				bdev_partition_name(rdev->bdev));
+				bdevname(rdev->bdev,b));
 			kick_rdev_from_array(rdev);
 		}
 
@@ -1402,7 +1409,7 @@
 			    validate_super(mddev, rdev)) {
 				printk(KERN_WARNING "md: kicking non-fresh %s"
 					" from array!\n",
-					bdev_partition_name(rdev->bdev));
+					bdevname(rdev->bdev,b));
 				kick_rdev_from_array(rdev);
 				continue;
 			}
@@ -1490,6 +1497,7 @@
 	struct list_head *tmp;
 	mdk_rdev_t *rdev;
 	struct gendisk *disk;
+	char b[BDEVNAME_SIZE];
 
 	if (list_empty(&mddev->disks)) {
 		MD_BUG();
@@ -1548,7 +1556,7 @@
 				printk(KERN_WARNING
 					"md: Dev %s smaller than chunk_size:"
 					" %lluk < %dk\n",
-					bdev_partition_name(rdev->bdev),
+					bdevname(rdev->bdev,b),
 					(unsigned long long)rdev->size,
 					chunk_size / 1024);
 				return -EINVAL;
@@ -1670,13 +1678,12 @@
 	int err = 0;
 	struct gendisk *disk = disks[mdidx(mddev)];
 
-	if (atomic_read(&mddev->active)>2) {
-		printk("md: md%d still in use.\n",mdidx(mddev));
-		err = -EBUSY;
-		goto out;
-	}
-
 	if (mddev->pers) {
+		if (atomic_read(&mddev->active)>2) {
+			printk("md: md%d still in use.\n",mdidx(mddev));
+			return -EBUSY;
+		}
+
 		if (mddev->sync_thread) {
 			set_bit(MD_RECOVERY_INTR, &mddev->recovery);
 			md_unregister_thread(mddev->sync_thread);
@@ -1749,7 +1756,8 @@
 	printk(KERN_INFO "md: running: ");
 
 	ITERATE_RDEV(mddev,rdev,tmp) {
-		printk("<%s>", bdev_partition_name(rdev->bdev));
+		char b[BDEVNAME_SIZE];
+		printk("<%s>", bdevname(rdev->bdev,b));
 	}
 	printk("\n");
 
@@ -1778,6 +1786,7 @@
 	struct list_head *tmp;
 	mdk_rdev_t *rdev0, *rdev;
 	mddev_t *mddev;
+	char b[BDEVNAME_SIZE];
 
 	printk(KERN_INFO "md: autorun ...\n");
 	while (!list_empty(&pending_raid_disks)) {
@@ -1785,12 +1794,12 @@
 					 mdk_rdev_t, same_set);
 
 		printk(KERN_INFO "md: considering %s ...\n",
-			bdev_partition_name(rdev0->bdev));
+			bdevname(rdev0->bdev,b));
 		INIT_LIST_HEAD(&candidates);
 		ITERATE_RDEV_PENDING(rdev,tmp)
 			if (super_90_load(rdev, rdev0, 0) >= 0) {
 				printk(KERN_INFO "md:  adding %s ...\n",
-					bdev_partition_name(rdev->bdev));
+					bdevname(rdev->bdev,b));
 				list_move(&rdev->same_set, &candidates);
 			}
 		/*
@@ -1812,7 +1821,7 @@
 			 || !list_empty(&mddev->disks)) {
 			printk(KERN_WARNING 
 				"md: md%d already running, cannot run %s\n",
-				mdidx(mddev), bdev_partition_name(rdev0->bdev));
+				mdidx(mddev), bdevname(rdev0->bdev,b));
 			mddev_unlock(mddev);
 		} else {
 			printk(KERN_INFO "md: created md%d\n", mdidx(mddev));
@@ -1865,7 +1874,7 @@
 	if (start_rdev->faulty) {
 		printk(KERN_WARNING 
 			"md: can not autostart based on faulty %s!\n",
-			bdev_partition_name(start_rdev->bdev));
+			bdevname(start_rdev->bdev,b));
 		export_rdev(start_rdev);
 		return err;
 	}
@@ -2002,6 +2011,7 @@
 
 static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
 {
+	char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
 	mdk_rdev_t *rdev;
 	dev_t dev;
 	dev = MKDEV(info->major,info->minor);
@@ -2023,8 +2033,8 @@
 			if (err < 0) {
 				printk(KERN_WARNING 
 					"md: %s has different UUID to %s\n",
-					bdev_partition_name(rdev->bdev), 
-					bdev_partition_name(rdev0->bdev));
+					bdevname(rdev->bdev,b), 
+					bdevname(rdev0->bdev,b2));
 				export_rdev(rdev);
 				return -EINVAL;
 			}
@@ -2176,7 +2186,7 @@
 	return 0;
 busy:
 	printk(KERN_WARNING "md: cannot remove active disk %s from md%d ... \n",
-		bdev_partition_name(rdev->bdev), mdidx(mddev));
+		bdevname(rdev->bdev,b), mdidx(mddev));
 	return -EBUSY;
 }
 
@@ -2230,7 +2240,7 @@
 	if (rdev->faulty) {
 		printk(KERN_WARNING 
 			"md: can not hot-add faulty %s disk to md%d!\n",
-			bdev_partition_name(rdev->bdev), mdidx(mddev));
+			bdevname(rdev->bdev,b), mdidx(mddev));
 		err = -EINVAL;
 		goto abort_export;
 	}
@@ -2783,9 +2793,10 @@
 	seq_printf(seq, "unused devices: ");
 
 	ITERATE_RDEV_PENDING(rdev,tmp) {
+		char b[BDEVNAME_SIZE];
 		i++;
 		seq_printf(seq, "%s ",
-			      bdev_partition_name(rdev->bdev));
+			      bdevname(rdev->bdev,b));
 	}
 	if (!i)
 		seq_printf(seq, "<none>");
@@ -2940,8 +2951,9 @@
 
 		size = 0;
 		ITERATE_RDEV(mddev,rdev,tmp2) {
+			char b[BDEVNAME_SIZE];
 			seq_printf(seq, " %s[%d]",
-				bdev_partition_name(rdev->bdev), rdev->desc_nr);
+				bdevname(rdev->bdev,b), rdev->desc_nr);
 			if (rdev->faulty) {
 				seq_printf(seq, "(F)");
 				continue;
diff -Nru a/drivers/md/multipath.c b/drivers/md/multipath.c
--- a/drivers/md/multipath.c	Thu Apr  3 17:21:33 2003
+++ b/drivers/md/multipath.c	Mon May 26 19:01:37 2003
@@ -23,7 +23,6 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/raid/multipath.h>
-#include <linux/bio.h>
 #include <linux/buffer_head.h>
 #include <asm/atomic.h>
 
@@ -59,7 +58,7 @@
 static int multipath_map (mddev_t *mddev, mdk_rdev_t **rdevp)
 {
 	multipath_conf_t *conf = mddev_to_conf(mddev);
-	int i, disks = mddev->max_disks;
+	int i, disks = conf->raid_disks;
 
 	/*
 	 * Later we do read balancing on the read side 
@@ -128,9 +127,10 @@
 		/*
 		 * oops, IO error:
 		 */
+		char b[BDEVNAME_SIZE];
 		md_error (mp_bh->mddev, rdev);
 		printk(KERN_ERR "multipath: %s: rescheduling sector %llu\n", 
-		       bdev_partition_name(rdev->bdev), 
+		       bdevname(rdev->bdev,b), 
 		       (unsigned long long)bio->bi_sector);
 		multipath_reschedule_retry(mp_bh);
 	}
@@ -147,7 +147,7 @@
 {
 	int disk;
 
-	for (disk = 0; disk < conf->mddev->max_disks; disk++) {
+	for (disk = 0; disk < conf->raid_disks; disk++) {
 		mdk_rdev_t *rdev = conf->multipaths[disk].rdev;
 		if (rdev && rdev->in_sync)
 			return disk;
@@ -221,6 +221,7 @@
 		 * Mark disk as unusable
 		 */
 		if (!rdev->faulty) {
+			char b[BDEVNAME_SIZE];
 			rdev->in_sync = 0;
 			rdev->faulty = 1;
 			mddev->sb_dirty = 1;
@@ -228,7 +229,7 @@
 			printk(KERN_ALERT "multipath: IO failure on %s,"
 				" disabling IO path. \n	Operation continuing"
 				" on %d IO paths.\n",
-				bdev_partition_name (rdev->bdev),
+				bdevname (rdev->bdev,b),
 				conf->working_disks);
 		}
 	}
@@ -247,12 +248,13 @@
 	printk(" --- wd:%d rd:%d\n", conf->working_disks,
 			 conf->raid_disks);
 
-	for (i = 0; i < conf->mddev->max_disks; i++) {
+	for (i = 0; i < conf->raid_disks; i++) {
+		char b[BDEVNAME_SIZE];
 		tmp = conf->multipaths + i;
 		if (tmp->rdev)
 			printk(" disk%d, o:%d, dev:%s\n",
 				i,!tmp->rdev->faulty,
-			       bdev_partition_name(tmp->rdev->bdev));
+			       bdevname(tmp->rdev->bdev,b));
 	}
 }
 
@@ -327,6 +329,7 @@
 
 	md_check_recovery(mddev);
 	for (;;) {
+		char b[BDEVNAME_SIZE];
 		spin_lock_irqsave(&retry_list_lock, flags);
 		mp_bh = multipath_retry_list;
 		if (!mp_bh)
@@ -342,13 +345,13 @@
 		if (multipath_map (mddev, &rdev)<0) {
 			printk(KERN_ALERT "multipath: %s: unrecoverable IO read"
 				" error for block %llu\n",
-				bdev_partition_name(bio->bi_bdev), 
+				bdevname(bio->bi_bdev,b),
 				(unsigned long long)bio->bi_sector);
 			multipath_end_bh_io(mp_bh, 0);
 		} else {
 			printk(KERN_ERR "multipath: %s: redirecting sector %llu"
 				" to another IO path\n",
-				bdev_partition_name(bio->bi_bdev), 
+				bdevname(bio->bi_bdev,b),
 				(unsigned long long)bio->bi_sector);
 			bio->bi_bdev = rdev->bdev;
 			generic_make_request(bio);
@@ -386,6 +389,15 @@
 	}
 	memset(conf, 0, sizeof(*conf));
 
+	conf->multipaths = kmalloc(sizeof(struct multipath_info)*mddev->raid_disks,
+				   GFP_KERNEL);
+	if (!conf->multipaths) {
+		printk(KERN_ERR 
+			"multipath: couldn't allocate memory for md%d\n",
+			mdidx(mddev));
+		goto out_free_conf;
+	}
+
 	conf->working_disks = 0;
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		disk_idx = rdev->raid_disk;
@@ -444,6 +456,8 @@
 out_free_conf:
 	if (conf->pool)
 		mempool_destroy(conf->pool);
+	if (conf->multipaths)
+		kfree(conf->multipaths);
 	kfree(conf);
 	mddev->private = NULL;
 out:
@@ -457,6 +471,7 @@
 
 	md_unregister_thread(mddev->thread);
 	mempool_destroy(conf->pool);
+	kfree(conf->multipaths);
 	kfree(conf);
 	mddev->private = NULL;
 	return 0;
diff -Nru a/drivers/md/raid0.c b/drivers/md/raid0.c
--- a/drivers/md/raid0.c	Thu Apr  3 17:21:33 2003
+++ b/drivers/md/raid0.c	Mon May 26 19:01:37 2003
@@ -20,7 +20,6 @@
 
 #include <linux/module.h>
 #include <linux/raid/raid0.h>
-#include <linux/bio.h>
 
 #define MAJOR_NR MD_MAJOR
 #define MD_DRIVER
@@ -31,11 +30,13 @@
 {
 	int i, c, j;
 	sector_t current_offset, curr_zone_offset;
+	sector_t min_spacing;
 	raid0_conf_t *conf = mddev_to_conf(mddev);
 	mdk_rdev_t *smallest, *rdev1, *rdev2, *rdev;
 	struct list_head *tmp1, *tmp2;
 	struct strip_zone *zone;
 	int cnt;
+	char b[BDEVNAME_SIZE];
  
 	/*
 	 * The number of 'same size groups'
@@ -44,14 +45,15 @@
  
 	ITERATE_RDEV(mddev,rdev1,tmp1) {
 		printk("raid0: looking at %s\n",
-			bdev_partition_name(rdev1->bdev));
+			bdevname(rdev1->bdev,b));
 		c = 0;
 		ITERATE_RDEV(mddev,rdev2,tmp2) {
-			printk("raid0:   comparing %s(%llu) with %s(%llu)\n",
-				bdev_partition_name(rdev1->bdev),
-				(unsigned long long)rdev1->size,
-				bdev_partition_name(rdev2->bdev),
-				(unsigned long long)rdev2->size);
+			printk("raid0:   comparing %s(%llu)",
+			       bdevname(rdev1->bdev,b),
+			       (unsigned long long)rdev1->size);
+			printk(" with %s(%llu)\n",
+			       bdevname(rdev2->bdev,b),
+			       (unsigned long long)rdev2->size);
 			if (rdev2 == rdev1) {
 				printk("raid0:   END\n");
 				break;
@@ -76,19 +78,27 @@
 	}
 	printk("raid0: FINAL %d zones\n", conf->nr_strip_zones);
 
-	conf->strip_zone = vmalloc(sizeof(struct strip_zone)*
-				conf->nr_strip_zones);
+	conf->strip_zone = kmalloc(sizeof(struct strip_zone)*
+				conf->nr_strip_zones, GFP_KERNEL);
 	if (!conf->strip_zone)
 		return 1;
+	conf->devlist = kmalloc(sizeof(mdk_rdev_t*)*
+				conf->nr_strip_zones*mddev->raid_disks,
+				GFP_KERNEL);
+	if (!conf->devlist) {
+		kfree(conf);
+		return 1;
+	}
 
 	memset(conf->strip_zone, 0,sizeof(struct strip_zone)*
 				   conf->nr_strip_zones);
 	/* The first zone must contain all devices, so here we check that
-	 * there is a properly alignment of slots to devices and find them all
+	 * there is a proper alignment of slots to devices and find them all
 	 */
 	zone = &conf->strip_zone[0];
 	cnt = 0;
 	smallest = NULL;
+	zone->dev = conf->devlist;
 	ITERATE_RDEV(mddev, rdev1, tmp1) {
 		int j = rdev1->raid_disk;
 
@@ -115,7 +125,6 @@
 	zone->size = smallest->size * cnt;
 	zone->zone_offset = 0;
 
-	conf->smallest = zone;
 	current_offset = smallest->size;
 	curr_zone_offset = zone->size;
 
@@ -123,6 +132,7 @@
 	for (i = 1; i < conf->nr_strip_zones; i++)
 	{
 		zone = conf->strip_zone + i;
+		zone->dev = conf->strip_zone[i-1].dev + mddev->raid_disks;
 
 		printk("raid0: zone %d\n", i);
 		zone->dev_offset = current_offset;
@@ -130,8 +140,9 @@
 		c = 0;
 
 		for (j=0; j<cnt; j++) {
+			char b[BDEVNAME_SIZE];
 			rdev = conf->strip_zone[0].dev[j];
-			printk("raid0: checking %s ...", bdev_partition_name(rdev->bdev));
+			printk("raid0: checking %s ...", bdevname(rdev->bdev,b));
 			if (rdev->size > current_offset)
 			{
 				printk(" contained as device %d\n", c);
@@ -151,9 +162,6 @@
 		printk("raid0: zone->nb_dev: %d, size: %llu\n",
 			zone->nb_dev, (unsigned long long)zone->size);
 
-		if (!conf->smallest || (zone->size < conf->smallest->size))
-			conf->smallest = zone;
-
 		zone->zone_offset = curr_zone_offset;
 		curr_zone_offset += zone->size;
 
@@ -161,10 +169,32 @@
 		printk("raid0: current zone offset: %llu\n",
 			(unsigned long long)current_offset);
 	}
+
+	/* Now find appropriate hash spacing.
+	 * We want a number which causes most hash entries to cover
+	 * at most two strips, but the hash table must be at most
+	 * 1 PAGE.  We choose the smallest strip, or contiguous collection
+	 * of strips, that has big enough size.  We never consider the last
+	 * strip though as it's size has no bearing on the efficacy of the hash
+	 * table.
+	 */
+	conf->hash_spacing = curr_zone_offset;
+	min_spacing = curr_zone_offset;
+	sector_div(min_spacing, PAGE_SIZE/sizeof(struct strip_zone*));
+	for (i=0; i < conf->nr_strip_zones-1; i++) {
+		sector_t sz = 0;
+		for (j=i; j<conf->nr_strip_zones-1 &&
+			     sz < min_spacing ; j++)
+			sz += conf->strip_zone[j].size;
+		if (sz >= min_spacing && sz < conf->hash_spacing)
+			conf->hash_spacing = sz;
+	}
+
 	printk("raid0: done.\n");
 	return 0;
  abort:
-	vfree(conf->strip_zone);
+	kfree(conf->devlist);
+	kfree(conf->strip_zone);
 	return 1;
 }
 
@@ -179,27 +209,28 @@
 static int raid0_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *biovec)
 {
 	mddev_t *mddev = q->queuedata;
-	sector_t sector;
-	unsigned int chunk_sectors;
-	unsigned int bio_sectors;
-
-	chunk_sectors = mddev->chunk_size >> 9;
-	sector = bio->bi_sector;
-	bio_sectors = bio->bi_size >> 9;
-
-	return (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9;
+	sector_t sector = bio->bi_sector;
+	int max;
+	unsigned int chunk_sectors = mddev->chunk_size >> 9;
+	unsigned int bio_sectors = bio->bi_size >> 9;
+
+	max =  (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9;
+	if (max < 0) max = 0; /* bio_add cannot handle a negative return */
+	if (max <= biovec->bv_len && bio_sectors == 0)
+		return biovec->bv_len;
+	else 
+		return max;
 }
 
 static int raid0_run (mddev_t *mddev)
 {
 	unsigned  cur=0, i=0, nb_zone;
-	sector_t zone0_size;
 	s64 size;
 	raid0_conf_t *conf;
 	mdk_rdev_t *rdev;
 	struct list_head *tmp;
 
-	conf = vmalloc(sizeof (raid0_conf_t));
+	conf = kmalloc(sizeof (raid0_conf_t), GFP_KERNEL);
 	if (!conf)
 		goto out;
 	mddev->private = (void *)conf;
@@ -214,70 +245,64 @@
 
 	printk("raid0 : md_size is %llu blocks.\n", 
 		(unsigned long long)mddev->array_size);
-	printk("raid0 : conf->smallest->size is %llu blocks.\n",
-		(unsigned long long)conf->smallest->size);
+	printk("raid0 : conf->hash_spacing is %llu blocks.\n",
+		(unsigned long long)conf->hash_spacing);
 	{
 #if __GNUC__ < 3
 		volatile
 #endif
 		sector_t s = mddev->array_size;
-		int round = sector_div(s, (unsigned long)conf->smallest->size) ? 1 : 0;
+		sector_t space = conf->hash_spacing;
+		int round;
+		conf->preshift = 0;
+		if (sizeof(sector_t) > sizeof(unsigned long)) {
+			/*shift down space and s so that sector_div will work */
+			while (space > (sector_t) (~(unsigned long)0)) {
+				s >>= 1;
+				space >>= 1;
+				s += 1; /* force round-up */
+				conf->preshift++;
+			}
+		}
+		round = sector_div(s, (unsigned long)space) ? 1 : 0;
 		nb_zone = s + round;
 	}
 	printk("raid0 : nb_zone is %d.\n", nb_zone);
-	conf->nr_zones = nb_zone;
 
 	printk("raid0 : Allocating %Zd bytes for hash.\n",
-				nb_zone*sizeof(struct raid0_hash));
-	conf->hash_table = vmalloc (sizeof (struct raid0_hash)*nb_zone);
+				nb_zone*sizeof(struct strip_zone*));
+	conf->hash_table = kmalloc (sizeof (struct strip_zone *)*nb_zone, GFP_KERNEL);
 	if (!conf->hash_table)
 		goto out_free_zone_conf;
 	size = conf->strip_zone[cur].size;
 
-	i = 0;
-	while (cur < conf->nr_strip_zones) {
-		conf->hash_table[i].zone0 = conf->strip_zone + cur;
-
-		/*
-		 * If we completely fill the slot
-		 */
-		if (size >= conf->smallest->size) {
-			conf->hash_table[i++].zone1 = NULL;
-			size -= conf->smallest->size;
-
-			if (!size) {
-				if (++cur == conf->nr_strip_zones)
-					continue;
-				size = conf->strip_zone[cur].size;
-			}
-			continue;
-		}
-		if (++cur == conf->nr_strip_zones) {
-			/*
-			 * Last dev, set unit1 as NULL
-			 */
-			conf->hash_table[i].zone1=NULL;
-			continue;
+	for (i=0; i< nb_zone; i++) {
+		conf->hash_table[i] = conf->strip_zone + cur;
+		while (size <= conf->hash_spacing) {
+			cur++;
+			size += conf->strip_zone[cur].size;
 		}
-
-		/*
-		 * Here we use a 2nd dev to fill the slot
+		size -= conf->hash_spacing;
+	}
+	if (conf->preshift) {
+		conf->hash_spacing >>= conf->preshift;
+		/* round hash_spacing up so when we divide by it, we
+		 * err on the side of too-low, which is safest
 		 */
-		zone0_size = size;
-		size = conf->strip_zone[cur].size;
-		conf->hash_table[i++].zone1 = conf->strip_zone + cur;
-		size -= (conf->smallest->size - zone0_size);
+		conf->hash_spacing++;
 	}
+
 	blk_queue_max_sectors(&mddev->queue, mddev->chunk_size >> 9);
 	blk_queue_merge_bvec(&mddev->queue, raid0_mergeable_bvec);
 	return 0;
 
 out_free_zone_conf:
-	vfree(conf->strip_zone);
+	kfree(conf->strip_zone);
 	conf->strip_zone = NULL;
 
 out_free_conf:
-	vfree(conf);
+	kfree (conf->devlist);
+	kfree(conf);
 	mddev->private = NULL;
 out:
 	return 1;
@@ -287,11 +312,11 @@
 {
 	raid0_conf_t *conf = mddev_to_conf(mddev);
 
-	vfree (conf->hash_table);
+	kfree (conf->hash_table);
 	conf->hash_table = NULL;
-	vfree (conf->strip_zone);
+	kfree (conf->strip_zone);
 	conf->strip_zone = NULL;
-	vfree (conf);
+	kfree (conf);
 	mddev->private = NULL;
 
 	return 0;
@@ -302,7 +327,6 @@
 	mddev_t *mddev = q->queuedata;
 	unsigned int sect_in_chunk, chunksize_bits,  chunk_size;
 	raid0_conf_t *conf = mddev_to_conf(mddev);
-	struct raid0_hash *hash;
 	struct strip_zone *zone;
 	mdk_rdev_t *tmp_dev;
 	unsigned long chunk;
@@ -313,39 +337,45 @@
 	block = bio->bi_sector >> 1;
 	
 
+	if (unlikely(chunk_size < (block & (chunk_size - 1)) + (bio->bi_size >> 10))) {
+		struct bio_pair *bp;
+		/* Sanity check -- queue functions should prevent this happening */
+		if (bio->bi_vcnt != 1 ||
+		    bio->bi_idx != 0)
+			goto bad_map;
+		/* This is a one page bio that upper layers
+		 * refuse to split for us, so we need to split it.
+		 */
+		bp = bio_split(bio, bio_split_pool, (chunk_size - (block & (chunk_size - 1)))<<1 );
+		if (raid0_make_request(q, &bp->bio1))
+			generic_make_request(&bp->bio1);
+		if (raid0_make_request(q, &bp->bio2))
+			generic_make_request(&bp->bio2);
+
+		bio_pair_release(bp);
+		return 0;
+	}
+ 
+
 	{
 #if __GNUC__ < 3
 		volatile
 #endif
-		sector_t x = block;
-		sector_div(x, (unsigned long)conf->smallest->size);
-		hash = conf->hash_table + x;
+		sector_t x = block >> conf->preshift;
+		sector_div(x, (unsigned long)conf->hash_spacing);
+		zone = conf->hash_table[x];
 	}
-
-	/* Sanity check -- queue functions should prevent this happening */
-	if (unlikely(chunk_size < (block & (chunk_size - 1)) + (bio->bi_size >> 10)))
-		goto bad_map;
  
-	if (!hash)
-		goto bad_hash;
-
-	if (!hash->zone0)
-		goto bad_zone0;
- 
-	if (block >= (hash->zone0->size + hash->zone0->zone_offset)) {
-		if (!hash->zone1)
-			goto bad_zone1;
-		zone = hash->zone1;
-	} else
-		zone = hash->zone0;
+	while (block >= (zone->zone_offset + zone->size)) 
+		zone++;
     
 	sect_in_chunk = bio->bi_sector & ((chunk_size<<1) -1);
 
 
 	{
-		sector_t x =  block - zone->zone_offset;
+		sector_t x =  (block - zone->zone_offset) >> chunksize_bits;
 
-		sector_div(x, (zone->nb_dev << chunksize_bits));
+		sector_div(x, zone->nb_dev);
 		chunk = x;
 		BUG_ON(x != (sector_t)chunk);
 
@@ -355,10 +385,6 @@
 	rsect = (((chunk << chunksize_bits) + zone->dev_offset)<<1)
 		+ sect_in_chunk;
  
-	/*
-	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
-	 * is the only IO operation happening on this bh.
-	 */
 	bio->bi_bdev = tmp_dev->bdev;
 	bio->bi_sector = rsect + tmp_dev->data_offset;
 
@@ -371,19 +397,7 @@
 	printk("raid0_make_request bug: can't convert block across chunks"
 		" or bigger than %dk %llu %d\n", chunk_size, 
 		(unsigned long long)bio->bi_sector, bio->bi_size >> 10);
-	goto outerr;
-bad_hash:
-	printk("raid0_make_request bug: hash==NULL for block %llu\n",
-		(unsigned long long)block);
-	goto outerr;
-bad_zone0:
-	printk("raid0_make_request bug: hash->zone0==NULL for block %llu\n",
-		(unsigned long long)block);
-	goto outerr;
-bad_zone1:
-	printk("raid0_make_request bug: hash->zone1==NULL for block %llu\n",
-			(unsigned long long)block);
- outerr:
+
 	bio_io_error(bio, bio->bi_size);
 	return 0;
 }
@@ -392,27 +406,19 @@
 {
 #undef MD_DEBUG
 #ifdef MD_DEBUG
-	int j, k;
+	int j, k, h;
+	char b[BDEVNAME_SIZE];
 	raid0_conf_t *conf = mddev_to_conf(mddev);
   
-	seq_printf(seq, "      ");
-	for (j = 0; j < conf->nr_zones; j++) {
-		seq_printf(seq, "[z%d",
-				conf->hash_table[j].zone0 - conf->strip_zone);
-		if (conf->hash_table[j].zone1)
-			seq_printf(seq, "/z%d] ",
-				conf->hash_table[j].zone1 - conf->strip_zone);
-		else
-			seq_printf(seq, "] ");
-	}
-  
-	seq_printf(seq, "\n");
-  
+	h = 0;
 	for (j = 0; j < conf->nr_strip_zones; j++) {
-		seq_printf(seq, "      z%d=[", j);
+		seq_printf(seq, "      z%d", j);
+		if (conf->hash_table[h] == conf->strip_zone+j)
+			seq_printf("(h%d)", h++);
+		seq_printf(seq, "=[");
 		for (k = 0; k < conf->strip_zone[j].nb_dev; k++)
-			seq_printf (seq, "%s/", bdev_partition_name(
-				conf->strip_zone[j].dev[k]->bdev));
+			seq_printf (seq, "%s/", bdevname(
+				conf->strip_zone[j].dev[k]->bdev,b));
 
 		seq_printf (seq, "] zo=%d do=%d s=%d\n",
 				conf->strip_zone[j].zone_offset,
diff -Nru a/drivers/md/raid1.c b/drivers/md/raid1.c
--- a/drivers/md/raid1.c	Sun Apr 20 09:24:36 2003
+++ b/drivers/md/raid1.c	Mon May 26 19:01:37 2003
@@ -23,7 +23,6 @@
  */
 
 #include <linux/raid/raid1.h>
-#include <linux/bio.h>
 
 #define MAJOR_NR MD_MAJOR
 #define MD_DRIVER
@@ -41,9 +40,12 @@
 
 static void * r1bio_pool_alloc(int gfp_flags, void *data)
 {
+	mddev_t *mddev = data;
 	r1bio_t *r1_bio;
 
-	r1_bio = kmalloc(sizeof(r1bio_t), gfp_flags);
+	/* allocate a r1bio with room for raid_disks entries in the write_bios array */
+	r1_bio = kmalloc(sizeof(r1bio_t) + sizeof(struct bio*)*mddev->raid_disks,
+			 gfp_flags);
 	if (r1_bio)
 		memset(r1_bio, 0, sizeof(*r1_bio));
 
@@ -68,8 +70,9 @@
 	struct bio *bio;
 	int i, j;
 
-	r1_bio = mempool_alloc(conf->r1bio_pool, gfp_flags);
-
+	r1_bio = r1bio_pool_alloc(gfp_flags, conf->mddev);
+	if (!r1_bio)
+		return NULL;
 	bio = bio_alloc(gfp_flags, RESYNC_PAGES);
 	if (!bio)
 		goto out_free_r1_bio;
@@ -102,7 +105,7 @@
 		__free_page(bio->bi_io_vec[j].bv_page);
 	bio_put(bio);
 out_free_r1_bio:
-	mempool_free(r1_bio, conf->r1bio_pool);
+	r1bio_pool_free(r1_bio, conf->mddev);
 	return NULL;
 }
 
@@ -122,7 +125,7 @@
 	if (atomic_read(&bio->bi_cnt) != 1)
 		BUG();
 	bio_put(bio);
-	mempool_free(r1bio, conf->r1bio_pool);
+	r1bio_pool_free(r1bio, conf->mddev);
 }
 
 static void put_all_bios(conf_t *conf, r1bio_t *r1_bio)
@@ -305,8 +308,9 @@
 			/*
 			 * oops, read error:
 			 */
+			char b[BDEVNAME_SIZE];
 			printk(KERN_ERR "raid1: %s: rescheduling sector %llu\n",
-				bdev_partition_name(conf->mirrors[mirror].rdev->bdev), (unsigned long long)r1_bio->sector);
+				bdevname(conf->mirrors[mirror].rdev->bdev,b), (unsigned long long)r1_bio->sector);
 			reschedule_retry(r1_bio);
 		}
 	} else {
@@ -594,6 +598,7 @@
 
 static void error(mddev_t *mddev, mdk_rdev_t *rdev)
 {
+	char b[BDEVNAME_SIZE];
 	conf_t *conf = mddev_to_conf(mddev);
 
 	/*
@@ -622,7 +627,7 @@
 	mddev->sb_dirty = 1;
 	printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n"
 		"	Operation continuing on %d devices\n",
-		bdev_partition_name(rdev->bdev), conf->working_disks);
+		bdevname(rdev->bdev,b), conf->working_disks);
 }
 
 static void print_conf(conf_t *conf)
@@ -639,11 +644,12 @@
 		conf->raid_disks);
 
 	for (i = 0; i < conf->raid_disks; i++) {
+		char b[BDEVNAME_SIZE];
 		tmp = conf->mirrors + i;
 		if (tmp->rdev)
 			printk(" disk %d, wo:%d, o:%d, dev:%s\n",
 				i, !tmp->rdev->in_sync, !tmp->rdev->faulty,
-				bdev_partition_name(tmp->rdev->bdev));
+				bdevname(tmp->rdev->bdev,b));
 	}
 }
 
@@ -811,9 +817,10 @@
 		 * There is no point trying a read-for-reconstruct as
 		 * reconstruct is about to be aborted
 		 */
+		char b[BDEVNAME_SIZE];
 		printk(KERN_ALERT "raid1: %s: unrecoverable I/O read error"
 			" for block %llu\n",
-			bdev_partition_name(bio->bi_bdev), 
+			bdevname(bio->bi_bdev,b), 
 			(unsigned long long)r1_bio->sector);
 		md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0);
 		put_buf(r1_bio);
@@ -826,7 +833,7 @@
 		if (!conf->mirrors[i].rdev || 
 		    conf->mirrors[i].rdev->faulty)
 			continue;
-		if (i == conf->last_used)
+		if (conf->mirrors[i].rdev->bdev == bio->bi_bdev)
 			/*
 			 * we read from here, no need to write
 			 */
@@ -903,6 +910,7 @@
 	md_handle_safemode(mddev);
 	
 	for (;;) {
+		char b[BDEVNAME_SIZE];
 		spin_lock_irqsave(&retry_list_lock, flags);
 		if (list_empty(head))
 			break;
@@ -922,14 +930,14 @@
 			if (map(mddev, &rdev) == -1) {
 				printk(KERN_ALERT "raid1: %s: unrecoverable I/O"
 				" read error for block %llu\n",
-				bdev_partition_name(bio->bi_bdev), 
+				bdevname(bio->bi_bdev,b),
 				(unsigned long long)r1_bio->sector);
 				raid_end_bio_io(r1_bio);
 				break;
 			}
 			printk(KERN_ERR "raid1: %s: redirecting sector %llu to"
 				" another mirror\n",
-				bdev_partition_name(rdev->bdev), 
+				bdevname(rdev->bdev,b),
 				(unsigned long long)r1_bio->sector);
 			bio->bi_bdev = rdev->bdev;
 			bio->bi_sector = r1_bio->sector + rdev->data_offset;
@@ -1086,13 +1094,20 @@
 		goto out;
 	}
 	memset(conf, 0, sizeof(*conf));
+	conf->mirrors = kmalloc(sizeof(struct mirror_info)*mddev->raid_disks, 
+				 GFP_KERNEL);
+	if (!conf->mirrors) {
+		printk(KERN_ERR "raid1: couldn't allocate memory for md%d\n",
+		       mdidx(mddev));
+		goto out_free_conf;
+	}
 
 	conf->r1bio_pool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc,
-						r1bio_pool_free, NULL);
+						r1bio_pool_free, mddev);
 	if (!conf->r1bio_pool) {
 		printk(KERN_ERR "raid1: couldn't allocate memory for md%d\n", 
 			mdidx(mddev));
-		goto out;
+		goto out_free_conf;
 	}
 
 
@@ -1170,6 +1185,8 @@
 out_free_conf:
 	if (conf->r1bio_pool)
 		mempool_destroy(conf->r1bio_pool);
+	if (conf->mirrors)
+		kfree(conf->mirrors);
 	kfree(conf);
 	mddev->private = NULL;
 out:
@@ -1184,6 +1201,8 @@
 	mddev->thread = NULL;
 	if (conf->r1bio_pool)
 		mempool_destroy(conf->r1bio_pool);
+	if (conf->mirrors)
+		kfree(conf->mirrors);
 	kfree(conf);
 	mddev->private = NULL;
 	return 0;
diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c
--- a/drivers/md/raid5.c	Thu Apr  3 17:21:33 2003
+++ b/drivers/md/raid5.c	Mon May 26 19:01:37 2003
@@ -20,7 +20,6 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/raid/raid5.h>
-#include <linux/bio.h>
 #include <linux/highmem.h>
 #include <asm/bitops.h>
 #include <asm/atomic.h>
@@ -458,6 +457,7 @@
 
 static void error(mddev_t *mddev, mdk_rdev_t *rdev)
 {
+	char b[BDEVNAME_SIZE];
 	raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
 	PRINTK("raid5: error called\n");
 
@@ -477,7 +477,7 @@
 		printk (KERN_ALERT
 			"raid5: Disk failure on %s, disabling device."
 			" Operation continuing on %d devices\n",
-			bdev_partition_name(rdev->bdev), conf->working_disks);
+			bdevname(rdev->bdev,b), conf->working_disks);
 	}
 }	
 
@@ -919,7 +919,7 @@
 	/* check if the array has lost two devices and, if so, some requests might
 	 * need to be failed
 	 */
-	if (failed > 1 && to_read+to_write) {
+	if (failed > 1 && to_read+to_write+written) {
 		spin_lock_irq(&conf->device_lock);
 		for (i=disks; i--; ) {
 			/* fail all writes first */
@@ -937,6 +937,20 @@
 				}
 				bi = nextbi;
 			}
+			/* and fail all 'written' */
+			bi = sh->dev[i].written;
+			sh->dev[i].written = NULL;
+			while (bi && bi->bi_sector < dev->sector + STRIPE_SECTORS) {
+				struct bio *bi2 = bi->bi_next;
+				clear_bit(BIO_UPTODATE, &bi->bi_flags);
+				if (--bi->bi_phys_segments == 0) {
+					md_write_end(conf->mddev);
+					bi->bi_next = return_bi;
+					return_bi = bi;
+				}
+				bi = bi2;
+			}
+
 			/* fail any reads if this device is non-operational */
 			if (!test_bit(R5_Insync, &sh->dev[i].flags)) {
 				bi = sh->dev[i].toread;
@@ -1439,7 +1453,9 @@
 		return -EIO;
 	}
 
-	mddev->private = kmalloc (sizeof (raid5_conf_t), GFP_KERNEL);
+	mddev->private = kmalloc (sizeof (raid5_conf_t)
+				  + mddev->raid_disks * sizeof(struct disk_info),
+				  GFP_KERNEL);
 	if ((conf = mddev->private) == NULL)
 		goto abort;
 	memset (conf, 0, sizeof (*conf));
@@ -1463,7 +1479,7 @@
 
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		raid_disk = rdev->raid_disk;
-		if (raid_disk > mddev->raid_disks
+		if (raid_disk >= mddev->raid_disks
 		    || raid_disk < 0)
 			continue;
 		disk = conf->disks + raid_disk;
@@ -1471,8 +1487,9 @@
 		disk->rdev = rdev;
 
 		if (rdev->in_sync) {
+			char b[BDEVNAME_SIZE];
 			printk(KERN_INFO "raid5: device %s operational as raid"
-				" disk %d\n", bdev_partition_name(rdev->bdev),
+				" disk %d\n", bdevname(rdev->bdev,b),
 				raid_disk);
 			conf->working_disks++;
 		}
@@ -1648,11 +1665,12 @@
 		 conf->working_disks, conf->failed_disks);
 
 	for (i = 0; i < conf->raid_disks; i++) {
+		char b[BDEVNAME_SIZE];
 		tmp = conf->disks + i;
 		if (tmp->rdev)
 		printk(" disk %d, o:%d, dev:%s\n",
 			i, !tmp->rdev->faulty,
-			bdev_partition_name(tmp->rdev->bdev));
+			bdevname(tmp->rdev->bdev,b));
 	}
 }
 
diff -Nru a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c
--- a/drivers/media/video/zoran_procfs.c	Mon Oct  7 07:39:00 2002
+++ b/drivers/media/video/zoran_procfs.c	Thu May 29 22:42:37 2003
@@ -119,7 +119,10 @@
 		printk(KERN_ERR "%s: write_proc: can not allocate memory\n", zr->name);
 		return -ENOMEM;
 	}
-	memcpy(string, buffer, count);
+	if (copy_from_user(string, buffer, count)) {
+		vfree(string);
+		return -EFAULT;
+	}
 	string[count] = 0;
 	DEBUG2(printk(KERN_INFO "%s: write_proc: name=%s count=%lu data=%x\n", zr->name, file->f_dentry->d_name.name, count, (int) data));
 	ldelim = " \t\n";
diff -Nru a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
--- a/drivers/message/fusion/mptscsih.c	Sun May  4 02:56:42 2003
+++ b/drivers/message/fusion/mptscsih.c	Mon May 12 07:26:09 2003
@@ -2149,8 +2149,8 @@
  * 	hostno: scsi host number
  *	func:   if write = 1; if read = 0
  */
-int mptscsih_proc_info(char *buffer, char **start, off_t offset,
-			int length, int hostno, int func)
+int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+			int length, int func)
 {
 	MPT_ADAPTER	*ioc = NULL;
 	MPT_SCSI_HOST	*hd = NULL;
@@ -2161,7 +2161,7 @@
 			buffer, start, *start, offset, length));
 
 	for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) {
-		if ((ioc->sh) && (ioc->sh->host_no == hostno)) {
+		if ((ioc->sh) && (ioc->sh == host)) {
 			hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
 			break;
 		}
diff -Nru a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
--- a/drivers/message/fusion/mptscsih.h	Sun May  4 02:56:43 2003
+++ b/drivers/message/fusion/mptscsih.h	Mon May 12 07:26:10 2003
@@ -199,7 +199,7 @@
 extern	int		 x_scsi_slave_alloc(Scsi_Device *);
 extern	int		 x_scsi_slave_configure(Scsi_Device *);
 extern	void		 x_scsi_slave_destroy(Scsi_Device *);
-extern	int		 x_scsi_proc_info(char *, char **, off_t, int, int, int);
+extern	int		 x_scsi_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
diff -Nru a/drivers/message/i2o/i2o_core.c b/drivers/message/i2o/i2o_core.c
--- a/drivers/message/i2o/i2o_core.c	Wed May 14 23:43:59 2003
+++ b/drivers/message/i2o/i2o_core.c	Thu May 29 22:42:40 2003
@@ -1690,7 +1690,9 @@
 		if((jiffies-time)>=20*HZ)
 		{
 			printk(KERN_ERR "IOP reset timeout.\n");
-			// Better to leak this for safety: - status;
+			/* The controller still may respond and overwrite
+			 * status_phys, LEAK it to prevent memory corruption.
+			 */
 			return -ETIMEDOUT;
 		}
 		schedule();
@@ -1719,6 +1721,10 @@
 			{
 				printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n", 
 						c->name); 
+				/* The controller still may respond and
+				 * overwrite status_phys, LEAK it to prevent
+				 * memory corruption.
+				 */
 				return -ETIMEDOUT; 
 			} 
 			schedule(); 
diff -Nru a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
--- a/drivers/mtd/Kconfig	Tue Oct 29 17:16:55 2002
+++ b/drivers/mtd/Kconfig	Wed May 28 08:01:01 2003
@@ -1,4 +1,4 @@
-# $Id: Config.in,v 1.74 2002/04/23 13:52:14 mag Exp $
+# $Id: Kconfig,v 1.3 2003/05/28 11:02:23 dwmw2 Exp $
 
 menu "Memory Technology Devices (MTD)"
 
@@ -199,13 +199,28 @@
 	  not use it.
 
 config NFTL_RW
-	bool "Write support for NFTL (BETA)"
+	bool "Write support for NFTL"
 	depends on NFTL
 	help
-	  If you're lucky, this will actually work. Don't whinge if it
-	  doesn't.  Send mail to the MTD mailing list
-	  <linux-mtd@lists.infradead.org> if you want to help to make it more
-	  reliable.
+	  Support for writing to the NAND Flash Translation Layer, as used
+	  on the DiskOnChip.
+
+config INFTL
+	tristate "INFTL (Inverse NAND Flash Translation Layer) support"
+	depends on MTD
+	---help---
+	  This provides support for the Inverse NAND Flash Translation 
+	  Layer which is used on M-Systems' newer DiskOnChip devices. It
+	  uses a kind of pseudo-file system on a flash device to emulate
+	  a block device with 512-byte sectors, on top of which you put
+	  a 'normal' file system.
+
+	  You may find that the algorithms used in this code are patented
+	  unless you live in the Free World where software patents aren't
+	  legal - in the USA you are only permitted to use this on DiskOnChip
+	  hardware, although under the terms of the GPL you're obviously
+	  permitted to copy, modify and distribute the code as you wish. Just
+	  not use it.
 
 source "drivers/mtd/chips/Kconfig"
 
diff -Nru a/drivers/mtd/Makefile b/drivers/mtd/Makefile
--- a/drivers/mtd/Makefile	Mon Feb  3 14:19:37 2003
+++ b/drivers/mtd/Makefile	Wed May 28 08:01:01 2003
@@ -1,10 +1,7 @@
 #
 # Makefile for the memory technology device drivers.
 #
-# Based on:
-# $Id: Makefile,v 1.66 2002/04/23 13:52:14 mag Exp $
-
-obj-y           += chips/ maps/ devices/ nand/
+# $Id: Makefile.common,v 1.2 2003/05/23 11:38:29 dwmw2 Exp $
 
 #                       *** BIG UGLY NOTE ***
 #
@@ -27,14 +24,18 @@
 obj-$(CONFIG_MTD_CONCAT)	+= mtdconcat.o
 obj-$(CONFIG_MTD_PARTITIONS)	+= mtdpart.o
 obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
-obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdline.o
+obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
 obj-$(CONFIG_MTD_AFS_PARTS)	+= afs.o
 
 # 'Users' - code which presents functionality to userspace.
 obj-$(CONFIG_MTD_CHAR)		+= mtdchar.o
-obj-$(CONFIG_MTD_BLOCK)		+= mtdblock.o
-obj-$(CONFIG_MTD_BLOCK_RO)	+= mtdblock_ro.o
-obj-$(CONFIG_FTL)		+= ftl.o
-obj-$(CONFIG_NFTL)		+= nftl.o
+obj-$(CONFIG_MTD_BLOCK)		+= mtdblock.o mtd_blkdevs.o
+obj-$(CONFIG_MTD_BLOCK_RO)	+= mtdblock_ro.o mtd_blkdevs.o
+obj-$(CONFIG_FTL)		+= ftl.o mtd_blkdevs.o
+obj-$(CONFIG_NFTL)		+= nftl.o mtd_blkdevs.o
+obj-$(CONFIG_INFTL)		+= inftl.o mtd_blkdevs.o
+
+nftl-objs		:= nftlcore.o nftlmount.o
+inftl-objs		:= inftlcore.o inftlmount.o
 
-nftl-objs	:= nftlcore.o nftlmount.o
+obj-y		+= chips/ maps/ devices/ nand/
diff -Nru a/drivers/mtd/afs.c b/drivers/mtd/afs.c
--- a/drivers/mtd/afs.c	Sun Oct 13 10:51:44 2002
+++ b/drivers/mtd/afs.c	Wed May 28 08:01:01 2003
@@ -21,7 +21,7 @@
    This is access code for flashes using ARM's flash partitioning 
    standards.
 
-   $Id: afs.c,v 1.8 2002/05/04 08:49:09 rmk Exp $
+   $Id: afs.c,v 1.11 2003/05/16 17:08:24 dwmw2 Exp $
 
 ======================================================================*/
 
@@ -125,7 +125,9 @@
 	return ret;
 }
 
-int parse_afs_partitions(struct mtd_info *mtd, struct mtd_partition **pparts)
+static int parse_afs_partitions(struct mtd_info *mtd, 
+                         struct mtd_partition **pparts,
+                         unsigned long origin)
 {
 	struct mtd_partition *parts;
 	u_int mask, off, idx, sz;
@@ -227,7 +229,25 @@
 	return idx ? idx : ret;
 }
 
-EXPORT_SYMBOL(parse_afs_partitions);
+static struct mtd_part_parser afs_parser = {
+	.owner = THIS_MODULE,
+	.parse_fn = parse_afs_partitions,
+	.name = "afs",
+};
+
+static int __init afs_parser_init(void)
+{
+	return register_mtd_parser(&afs_parser);
+}
+
+static void __exit afs_parser_exit(void)
+{
+	deregister_mtd_parser(&afs_parser);
+}
+
+module_init(afs_parser_init);
+module_exit(afs_parser_exit);
+
 
 MODULE_AUTHOR("ARM Ltd");
 MODULE_DESCRIPTION("ARM Firmware Suite partition parser");
diff -Nru a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
--- a/drivers/mtd/chips/Kconfig	Tue Oct 29 17:16:55 2002
+++ b/drivers/mtd/chips/Kconfig	Wed May 28 08:56:01 2003
@@ -1,5 +1,5 @@
-# drivers/mtd/chips/Config.in
-# $Id: Config.in,v 1.12 2001/09/23 15:35:21 dwmw2 Exp $
+# drivers/mtd/chips/Kconfig
+# $Id: Kconfig,v 1.3 2003/05/28 15:13:24 dwmw2 Exp $
 
 menu "RAM/ROM/Flash chip drivers"
 	depends on MTD!=n
@@ -15,7 +15,6 @@
 	  option. Visit <http://www.amd.com/products/nvd/overview/cfi.html>
 	  for more information on CFI.
 
-#dep_tristate '  Detect non-CFI Intel-compatible flash chips' CONFIG_MTD_INTELPROBE $CONFIG_MTD
 config MTD_JEDECPROBE
 	tristate "Detect non-CFI AMD/JEDEC-compatible flash chips"
 	depends on MTD
@@ -107,6 +106,13 @@
 	  If you wish to support CFI devices on a physical bus which is
 	  32 bits wide, say 'Y'.
 
+config MTD_CFI_B8
+	bool "Support 64-bit buswidth"
+	depends on MTD_CFI_GEOMETRY
+	help
+	  If you wish to support CFI devices on a physical bus which is
+	  64 bits wide, say 'Y'.
+
 config MTD_CFI_I1
 	bool "Support 1-chip flash interleave" if !MTD_CFI_B1
 	depends on MTD_CFI_GEOMETRY
@@ -129,6 +135,13 @@
 	  If your flash chips are interleaved in fours - i.e. you have four
 	  flash chips addressed by each bus cycle, then say 'Y'.
 
+config MTD_CFI_I8
+	bool "Support 8-chip flash interleave"
+	depends on MTD_CFI_GEOMETRY
+	help
+	  If your flash chips are interleaved in eights - i.e. you have eight
+	  flash chips addressed by each bus cycle, then say 'Y'.
+
 config MTD_CFI_INTELEXT
 	tristate "Support for Intel/Sharp flash chips"
 	depends on MTD_GEN_PROBE
@@ -145,7 +158,15 @@
 	  The Common Flash Interface defines a number of different command
 	  sets which a CFI-compliant chip may claim to implement. This code
 	  provides support for one of those command sets, used on chips 
-	  chips including the AMD Am29LV320.
+	  including the AMD Am29LV320.
+
+config MTD_CFI_STAA
+	tristate "Support for ST (Advanced Architecture) flash chips"
+	depends on MTD_GEN_PROBE
+	help
+	  The Common Flash Interface defines a number of different command
+	  sets which a CFI-compliant chip may claim to implement. This code
+	  provides support for one of those command sets.
 
 config MTD_RAM
 	tristate "Support for RAM chips in bus mapping"
@@ -177,10 +198,10 @@
 	help
 	  This option does not enable any code directly, but will allow you to
 	  select some other chip drivers which are now considered obsolete,
-	  because the generic CONFIG_JEDEC_PROBE code above should now detect
+	  because the generic CONFIG_JEDECPROBE code above should now detect
 	  the chips which are supported by these drivers, and allow the generic
 	  CFI-compatible drivers to drive the chips. Say 'N' here unless you have
-	  already tried the CONFIG_JEDEC_PROBE method and reported its failure
+	  already tried the CONFIG_JEDECPROBE method and reported its failure
 	  to the MTD mailing list at <linux-mtd@lists.infradead.org>
 
 config MTD_AMDSTD
@@ -209,8 +230,7 @@
 	  programming flash.  It is commonly used in older AMD chips.  It is
 	  only called JEDEC because the JEDEC association
 	  <http://www.jedec.org/> distributes the identification codes for the
-	  chips. WARNING!!!! This code does not compile and is incomplete as
-	  are the specific JEDEC devices drivers.
+	  chips.
 
 endmenu
 
diff -Nru a/drivers/mtd/chips/Makefile b/drivers/mtd/chips/Makefile
--- a/drivers/mtd/chips/Makefile	Mon Feb  3 14:19:37 2003
+++ b/drivers/mtd/chips/Makefile	Wed May 28 08:01:01 2003
@@ -1,7 +1,7 @@
 #
 # linux/drivers/chips/Makefile
 #
-# $Id: Makefile,v 1.7 2001/10/05 06:53:51 dwmw2 Exp $
+# $Id: Makefile.common,v 1.1 2003/05/21 15:00:01 dwmw2 Exp $
 
 #                       *** BIG UGLY NOTE ***
 #
@@ -13,10 +13,10 @@
 obj-$(CONFIG_MTD)		+= chipreg.o
 obj-$(CONFIG_MTD_AMDSTD)	+= amd_flash.o 
 obj-$(CONFIG_MTD_CFI)		+= cfi_probe.o
+obj-$(CONFIG_MTD_CFI_STAA)	+= cfi_cmdset_0020.o
 obj-$(CONFIG_MTD_CFI_AMDSTD)	+= cfi_cmdset_0002.o
 obj-$(CONFIG_MTD_CFI_INTELEXT)	+= cfi_cmdset_0001.o
 obj-$(CONFIG_MTD_GEN_PROBE)	+= gen_probe.o
-obj-$(CONFIG_MTD_INTELPROBE)	+= intel_probe.o
 obj-$(CONFIG_MTD_JEDEC)		+= jedec.o
 obj-$(CONFIG_MTD_JEDECPROBE)	+= jedec_probe.o
 obj-$(CONFIG_MTD_RAM)		+= map_ram.o
diff -Nru a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c
--- a/drivers/mtd/chips/amd_flash.c	Wed Feb 26 05:19:57 2003
+++ b/drivers/mtd/chips/amd_flash.c	Wed May 28 08:01:01 2003
@@ -3,7 +3,7 @@
  *
  * Author: Jonas Holmberg <jonas.holmberg@axis.com>
  *
- * $Id: amd_flash.c,v 1.15 2001/10/02 15:05:11 dwmw2 Exp $
+ * $Id: amd_flash.c,v 1.22 2003/05/28 13:47:19 dwmw2 Exp $
  *
  * Copyright (c) 2001 Axis Communications AB
  *
@@ -52,6 +52,7 @@
 
 /* Manufacturers */
 #define MANUFACTURER_AMD	0x0001
+#define MANUFACTURER_ATMEL	0x001F
 #define MANUFACTURER_FUJITSU	0x0004
 #define MANUFACTURER_ST		0x0020
 #define MANUFACTURER_SST	0x00BF
@@ -67,10 +68,14 @@
 #define AM29BDS323D     0x22D1
 #define AM29BDS643D	0x227E
 
+/* Atmel */
+#define AT49xV16x	0x00C0
+#define AT49xV16xT	0x00C2
 
 /* Fujitsu */
 #define MBM29LV160TE	0x22C4
 #define MBM29LV160BE	0x2249
+#define MBM29LV800BB	0x225B
 
 /* ST - www.st.com */
 #define M29W800T	0x00D7
@@ -120,10 +125,10 @@
 
 
 static struct mtd_chip_driver amd_flash_chipdrv = {
-	.probe		= amd_flash_probe,
-	.destroy	= amd_flash_destroy,
-	.name		= "amd_flash",
-	.module		= THIS_MODULE
+	.probe = amd_flash_probe,
+	.destroy = amd_flash_destroy,
+	.name = "amd_flash",
+	.module = THIS_MODULE
 };
 
 
@@ -135,11 +140,11 @@
 static inline __u32 wide_read(struct map_info *map, __u32 addr)
 {
 	if (map->buswidth == 1) {
-		return map->read8(map, addr);
+		return map_read8(map, addr);
 	} else if (map->buswidth == 2) {
-		return map->read16(map, addr);
+		return map_read16(map, addr);
 	} else if (map->buswidth == 4) {
-		return map->read32(map, addr);
+		return map_read32(map, addr);
         }
 
 	return 0;
@@ -148,11 +153,11 @@
 static inline void wide_write(struct map_info *map, __u32 val, __u32 addr)
 {
 	if (map->buswidth == 1) {
-		map->write8(map, val, addr);
+		map_write8(map, val, addr);
 	} else if (map->buswidth == 2) {
-		map->write16(map, val, addr);
+		map_write16(map, val, addr);
 	} else if (map->buswidth == 4) {
-		map->write32(map, val, addr);
+		map_write32(map, val, addr);
 	}
 }
 
@@ -419,10 +424,7 @@
 
 static struct mtd_info *amd_flash_probe(struct map_info *map)
 {
-	/* Keep this table on the stack so that it gets deallocated after the
-	 * probe is done.
-	 */
-	const struct amd_flash_info table[] = {
+	static const struct amd_flash_info table[] = {
 	{
 		.mfr_id = MANUFACTURER_AMD,
 		.dev_id = AM29LV160DT,
@@ -431,9 +433,9 @@
 		.numeraseregions = 4,
 		.regions = {
 			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-			{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks  = 1 },
-			{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks  = 2 },
-			{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks  = 1 }
+			{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
+			{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
+			{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
 		}
 	}, {
 		.mfr_id = MANUFACTURER_AMD,
@@ -442,9 +444,9 @@
 		.size = 0x00200000,
 		.numeraseregions = 4,
 		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks  = 1 },
-			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks  = 2 },
-			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks  = 1 },
+			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
+			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
+			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
 			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
 		}
 	}, {
@@ -455,9 +457,9 @@
 		.numeraseregions = 4,
 		.regions = {
 			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-			{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks  = 1 },
-			{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks  = 2 },
-			{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks  = 1 }
+			{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
+			{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
+			{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
 		}
 	}, {
 		.mfr_id = MANUFACTURER_FUJITSU,
@@ -467,9 +469,9 @@
 		.numeraseregions = 4,
 		.regions = {
 			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-			{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks  = 1 },
-			{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks  = 2 },
-			{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks  = 1 }
+			{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
+			{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
+			{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
 		}
 	}, {
 		.mfr_id = MANUFACTURER_TOSHIBA,
@@ -478,9 +480,9 @@
 		.size = 0x00200000,
 		.numeraseregions = 4,
 		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks  = 1 },
-			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks  = 2 },
-			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks  = 1 },
+			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
+			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
+			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
 			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
 		}
 	}, {
@@ -490,9 +492,9 @@
 		.size = 0x00200000,
 		.numeraseregions = 4,
 		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks  = 1 },
-			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks  = 2 },
-			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks  = 1 },
+			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
+			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
+			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
 			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
 		}
 	}, {
@@ -502,9 +504,9 @@
 		.size = 0x00100000,
 		.numeraseregions = 4,
 		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks  = 1 },
-			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks  = 2 },
-			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks  = 1 },
+			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
+			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
+			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
 			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
 		}
 	}, {
@@ -514,9 +516,9 @@
 		.size = 0x00100000,
 		.numeraseregions = 4,
 		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks  = 1 },
-			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks  = 2 },
-			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks  = 1 },
+			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
+			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
+			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
 			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
 		}
 	}, {
@@ -527,9 +529,9 @@
 		.numeraseregions = 4,
 		.regions = {
 			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-			{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks  = 1 },
-			{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks  = 2 },
-			{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks  = 1 }
+			{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
+			{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
+			{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
 		}
 	}, {
 		.mfr_id = MANUFACTURER_AMD,
@@ -539,9 +541,9 @@
 		.numeraseregions = 4,
 		.regions = {
 			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-			{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks  = 1 },
-			{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks  = 2 },
-			{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks  = 1 }
+			{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
+			{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
+			{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
 		}
 	}, {
 		.mfr_id = MANUFACTURER_AMD,
@@ -551,9 +553,21 @@
 		.numeraseregions = 4,
 		.regions = {
 			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-			{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks  = 1 },
-			{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks  = 2 },
-			{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks  = 1 }
+			{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
+			{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
+			{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
+		}
+	}, {
+		.mfr_id = MANUFACTURER_FUJITSU,
+		.dev_id = MBM29LV800BB,
+		.name = "Fujitsu MBM29LV800BB",
+		.size = 0x00100000,
+		.numeraseregions = 4,
+		.regions = {
+			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
+			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
+			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
+			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
 		}
 	}, {
 		.mfr_id = MANUFACTURER_ST,
@@ -563,9 +577,9 @@
 		.numeraseregions = 4,
 		.regions = {
 			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-			{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks  = 1 },
-			{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks  = 2 },
-			{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks  = 1 }
+			{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
+			{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
+			{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
 		}
 	}, {
 		.mfr_id = MANUFACTURER_ST,
@@ -575,9 +589,9 @@
 		.numeraseregions = 4,
 		.regions = {
 			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-			{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks  = 1 },
-			{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks  = 2 },
-			{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks  = 1 }
+			{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
+			{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
+			{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
 		}
 	}, {
 		.mfr_id = MANUFACTURER_ST,
@@ -586,9 +600,9 @@
 		.size = 0x00200000,
 		.numeraseregions = 4,
 		.regions = {
-			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks  = 1 },
-			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks  = 2 },
-			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks  = 1 },
+			{ .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
+			{ .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
+			{ .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
 			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
 		}
 	}, {
@@ -600,7 +614,7 @@
 		.regions = {
 			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 48 },
 			{ .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 },
-			{ .offset = 0x3f0000, .erasesize = 0x02000, .numblocks  = 8 },
+			{ .offset = 0x3f0000, .erasesize = 0x02000, .numblocks =  8 },
 		}
 	}, {
 		.mfr_id = MANUFACTURER_AMD,
@@ -611,7 +625,27 @@
 		.regions = {
 			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 96 },
 			{ .offset = 0x600000, .erasesize = 0x10000, .numblocks = 31 },
-			{ .offset = 0x7f0000, .erasesize = 0x02000, .numblocks  = 8 },
+			{ .offset = 0x7f0000, .erasesize = 0x02000, .numblocks =  8 },
+		}
+	}, {
+		.mfr_id = MANUFACTURER_ATMEL,
+		.dev_id = AT49xV16x,
+		.name = "Atmel AT49xV16x",
+		.size = 0x00200000,
+		.numeraseregions = 2,
+		.regions = {
+			{ .offset = 0x000000, .erasesize = 0x02000, .numblocks =  8 },
+			{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
+		}
+	}, {
+		.mfr_id = MANUFACTURER_ATMEL,
+		.dev_id = AT49xV16xT,
+		.name = "Atmel AT49xV16xT",
+		.size = 0x00200000,
+		.numeraseregions = 2,
+		.regions = {
+			{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
+			{ .offset = 0x1F0000, .erasesize = 0x02000, .numblocks =  8 }
 		}
 	} 
 	};
@@ -785,7 +819,7 @@
 
 	chip->state = FL_READY;
 
-	map->copy_from(map, buf, adr, len);
+	map_copy_from(map, buf, adr, len);
 
 	wake_up(&chip->wq);
 	spin_unlock_bh(chip->mutex);
@@ -947,7 +981,7 @@
 		u_char tmp_buf[4];
 		__u32 datum;
 
-		map->copy_from(map, tmp_buf,
+		map_copy_from(map, tmp_buf,
 			       bus_ofs + private->chips[chipnum].start,
 			       map->buswidth);
 		while (len && i < map->buswidth)
@@ -1020,7 +1054,7 @@
 		u_char tmp_buf[2];
 		__u32 datum;
 
-		map->copy_from(map, tmp_buf,
+		map_copy_from(map, tmp_buf,
 			       ofs + private->chips[chipnum].start,
 			       map->buswidth);
 		while (len--) {
@@ -1141,7 +1175,7 @@
 		__u8 verify;
 
 		for (address = adr; address < (adr + size); address++) {
-			if ((verify = map->read8(map, address)) != 0xFF) {
+			if ((verify = map_read8(map, address)) != 0xFF) {
 				error = 1;
 				break;
 			}
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 May 14 23:43:59 2003
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c	Wed May 28 08:01:01 2003
@@ -4,7 +4,7 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
- * $Id: cfi_cmdset_0001.c,v 1.87 2001/10/02 15:05:11 dwmw2 Exp $
+ * $Id: cfi_cmdset_0001.c,v 1.123 2003/05/28 12:51:48 dwmw2 Exp $
  *
  * 
  * 10/10/2000	Nicolas Pitre <nico@cam.org>
@@ -13,12 +13,15 @@
  * 	- scalability vs code size is completely set at compile-time
  * 	  (see include/linux/mtd/cfi.h for selection)
  *	- optimized write buffer method
+ * 02/05/2002	Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com>
+ *	- reworked lock/unlock/erase support for var size flash
  */
 
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 
@@ -27,10 +30,16 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/map.h>
-#include <linux/mtd/cfi.h>
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/compatmac.h>
+#include <linux/mtd/cfi.h>
+
+// debugging, turns off buffer write mode if set to 1
+#define FORCE_WORD_WRITE 0
 
 static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
@@ -46,6 +55,16 @@
 
 static struct mtd_info *cfi_intelext_setup (struct map_info *);
 
+static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
+		     size_t *retlen, u_char **mtdbuf);
+static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
+			size_t len);
+
+
+/*
+ *  *********** SETUP AND PROBE BITS  ***********
+ */
+
 static struct mtd_chip_driver cfi_intelext_chipdrv = {
 	.probe		= NULL, /* Not usable directly */
 	.destroy	= cfi_intelext_destroy,
@@ -59,6 +78,7 @@
 #ifdef DEBUG_CFI_FEATURES
 static void cfi_tell_features(struct cfi_pri_intelext *extp)
 {
+	int i;
 	printk("  Feature/Command Support: %4.4X\n", extp->FeatureSupport);
 	printk("     - Chip Erase:         %s\n", extp->FeatureSupport&1?"supported":"unsupported");
 	printk("     - Suspend Erase:      %s\n", extp->FeatureSupport&2?"supported":"unsupported");
@@ -110,7 +130,7 @@
 	int i;
 	__u32 base = cfi->chips[0].start;
 
-	if (cfi->cfi_mode) {
+	if (cfi->cfi_mode == CFI_MODE_CFI) {
 		/* 
 		 * It's a real CFI chip, not one for which the probe
 		 * routine faked a CFI structure. So we read the feature
@@ -140,7 +160,7 @@
 		}
 		
 		if (extp->MajorVersion != '1' || 
-		    (extp->MinorVersion < '0' || extp->MinorVersion > '2')) {
+		    (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
 			printk(KERN_WARNING "  Unknown IntelExt Extended Query "
 			       "version %c.%c.\n",  extp->MajorVersion,
 			       extp->MinorVersion);
@@ -149,26 +169,38 @@
 		}
 		
 		/* Do some byteswapping if necessary */
-		extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport);
-		extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask);
-		
+		extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
+		extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
+		extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
+			
 #ifdef DEBUG_CFI_FEATURES
 		/* Tell the user about it in lots of lovely detail */
 		cfi_tell_features(extp);
 #endif	
 
+		if(extp->SuspendCmdSupport & 1) {
+//#define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
+#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
+/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ 
+			printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
+			       "erase on write disabled.\n");
+			extp->SuspendCmdSupport &= ~1;
+#else
+			printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n");
+#endif
+		}
 		/* Install our own private info structure */
-		cfi->cmdset_priv = extp;
-	}	
+		cfi->cmdset_priv = extp;	
+	}
 
 	for (i=0; i< cfi->numchips; i++) {
-		cfi->chips[i].word_write_time = 128;
-		cfi->chips[i].buffer_write_time = 128;
-		cfi->chips[i].erase_time = 1024;
+		cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
+		cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
+		cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
+		cfi->chips[i].ref_point_counter = 0;
 	}		
 
 	map->fldrv = &cfi_intelext_chipdrv;
-	MOD_INC_USE_COUNT;
 	
 	/* Make sure it's in read mode */
 	cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
@@ -188,8 +220,7 @@
 
 	if (!mtd) {
 		printk(KERN_ERR "Failed to allocate memory for MTD device\n");
-		kfree(cfi->cmdset_priv);
-		return NULL;
+		goto setup_err;
 	}
 
 	memset(mtd, 0, sizeof(*mtd));
@@ -202,9 +233,7 @@
 			* mtd->numeraseregions, GFP_KERNEL);
 	if (!mtd->eraseregions) { 
 		printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
-		kfree(cfi->cmdset_priv);
-		kfree(mtd);
-		return NULL;
+		goto setup_err;
 	}
 	
 	for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
@@ -221,34 +250,39 @@
 			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
 		}
 		offset += (ersize * ernum);
-		}
+	}
 
-		if (offset != devsize) {
-			/* Argh */
-			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 (offset != devsize) {
+		/* Argh */
+		printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
+		goto setup_err;
+	}
 
-		for (i=0; i<mtd->numeraseregions;i++){
-			printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",
-			       i,mtd->eraseregions[i].offset,
-			       mtd->eraseregions[i].erasesize,
-			       mtd->eraseregions[i].numblocks);
-		}
+	for (i=0; i<mtd->numeraseregions;i++){
+		printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",
+		       i,mtd->eraseregions[i].offset,
+		       mtd->eraseregions[i].erasesize,
+		       mtd->eraseregions[i].numblocks);
+	}
 
 	/* Also select the correct geometry setup too */ 
-		mtd->erase = cfi_intelext_erase_varsize;
+	mtd->erase = cfi_intelext_erase_varsize;
 	mtd->read = cfi_intelext_read;
-	if ( cfi->cfiq->BufWriteTimeoutTyp ) {
-		//printk(KERN_INFO "Using buffer write method\n" );
+
+	if (map_is_linear(map)) {
+		mtd->point = cfi_intelext_point;
+		mtd->unpoint = cfi_intelext_unpoint;
+	}
+
+	if ( cfi->cfiq->BufWriteTimeoutTyp && !FORCE_WORD_WRITE) {
+		printk(KERN_INFO "Using buffer write method\n" );
 		mtd->write = cfi_intelext_write_buffers;
 	} else {
-		//printk(KERN_INFO "Using word write method\n" );
+		printk(KERN_INFO "Using word write method\n" );
 		mtd->write = cfi_intelext_write_words;
 	}
+	mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
+	mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
 	mtd->sync = cfi_intelext_sync;
 	mtd->lock = cfi_intelext_lock;
 	mtd->unlock = cfi_intelext_unlock;
@@ -256,127 +290,130 @@
 	mtd->resume = cfi_intelext_resume;
 	mtd->flags = MTD_CAP_NORFLASH;
 	map->fldrv = &cfi_intelext_chipdrv;
-	MOD_INC_USE_COUNT;
 	mtd->name = map->name;
+	__module_get(THIS_MODULE);
 	return mtd;
+
+ setup_err:
+	if(mtd) {
+		if(mtd->eraseregions)
+			kfree(mtd->eraseregions);
+		kfree(mtd);
+	}
+	kfree(cfi->cmdset_priv);
+	kfree(cfi->cfiq);
+	return NULL;
 }
 
+/*
+ *  *********** CHIP ACCESS FUNCTIONS ***********
+ */
 
-static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
 {
-	__u32 status, status_OK;
-	unsigned long timeo;
 	DECLARE_WAITQUEUE(wait, current);
-	int suspended = 0;
-	unsigned long cmd_addr;
 	struct cfi_private *cfi = map->fldrv_priv;
+	cfi_word status, status_OK = CMD(0x80);
+	unsigned long timeo;
+	struct cfi_pri_intelext *cfip = (struct cfi_pri_intelext *)cfi->cmdset_priv;
 
-	adr += chip->start;
-
-	/* Ensure cmd read/writes are aligned. */ 
-	cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); 
-
-	/* Let's determine this according to the interleave only once */
-	status_OK = CMD(0x80);
-
+ resettime:
 	timeo = jiffies + HZ;
  retry:
-	spin_lock_bh(chip->mutex);
-
-	/* Check that the chip's ready to talk to us.
-	 * If it's in FL_ERASING state, suspend it and make it talk now.
-	 */
 	switch (chip->state) {
+
+	case FL_STATUS:
+		for (;;) {
+			status = cfi_read(map, adr);
+			if ((status & status_OK) == status_OK)
+				break;
+
+			if (time_after(jiffies, timeo)) {
+				printk(KERN_ERR "Waiting for chip to be ready timed out. Status %llx\n", 
+				       (long long)status);
+				spin_unlock(chip->mutex);
+				return -EIO;
+			}
+			spin_unlock(chip->mutex);
+			cfi_udelay(1);
+			spin_lock(chip->mutex);
+			/* Someone else might have been playing with it. */
+			goto retry;
+		}
+				
+	case FL_READY:
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+		return 0;
+
 	case FL_ERASING:
-		if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)
-			goto sleep; /* We don't support erase suspend */
-		
-		cfi_write (map, CMD(0xb0), cmd_addr);
+		if (!(cfip->FeatureSupport & 2) ||
+		    !(mode == FL_READY || mode == FL_POINT ||
+		     (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1))))
+			goto sleep;
+
+
+		/* Erase suspend */
+		cfi_write(map, CMD(0xB0), adr);
+
 		/* If the flash has finished erasing, then 'erase suspend'
 		 * appears to make some (28F320) flash devices switch to
 		 * 'read' mode.  Make sure that we switch to 'read status'
 		 * mode so we get the right data. --rmk
 		 */
-		cfi_write(map, CMD(0x70), cmd_addr);
+		cfi_write(map, CMD(0x70), adr);
 		chip->oldstate = FL_ERASING;
 		chip->state = FL_ERASE_SUSPENDING;
-		//		printk("Erase suspending at 0x%lx\n", cmd_addr);
+		chip->erase_suspended = 1;
 		for (;;) {
-			status = cfi_read(map, cmd_addr);
+			status = cfi_read(map, adr);
 			if ((status & status_OK) == status_OK)
-				break;
-			
+			        break;
+
 			if (time_after(jiffies, timeo)) {
-				/* Urgh */
-				cfi_write(map, CMD(0xd0), cmd_addr);
-				/* make sure we're in 'read status' mode */
-				cfi_write(map, CMD(0x70), cmd_addr);
+				/* Urgh. Resume and pretend we weren't here.  */
+				cfi_write(map, CMD(0xd0), adr);
+				/* Make sure we're in 'read status' mode if it had finished */
+				cfi_write(map, CMD(0x70), adr);
 				chip->state = FL_ERASING;
-				spin_unlock_bh(chip->mutex);
+				chip->oldstate = FL_READY;
 				printk(KERN_ERR "Chip not ready after erase "
 				       "suspended: status = 0x%x\n", status);
 				return -EIO;
 			}
-			
-			spin_unlock_bh(chip->mutex);
+
+			spin_unlock(chip->mutex);
 			cfi_udelay(1);
-			spin_lock_bh(chip->mutex);
+			spin_lock(chip->mutex);
+			/* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
+			   So we can just loop here. */
 		}
-		
-		suspended = 1;
-		cfi_write(map, CMD(0xff), cmd_addr);
-		chip->state = FL_READY;
-		break;
-	
-#if 0
-	case FL_WRITING:
-		/* Not quite yet */
-#endif
-
-	case FL_READY:
-		break;
-
-	case FL_CFI_QUERY:
-	case FL_JEDEC_QUERY:
-		cfi_write(map, CMD(0x70), cmd_addr);
 		chip->state = FL_STATUS;
+		return 0;
 
-	case FL_STATUS:
-		status = cfi_read(map, cmd_addr);
-		if ((status & status_OK) == status_OK) {
-			cfi_write(map, CMD(0xff), cmd_addr);
-			chip->state = FL_READY;
-			break;
-		}
-		
-		/* Urgh. Chip not yet ready to talk to us. */
-		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %x\n", status);
-			return -EIO;
-		}
-
-		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-		cfi_udelay(1);
-		goto retry;
+	case FL_POINT:
+		/* Only if there's no operation suspended... */
+		if (mode == FL_READY && chip->oldstate == FL_READY)
+			return 0;
 
 	default:
 	sleep:
-		/* Stick ourselves on a wait queue to be woken when
-		   someone changes the status */
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		schedule();
 		remove_wait_queue(&chip->wq, &wait);
-		timeo = jiffies + HZ;
-		goto retry;
+		spin_lock(chip->mutex);
+		goto resettime;
 	}
+}
 
-	map->copy_from(map, buf, adr, len);
+static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
 
-	if (suspended) {
+	switch(chip->oldstate) {
+	case FL_ERASING:
 		chip->state = chip->oldstate;
 		/* What if one interleaved chip has finished and the 
 		   other hasn't? The old code would leave the finished
@@ -387,12 +424,167 @@
 		   sending the 0x70 (Read Status) command to an erasing
 		   chip and expecting it to be ignored, that's what we 
 		   do. */
-		cfi_write(map, CMD(0xd0), cmd_addr);
-		cfi_write(map, CMD(0x70), cmd_addr);		
-	}
+		cfi_write(map, CMD(0xd0), adr);
+		cfi_write(map, CMD(0x70), adr);
+		chip->oldstate = FL_READY;
+		chip->state = FL_ERASING;
+		break;
 
+	case FL_READY:
+		/* We should really make set_vpp() count, rather than doing this */
+		DISABLE_VPP(map);
+		break;
+	default:
+		printk(KERN_ERR "put_chip() called with oldstate %d!!\n", chip->oldstate);
+	}
 	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
+}
+
+static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
+{
+	unsigned long cmd_addr;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int ret = 0;
+
+	adr += chip->start;
+
+	/* Ensure cmd read/writes are aligned. */ 
+	cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); 
+
+	spin_lock(chip->mutex);
+
+	ret = get_chip(map, chip, cmd_addr, FL_POINT);
+
+	if (!ret) {
+		if (chip->state != FL_POINT && chip->state != FL_READY)
+			cfi_write(map, CMD(0xff), cmd_addr);
+
+		chip->state = FL_POINT;
+		chip->ref_point_counter++;
+	}
+	spin_unlock(chip->mutex);
+
+	return ret;
+}
+
+static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long ofs;
+	int chipnum;
+	int ret = 0;
+
+	if (from + len > mtd->size)
+		return -EINVAL;
+	
+	*mtdbuf = (void *)map->virt + from;
+	if(*mtdbuf == NULL)
+		return -EINVAL; /* can not point this region */
+	*retlen = 0;
+
+	/* Now lock the chip(s) to POINT state */
+
+	/* ofs: offset within the first chip that the first read should start */
+	chipnum = (from >> cfi->chipshift);
+	ofs = from - (chipnum << cfi->chipshift);
+
+	while (len) {
+		unsigned long thislen;
+
+		if (chipnum >= cfi->numchips)
+			break;
+
+		if ((len + ofs -1) >> cfi->chipshift)
+			thislen = (1<<cfi->chipshift) - ofs;
+		else
+			thislen = len;
+
+		ret = do_point_onechip(map, &cfi->chips[chipnum], ofs, thislen);
+		if (ret)
+			break;
+
+		*retlen += thislen;
+		len -= thislen;
+		
+		ofs = 0;
+		chipnum++;
+	}
+	return 0;
+}
+
+static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long ofs;
+	int chipnum;
+
+	/* Now unlock the chip(s) POINT state */
+
+	/* ofs: offset within the first chip that the first read should start */
+	chipnum = (from >> cfi->chipshift);
+	ofs = from - (chipnum <<  cfi->chipshift);
+
+	while (len) {
+		unsigned long thislen;
+		struct flchip *chip;
+
+		chip = &cfi->chips[chipnum];
+		if (chipnum >= cfi->numchips)
+			break;
+
+		if ((len + ofs -1) >> cfi->chipshift)
+			thislen = (1<<cfi->chipshift) - ofs;
+		else
+			thislen = len;
+
+		spin_lock(chip->mutex);
+		if (chip->state == FL_POINT) {
+			chip->ref_point_counter--;
+			if(chip->ref_point_counter == 0)
+				chip->state = FL_READY;
+		} else
+			printk(KERN_ERR "Warning: unpoint called on non pointed region\n"); /* Should this give an error? */
+
+		put_chip(map, chip, chip->start);
+		spin_unlock(chip->mutex);
+
+		len -= thislen;
+		ofs = 0;
+		chipnum++;
+	}
+}
+
+static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
+{
+	unsigned long cmd_addr;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int ret;
+
+	adr += chip->start;
+
+	/* Ensure cmd read/writes are aligned. */ 
+	cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); 
+
+	spin_lock(chip->mutex);
+	ret = get_chip(map, chip, cmd_addr, FL_READY);
+	if (ret) {
+		spin_unlock(chip->mutex);
+		return ret;
+	}
+
+	if (chip->state != FL_POINT && chip->state != FL_READY) {
+		cfi_write(map, CMD(0xff), cmd_addr);
+
+		chip->state = FL_READY;
+	}
+
+	map_copy_from(map, buf, adr, len);
+
+	put_chip(map, chip, cmd_addr);
+
+	spin_unlock(chip->mutex);
 	return 0;
 }
 
@@ -435,64 +627,115 @@
 	return ret;
 }
 
-static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum)
+static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz)
 {
+	struct map_info *map = mtd->priv;
 	struct cfi_private *cfi = map->fldrv_priv;
-	__u32 status, status_OK;
-	unsigned long timeo;
-	DECLARE_WAITQUEUE(wait, current);
-	int z;
+	struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+	struct flchip *chip;
+	int ofs_factor = cfi->interleave * cfi->device_type;
+	int count = len;
+	int chip_num, offst;
+	int ret;
 
-	adr += chip->start;
+	chip_num = ((unsigned int)from/reg_sz);
+	offst = from - (reg_sz*chip_num)+base_offst;
 
-	/* Let's determine this according to the interleave only once */
-	status_OK = CMD(0x80);
+	while (count) {
+	/* Calculate which chip & protection register offset we need */
 
-	timeo = jiffies + HZ;
- retry:
-	spin_lock_bh(chip->mutex);
+		if (chip_num >= cfi->numchips)
+			goto out;
 
-	/* Check that the chip's ready to talk to us.
-	 * Later, we can actually think about interrupting it
-	 * if it's in FL_ERASING state.
-	 * Not just yet, though.
-	 */
-	switch (chip->state) {
-	case FL_READY:
-		break;
+		chip = &cfi->chips[chip_num];
 		
-	case FL_CFI_QUERY:
-	case FL_JEDEC_QUERY:
-		cfi_write(map, CMD(0x70), adr);
-		chip->state = FL_STATUS;
+		spin_lock(chip->mutex);
+		ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
+		if (ret) {
+			spin_unlock(chip->mutex);
+			return (len-count)?:ret;
+		}
 
-	case FL_STATUS:
-		status = cfi_read(map, adr);
-		if ((status & status_OK) == status_OK)
-			break;
-		
-		/* Urgh. Chip not yet ready to talk to us. */
-		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_ERR "waiting for chip to be ready timed out in read\n");
-			return -EIO;
+		if (chip->state != FL_JEDEC_QUERY) {
+			cfi_write(map, CMD(0x90), chip->start);
+			chip->state = FL_JEDEC_QUERY;
 		}
 
-		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-		cfi_udelay(1);
-		goto retry;
+		while (count && ((offst-base_offst) < reg_sz)) {
+			*buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst));
+			buf++;
+			offst++;
+			count--;
+		}
 
-	default:
-		/* Stick ourselves on a wait queue to be woken when
-		   someone changes the status */
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-		timeo = jiffies + HZ;
-		goto retry;
+		put_chip(map, chip, chip->start);
+		spin_unlock(chip->mutex);
+
+		/* Move on to the next chip */
+		chip_num++;
+		offst = base_offst;
+	}
+	
+ out:	
+	return len-count;
+}
+	
+static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *extp=cfi->cmdset_priv;
+	int base_offst,reg_sz;
+	
+	/* Check that we actually have some protection registers */
+	if(!(extp->FeatureSupport&64)){
+		printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
+		return 0;
+	}
+
+	base_offst=(1<<extp->FactProtRegSize);
+	reg_sz=(1<<extp->UserProtRegSize);
+
+	return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
+}
+
+static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *extp=cfi->cmdset_priv;
+	int base_offst,reg_sz;
+	
+	/* Check that we actually have some protection registers */
+	if(!(extp->FeatureSupport&64)){
+		printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
+		return 0;
+	}
+
+	base_offst=0;
+	reg_sz=(1<<extp->FactProtRegSize);
+
+	return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
+}
+
+
+static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	cfi_word status, status_OK;
+	unsigned long timeo;
+	int z, ret=0;
+
+	adr += chip->start;
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	spin_lock(chip->mutex);
+	ret = get_chip(map, chip, adr, FL_WRITING);
+	if (ret) {
+		spin_unlock(chip->mutex);
+		return ret;
 	}
 
 	ENABLE_VPP(map);
@@ -500,22 +743,24 @@
 	cfi_write(map, datum, adr);
 	chip->state = FL_WRITING;
 
-	spin_unlock_bh(chip->mutex);
+	spin_unlock(chip->mutex);
 	cfi_udelay(chip->word_write_time);
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	timeo = jiffies + (HZ/2);
 	z = 0;
 	for (;;) {
 		if (chip->state != FL_WRITING) {
 			/* Someone's suspended the write. Sleep */
+			DECLARE_WAITQUEUE(wait, current);
+
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			add_wait_queue(&chip->wq, &wait);
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			schedule();
 			remove_wait_queue(&chip->wq, &wait);
 			timeo = jiffies + (HZ / 2); /* FIXME */
-			spin_lock_bh(chip->mutex);
+			spin_lock(chip->mutex);
 			continue;
 		}
 
@@ -526,17 +771,16 @@
 		/* OK Still waiting */
 		if (time_after(jiffies, timeo)) {
 			chip->state = FL_STATUS;
-			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
 			printk(KERN_ERR "waiting for chip to be ready timed out in word write\n");
-			return -EIO;
+			ret = -EIO;
+			goto out;
 		}
 
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		z++;
 		cfi_udelay(1);
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 	}
 	if (!z) {
 		chip->word_write_time--;
@@ -547,7 +791,6 @@
 		chip->word_write_time++;
 
 	/* Done and happy. */
-	DISABLE_VPP(map);
 	chip->state = FL_STATUS;
 	/* check for lock bit */
 	if (status & CMD(0x02)) {
@@ -555,13 +798,13 @@
 		cfi_write(map, CMD(0x50), adr);
 		/* put back into read status register mode */
 		cfi_write(map, CMD(0x70), adr);
-		wake_up(&chip->wq);
-		spin_unlock_bh(chip->mutex);
-		return -EROFS;
+		ret = -EROFS;
 	}
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-	return 0;
+ out:
+	put_chip(map, chip, adr);
+	spin_unlock(chip->mutex);
+
+	return ret;
 }
 
 
@@ -585,8 +828,8 @@
 		unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);
 		int gap = ofs - bus_ofs;
 		int i = 0, n = 0;
-		u_char tmp_buf[4];
-		__u32 datum;
+		u_char tmp_buf[8];
+		cfi_word datum;
 
 		while (gap--)
 			tmp_buf[i++] = 0xff;
@@ -599,6 +842,8 @@
 			datum = *(__u16*)tmp_buf;
 		} else if (cfi_buswidth_is_4()) {
 			datum = *(__u32*)tmp_buf;
+		} else if (cfi_buswidth_is_8()) {
+			datum = *(__u64*)tmp_buf;
 		} else {
 			return -EINVAL;  /* should never happen, but be safe */
 		}
@@ -621,7 +866,7 @@
 	}
 	
 	while(len >= CFIDEV_BUSWIDTH) {
-		__u32 datum;
+		cfi_word datum;
 
 		if (cfi_buswidth_is_1()) {
 			datum = *(__u8*)buf;
@@ -629,6 +874,8 @@
 			datum = *(__u16*)buf;
 		} else if (cfi_buswidth_is_4()) {
 			datum = *(__u32*)buf;
+		} else if (cfi_buswidth_is_8()) {
+			datum = *(__u64*)buf;
 		} else {
 			return -EINVAL;
 		}
@@ -653,8 +900,8 @@
 
 	if (len & (CFIDEV_BUSWIDTH-1)) {
 		int i = 0, n = 0;
-		u_char tmp_buf[4];
-		__u32 datum;
+		u_char tmp_buf[8];
+		cfi_word datum;
 
 		while (len--)
 			tmp_buf[i++] = buf[n++];
@@ -665,6 +912,8 @@
 			datum = *(__u16*)tmp_buf;
 		} else if (cfi_buswidth_is_4()) {
 			datum = *(__u32*)tmp_buf;
+		} else if (cfi_buswidth_is_8()) {
+			datum = *(__u64*)tmp_buf;
 		} else {
 			return -EINVAL;  /* should never happen, but be safe */
 		}
@@ -685,10 +934,9 @@
 				  unsigned long adr, const u_char *buf, int len)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	__u32 status, status_OK;
+	cfi_word status, status_OK;
 	unsigned long cmd_adr, timeo;
-	DECLARE_WAITQUEUE(wait, current);
-	int wbufsize, z;
+	int wbufsize, z, ret=0;
 
 	wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
 	adr += chip->start;
@@ -697,74 +945,52 @@
 	/* Let's determine this according to the interleave only once */
 	status_OK = CMD(0x80);
 
-	timeo = jiffies + HZ;
- retry:
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
+	ret = get_chip(map, chip, cmd_adr, FL_WRITING);
+	if (ret) {
+		spin_unlock(chip->mutex);
+		return ret;
+	}
 
-	/* Check that the chip's ready to talk to us.
-	 * Later, we can actually think about interrupting it
-	 * if it's in FL_ERASING state.
-	 * Not just yet, though.
-	 */
-	switch (chip->state) {
-	case FL_READY:
-		break;
-		
-	case FL_CFI_QUERY:
-	case FL_JEDEC_QUERY:
+	if (chip->state != FL_STATUS)
 		cfi_write(map, CMD(0x70), cmd_adr);
-		chip->state = FL_STATUS;
-
-	case FL_STATUS:
-		status = cfi_read(map, cmd_adr);
-		if ((status & status_OK) == status_OK)
-			break;
-		/* Urgh. Chip not yet ready to talk to us. */
-		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_ERR "waiting for chip to be ready timed out in buffer write\n");
-			return -EIO;
-		}
 
-		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-		cfi_udelay(1);
-		goto retry;
+	status = cfi_read(map, cmd_adr);
 
-	default:
-		/* Stick ourselves on a wait queue to be woken when
-		   someone changes the status */
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-		timeo = jiffies + HZ;
-		goto retry;
+	/* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set
+	   [...], the device will not accept any more Write to Buffer commands". 
+	   So we must check here and reset those bits if they're set. Otherwise
+	   we're just pissing in the wind */
+	if (status & CMD(0x30)) {
+		printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %x). Clearing.\n", status);
+		cfi_write(map, CMD(0x50), cmd_adr);
+		cfi_write(map, CMD(0x70), cmd_adr);
 	}
-
 	ENABLE_VPP(map);
-	cfi_write(map, CMD(0xe8), cmd_adr);
 	chip->state = FL_WRITING_TO_BUFFER;
 
 	z = 0;
 	for (;;) {
+		cfi_write(map, CMD(0xe8), cmd_adr);
+
 		status = cfi_read(map, cmd_adr);
 		if ((status & status_OK) == status_OK)
 			break;
 
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 
 		if (++z > 20) {
 			/* Argh. Not ready for write to buffer */
 			cfi_write(map, CMD(0x70), cmd_adr);
 			chip->state = FL_STATUS;
-			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %x, status = %x\n", status, cfi_read(map, cmd_adr));
-			return -EIO;
+			printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %llx, status = %llx\n", (__u64)status, (__u64)cfi_read(map, cmd_adr));
+			/* Odd. Clear status bits */
+			cfi_write(map, CMD(0x50), cmd_adr);
+			cfi_write(map, CMD(0x70), cmd_adr);
+			ret = -EIO;
+			goto out;
 		}
 	}
 
@@ -774,36 +1000,39 @@
 	/* Write data */
 	for (z = 0; z < len; z += CFIDEV_BUSWIDTH) {
 		if (cfi_buswidth_is_1()) {
-			map->write8 (map, *((__u8*)buf)++, adr+z);
+			map_write8 (map, *((__u8*)buf)++, adr+z);
 		} else if (cfi_buswidth_is_2()) {
-			map->write16 (map, *((__u16*)buf)++, adr+z);
+			map_write16 (map, *((__u16*)buf)++, adr+z);
 		} else if (cfi_buswidth_is_4()) {
-			map->write32 (map, *((__u32*)buf)++, adr+z);
+			map_write32 (map, *((__u32*)buf)++, adr+z);
+		} else if (cfi_buswidth_is_8()) {
+			map_write64 (map, *((__u64*)buf)++, adr+z);
 		} else {
-			DISABLE_VPP(map);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 	}
 	/* GO GO GO */
 	cfi_write(map, CMD(0xd0), cmd_adr);
 	chip->state = FL_WRITING;
 
-	spin_unlock_bh(chip->mutex);
+	spin_unlock(chip->mutex);
 	cfi_udelay(chip->buffer_write_time);
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	timeo = jiffies + (HZ/2);
 	z = 0;
 	for (;;) {
 		if (chip->state != FL_WRITING) {
 			/* Someone's suspended the write. Sleep */
+			DECLARE_WAITQUEUE(wait, current);
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			add_wait_queue(&chip->wq, &wait);
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			schedule();
 			remove_wait_queue(&chip->wq, &wait);
 			timeo = jiffies + (HZ / 2); /* FIXME */
-			spin_lock_bh(chip->mutex);
+			spin_lock(chip->mutex);
 			continue;
 		}
 
@@ -814,17 +1043,16 @@
 		/* OK Still waiting */
 		if (time_after(jiffies, timeo)) {
 			chip->state = FL_STATUS;
-			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
 			printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n");
-			return -EIO;
+			ret = -EIO;
+			goto out;
 		}
 		
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
 		z++;
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 	}
 	if (!z) {
 		chip->buffer_write_time--;
@@ -835,21 +1063,21 @@
 		chip->buffer_write_time++;
 
 	/* Done and happy. */
-	DISABLE_VPP(map);
-	chip->state = FL_STATUS;
+ 	chip->state = FL_STATUS;
+
 	/* check for lock bit */
 	if (status & CMD(0x02)) {
 		/* clear status */
 		cfi_write(map, CMD(0x50), cmd_adr);
 		/* put back into read status register mode */
 		cfi_write(map, CMD(0x70), adr);
-		wake_up(&chip->wq);
-		spin_unlock_bh(chip->mutex);
-		return -EROFS;
+		ret = -EROFS;
 	}
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
-	return 0;
+
+ out:
+	put_chip(map, chip, cmd_adr);
+	spin_unlock(chip->mutex);
+	return ret;
 }
 
 static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, 
@@ -928,11 +1156,102 @@
 	return 0;
 }
 
+typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip,
+			      unsigned long adr, void *thunk);
+
+static int cfi_intelext_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
+				     loff_t ofs, size_t len, void *thunk)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long adr;
+	int chipnum, ret = 0;
+	int i, first;
+	struct mtd_erase_region_info *regions = mtd->eraseregions;
+
+	if (ofs > mtd->size)
+		return -EINVAL;
+
+	if ((len + ofs) > mtd->size)
+		return -EINVAL;
+
+	/* Check that both start and end of the requested erase are
+	 * aligned with the erasesize at the appropriate addresses.
+	 */
+
+	i = 0;
+
+	/* Skip all erase regions which are ended before the start of 
+	   the requested erase. Actually, to save on the calculations,
+	   we skip to the first erase region which starts after the
+	   start of the requested erase, and then go back one.
+	*/
+	
+	while (i < mtd->numeraseregions && ofs >= regions[i].offset)
+	       i++;
+	i--;
+
+	/* OK, now i is pointing at the erase region in which this 
+	   erase request starts. Check the start of the requested
+	   erase range is aligned with the erase size which is in
+	   effect here.
+	*/
+
+	if (ofs & (regions[i].erasesize-1))
+		return -EINVAL;
+
+	/* Remember the erase region we start on */
+	first = i;
+
+	/* Next, check that the end of the requested erase is aligned
+	 * with the erase region at that address.
+	 */
+
+	while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset)
+		i++;
+
+	/* As before, drop back one to point at the region in which
+	   the address actually falls
+	*/
+	i--;
+	
+	if ((ofs + len) & (regions[i].erasesize-1))
+		return -EINVAL;
+
+	chipnum = ofs >> cfi->chipshift;
+	adr = ofs - (chipnum << cfi->chipshift);
+
+	i=first;
+
+	while(len) {
+		ret = (*frob)(map, &cfi->chips[chipnum], adr, thunk);
+		
+		if (ret)
+			return ret;
+
+		adr += regions[i].erasesize;
+		len -= regions[i].erasesize;
+
+		if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
+			i++;
+
+		if (adr >> cfi->chipshift) {
+			adr = 0;
+			chipnum++;
+			
+			if (chipnum >= cfi->numchips)
+			break;
+		}
+	}
+
+	return 0;
+}
+
 
-static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+static int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	__u32 status, status_OK;
+	cfi_word status, status_OK;
 	unsigned long timeo;
 	int retries = 3;
 	DECLARE_WAITQUEUE(wait, current);
@@ -943,45 +1262,12 @@
 	/* Let's determine this according to the interleave only once */
 	status_OK = CMD(0x80);
 
-	timeo = jiffies + HZ;
-retry:
-	spin_lock_bh(chip->mutex);
-
-	/* Check that the chip's ready to talk to us. */
-	switch (chip->state) {
-	case FL_CFI_QUERY:
-	case FL_JEDEC_QUERY:
-	case FL_READY:
-		cfi_write(map, CMD(0x70), adr);
-		chip->state = FL_STATUS;
-
-	case FL_STATUS:
-		status = cfi_read(map, adr);
-		if ((status & status_OK) == status_OK)
-			break;
-		
-		/* Urgh. Chip not yet ready to talk to us. */
-		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_ERR "waiting for chip to be ready timed out in erase\n");
-			return -EIO;
-		}
-
-		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-		cfi_udelay(1);
-		goto retry;
-
-	default:
-		/* Stick ourselves on a wait queue to be woken when
-		   someone changes the status */
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-		timeo = jiffies + HZ;
-		goto retry;
+ retry:
+	spin_lock(chip->mutex);
+	ret = get_chip(map, chip, adr, FL_ERASING);
+	if (ret) {
+		spin_unlock(chip->mutex);
+		return ret;
 	}
 
 	ENABLE_VPP(map);
@@ -992,10 +1278,12 @@
 	cfi_write(map, CMD(0x20), adr);
 	cfi_write(map, CMD(0xD0), adr);
 	chip->state = FL_ERASING;
-	
-	spin_unlock_bh(chip->mutex);
-	schedule_timeout(HZ);
-	spin_lock_bh(chip->mutex);
+	chip->erase_suspended = 0;
+
+	spin_unlock(chip->mutex);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout((chip->erase_time*HZ)/(2*1000));
+	spin_lock(chip->mutex);
 
 	/* FIXME. Use a timer to check this, and return immediately. */
 	/* Once the state machine's known to be working I'll do that */
@@ -1006,13 +1294,18 @@
 			/* Someone's suspended the erase. Sleep */
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			add_wait_queue(&chip->wq, &wait);
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			schedule();
 			remove_wait_queue(&chip->wq, &wait);
-			timeo = jiffies + (HZ*20); /* FIXME */
-			spin_lock_bh(chip->mutex);
+			spin_lock(chip->mutex);
 			continue;
 		}
+		if (chip->erase_suspended) {
+			/* This erase was suspended and resumed.
+			   Adjust the timeout */
+			timeo = jiffies + (HZ*20); /* FIXME */
+			chip->erase_suspended = 0;
+		}
 
 		status = cfi_read(map, adr);
 		if ((status & status_OK) == status_OK)
@@ -1022,16 +1315,21 @@
 		if (time_after(jiffies, timeo)) {
 			cfi_write(map, CMD(0x70), adr);
 			chip->state = FL_STATUS;
-			printk(KERN_ERR "waiting for erase to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			printk(KERN_ERR "waiting for erase at %08lx to complete timed out. Xstatus = %llx, status = %llx.\n",
+			       adr, (__u64)status, (__u64)cfi_read(map, adr));
+			/* Clear status bits */
+			cfi_write(map, CMD(0x50), adr);
+			cfi_write(map, CMD(0x70), adr);
 			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			return -EIO;
 		}
 		
 		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-		cfi_udelay(1);
-		spin_lock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+		spin_lock(chip->mutex);
 	}
 	
 	DISABLE_VPP(map);
@@ -1050,124 +1348,52 @@
 			for (i = 1; i<CFIDEV_INTERLEAVE; i++) {
 				      chipstatus |= status >> (cfi->device_type * 8);
 			}
-			printk(KERN_WARNING "Status is not identical for all chips: 0x%x. Merging to give 0x%02x\n", status, chipstatus);
+			printk(KERN_WARNING "Status is not identical for all chips: 0x%llx. Merging to give 0x%02x\n", (__u64)status, chipstatus);
 		}
 		/* Reset the error bits */
 		cfi_write(map, CMD(0x50), adr);
 		cfi_write(map, CMD(0x70), adr);
 		
 		if ((chipstatus & 0x30) == 0x30) {
-			printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", status);
+			printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%llx\n", (__u64)status);
 			ret = -EIO;
 		} else if (chipstatus & 0x02) {
 			/* Protection bit set */
 			ret = -EROFS;
 		} else if (chipstatus & 0x8) {
 			/* Voltage */
-			printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", status);
+			printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%llx\n", (__u64)status);
 			ret = -EIO;
 		} else if (chipstatus & 0x20) {
 			if (retries--) {
-				printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, status);
+				printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%llx. Retrying...\n", adr, (__u64)status);
 				timeo = jiffies + HZ;
 				chip->state = FL_STATUS;
-				spin_unlock_bh(chip->mutex);
+				spin_unlock(chip->mutex);
 				goto retry;
 			}
-			printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, status);
+			printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%llx\n", adr, (__u64)status);
 			ret = -EIO;
 		}
 	}
 
 	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
+	spin_unlock(chip->mutex);
 	return ret;
 }
 
 int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
-{	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned long adr, len;
-	int chipnum, ret = 0;
-	int i, first;
-	struct mtd_erase_region_info *regions = mtd->eraseregions;
-
-	if (instr->addr > mtd->size)
-		return -EINVAL;
-
-	if ((instr->len + instr->addr) > mtd->size)
-		return -EINVAL;
-
-	/* Check that both start and end of the requested erase are
-	 * aligned with the erasesize at the appropriate addresses.
-	 */
-
-	i = 0;
-
-	/* Skip all erase regions which are ended before the start of 
-	   the requested erase. Actually, to save on the calculations,
-	   we skip to the first erase region which starts after the
-	   start of the requested erase, and then go back one.
-	*/
-	
-	while (i < mtd->numeraseregions && instr->addr >= regions[i].offset)
-	       i++;
-	i--;
-
-	/* OK, now i is pointing at the erase region in which this 
-	   erase request starts. Check the start of the requested
-	   erase range is aligned with the erase size which is in
-	   effect here.
-	*/
-
-	if (instr->addr & (regions[i].erasesize-1))
-		return -EINVAL;
-
-	/* Remember the erase region we start on */
-	first = i;
-
-	/* Next, check that the end of the requested erase is aligned
-	 * with the erase region at that address.
-	 */
-
-	while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)
-		i++;
-
-	/* As before, drop back one to point at the region in which
-	   the address actually falls
-	*/
-	i--;
-	
-	if ((instr->addr + instr->len) & (regions[i].erasesize-1))
-		return -EINVAL;
+{
+	unsigned long ofs, len;
+	int ret;
 
-	chipnum = instr->addr >> cfi->chipshift;
-	adr = instr->addr - (chipnum << cfi->chipshift);
+	ofs = instr->addr;
 	len = instr->len;
 
-	i=first;
+	ret = cfi_intelext_varsize_frob(mtd, do_erase_oneblock, ofs, len, 0);
+	if (ret)
+		return ret;
 
-	while(len) {
-		ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
-		
-		if (ret)
-			return ret;
-
-		adr += regions[i].erasesize;
-		len -= regions[i].erasesize;
-
-		if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
-			i++;
-
-		if (adr >> cfi->chipshift) {
-			adr = 0;
-			chipnum++;
-			
-			if (chipnum >= cfi->numchips)
-			break;
-		}
-	}
-		
 	instr->state = MTD_ERASE_DONE;
 	if (instr->callback)
 		instr->callback(instr);
@@ -1182,38 +1408,20 @@
 	int i;
 	struct flchip *chip;
 	int ret = 0;
-	DECLARE_WAITQUEUE(wait, current);
 
 	for (i=0; !ret && i<cfi->numchips; i++) {
 		chip = &cfi->chips[i];
 
-	retry:
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
+		ret = get_chip(map, chip, chip->start, FL_SYNCING);
 
-		switch(chip->state) {
-		case FL_READY:
-		case FL_STATUS:
-		case FL_CFI_QUERY:
-		case FL_JEDEC_QUERY:
+		if (!ret) {
 			chip->oldstate = chip->state;
 			chip->state = FL_SYNCING;
 			/* No need to wake_up() on this state change - 
 			 * as the whole point is that nobody can do anything
 			 * with the chip now anyway.
 			 */
-		case FL_SYNCING:
-			spin_unlock_bh(chip->mutex);
-			break;
-
-		default:
-			/* Not an idle state */
-			add_wait_queue(&chip->wq, &wait);
-			
-			spin_unlock_bh(chip->mutex);
-			schedule();
-		        remove_wait_queue(&chip->wq, &wait);
-			
-			goto retry;
 		}
 	}
 
@@ -1222,231 +1430,73 @@
 	for (i--; i >=0; i--) {
 		chip = &cfi->chips[i];
 
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 		
 		if (chip->state == FL_SYNCING) {
 			chip->state = chip->oldstate;
 			wake_up(&chip->wq);
 		}
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 	}
 }
 
-static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+#ifdef DEBUG_LOCK_BITS
+static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	__u32 status, status_OK;
-	unsigned long timeo = jiffies + HZ;
-	DECLARE_WAITQUEUE(wait, current);
-
-	adr += chip->start;
-
-	/* Let's determine this according to the interleave only once */
-	status_OK = CMD(0x80);
-
-	timeo = jiffies + HZ;
-retry:
-	spin_lock_bh(chip->mutex);
-
-	/* Check that the chip's ready to talk to us. */
-	switch (chip->state) {
-	case FL_CFI_QUERY:
-	case FL_JEDEC_QUERY:
-	case FL_READY:
-		cfi_write(map, CMD(0x70), adr);
-		chip->state = FL_STATUS;
-
-	case FL_STATUS:
-		status = cfi_read(map, adr);
-		if ((status & status_OK) == status_OK) 
-			break;
-		
-		/* Urgh. Chip not yet ready to talk to us. */
-		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_ERR "waiting for chip to be ready timed out in lock\n");
-			return -EIO;
-		}
-
-		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-		cfi_udelay(1);
-		goto retry;
-
-	default:
-		/* Stick ourselves on a wait queue to be woken when
-		   someone changes the status */
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-		timeo = jiffies + HZ;
-		goto retry;
-	}
-
-	ENABLE_VPP(map);
-	cfi_write(map, CMD(0x60), adr);
-	cfi_write(map, CMD(0x01), adr);
-	chip->state = FL_LOCKING;
-	
-	spin_unlock_bh(chip->mutex);
-	schedule_timeout(HZ);
-	spin_lock_bh(chip->mutex);
-
-	/* FIXME. Use a timer to check this, and return immediately. */
-	/* Once the state machine's known to be working I'll do that */
-
-	timeo = jiffies + (HZ*2);
-	for (;;) {
+	int ofs_factor = cfi->interleave * cfi->device_type;
 
-		status = cfi_read(map, adr);
-		if ((status & status_OK) == status_OK)
-			break;
-		
-		/* OK Still waiting */
-		if (time_after(jiffies, timeo)) {
-			cfi_write(map, CMD(0x70), adr);
-			chip->state = FL_STATUS;
-			printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
-			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
-			return -EIO;
-		}
-		
-		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-		cfi_udelay(1);
-		spin_lock_bh(chip->mutex);
-	}
+	cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+	printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
+	       adr, cfi_read_query(map, adr+(2*ofs_factor)));
+	cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
 	
-	/* Done and happy. */
-	chip->state = FL_STATUS;
-	DISABLE_VPP(map);
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
 	return 0;
 }
-static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
-	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned long adr;
-	int chipnum, ret = 0;
-#ifdef DEBUG_LOCK_BITS
-	int ofs_factor = cfi->interleave * cfi->device_type;
-#endif
-
-	if (ofs & (mtd->erasesize - 1))
-		return -EINVAL;
-
-	if (len & (mtd->erasesize -1))
-		return -EINVAL;
-
-	if ((len + ofs) > mtd->size)
-		return -EINVAL;
-
-	chipnum = ofs >> cfi->chipshift;
-	adr = ofs - (chipnum << cfi->chipshift);
-
-	while(len) {
-
-#ifdef DEBUG_LOCK_BITS
-		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
-		printk("before lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
-		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
 #endif
 
-		ret = do_lock_oneblock(map, &cfi->chips[chipnum], adr);
-
-#ifdef DEBUG_LOCK_BITS
-		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
-		printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
-		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
-#endif	
-		
-		if (ret)
-			return ret;
-
-		adr += mtd->erasesize;
-		len -= mtd->erasesize;
+#define DO_XXLOCK_ONEBLOCK_LOCK		((void *) 1)
+#define DO_XXLOCK_ONEBLOCK_UNLOCK	((void *) 2)
 
-		if (adr >> cfi->chipshift) {
-			adr = 0;
-			chipnum++;
-			
-			if (chipnum >= cfi->numchips)
-			break;
-		}
-	}
-	return 0;
-}
-static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
-	__u32 status, status_OK;
+	cfi_word status, status_OK;
 	unsigned long timeo = jiffies + HZ;
-	DECLARE_WAITQUEUE(wait, current);
+	int ret;
 
 	adr += chip->start;
 
 	/* Let's determine this according to the interleave only once */
 	status_OK = CMD(0x80);
 
-	timeo = jiffies + HZ;
-retry:
-	spin_lock_bh(chip->mutex);
-
-	/* Check that the chip's ready to talk to us. */
-	switch (chip->state) {
-	case FL_CFI_QUERY:
-	case FL_JEDEC_QUERY:
-	case FL_READY:
-		cfi_write(map, CMD(0x70), adr);
-		chip->state = FL_STATUS;
-
-	case FL_STATUS:
-		status = cfi_read(map, adr);
-		if ((status & status_OK) == status_OK)
-			break;
-		
-		/* Urgh. Chip not yet ready to talk to us. */
-		if (time_after(jiffies, timeo)) {
-			spin_unlock_bh(chip->mutex);
-			printk(KERN_ERR "waiting for chip to be ready timed out in unlock\n");
-			return -EIO;
-		}
-
-		/* Latency issues. Drop the lock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
-		cfi_udelay(1);
-		goto retry;
-
-	default:
-		/* Stick ourselves on a wait queue to be woken when
-		   someone changes the status */
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		add_wait_queue(&chip->wq, &wait);
-		spin_unlock_bh(chip->mutex);
-		schedule();
-		remove_wait_queue(&chip->wq, &wait);
-		timeo = jiffies + HZ;
-		goto retry;
+	spin_lock(chip->mutex);
+	ret = get_chip(map, chip, adr, FL_LOCKING);
+	if (ret) {
+		spin_unlock(chip->mutex);
+		return ret;
 	}
 
 	ENABLE_VPP(map);
 	cfi_write(map, CMD(0x60), adr);
-	cfi_write(map, CMD(0xD0), adr);
-	chip->state = FL_UNLOCKING;
-	
-	spin_unlock_bh(chip->mutex);
+
+	if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) {
+		cfi_write(map, CMD(0x01), adr);
+		chip->state = FL_LOCKING;
+	} else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) {
+		cfi_write(map, CMD(0xD0), adr);
+		chip->state = FL_UNLOCKING;
+	} else
+		BUG();
+
+	spin_unlock(chip->mutex);
 	schedule_timeout(HZ);
-	spin_lock_bh(chip->mutex);
+	spin_lock(chip->mutex);
 
 	/* FIXME. Use a timer to check this, and return immediately. */
 	/* Once the state machine's known to be working I'll do that */
 
-	timeo = jiffies + (HZ*2);
+	timeo = jiffies + (HZ*20);
 	for (;;) {
 
 		status = cfi_read(map, adr);
@@ -1457,59 +1507,67 @@
 		if (time_after(jiffies, timeo)) {
 			cfi_write(map, CMD(0x70), adr);
 			chip->state = FL_STATUS;
-			printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %llx, status = %llx.\n", (__u64)status, (__u64)cfi_read(map, adr));
 			DISABLE_VPP(map);
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 			return -EIO;
 		}
 		
-		/* Latency issues. Drop the unlock, wait a while and retry */
-		spin_unlock_bh(chip->mutex);
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock(chip->mutex);
 		cfi_udelay(1);
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 	}
 	
 	/* Done and happy. */
 	chip->state = FL_STATUS;
-	DISABLE_VPP(map);
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
+	put_chip(map, chip, adr);
+	spin_unlock(chip->mutex);
 	return 0;
 }
-static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+
+static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
 {
-	struct map_info *map = mtd->priv;
-	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned long adr;
-	int chipnum, ret = 0;
+	int ret;
+
 #ifdef DEBUG_LOCK_BITS
-	int ofs_factor = cfi->interleave * cfi->device_type;
+	printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
+	       __FUNCTION__, ofs, len);
+	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
+				  ofs, len, 0);
 #endif
 
-	chipnum = ofs >> cfi->chipshift;
-	adr = ofs - (chipnum << cfi->chipshift);
-
+	ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock, 
+					ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);
+	
 #ifdef DEBUG_LOCK_BITS
-	{
-		unsigned long temp_adr = adr;
-		unsigned long temp_len = len;
-                 
-		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
-                while (temp_len) {
-			printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor)));
-			temp_adr += mtd->erasesize;
-			temp_len -= mtd->erasesize;
-		}
-		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
-	}
+	printk(KERN_DEBUG __FUNCTION__
+	       "%s: lock status after, ret=%d\n", __FUNCTION__, ret);
+	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
+				  ofs, len, 0);
 #endif
 
-	ret = do_unlock_oneblock(map, &cfi->chips[chipnum], adr);
+	return ret;
+}
+
+static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	int ret;
 
 #ifdef DEBUG_LOCK_BITS
-	cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
-	printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
-	cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+	printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
+	       __FUNCTION__, ofs, len);
+	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
+				  ofs, len, 0);
+#endif
+
+	ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock,
+					ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK);
+	
+#ifdef DEBUG_LOCK_BITS
+	printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret);
+	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock, 
+				  ofs, len, 0);
 #endif
 	
 	return ret;
@@ -1526,27 +1584,28 @@
 	for (i=0; !ret && i<cfi->numchips; i++) {
 		chip = &cfi->chips[i];
 
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 
-		switch(chip->state) {
+		switch (chip->state) {
 		case FL_READY:
 		case FL_STATUS:
 		case FL_CFI_QUERY:
 		case FL_JEDEC_QUERY:
-			chip->oldstate = chip->state;
-			chip->state = FL_PM_SUSPENDED;
-			/* No need to wake_up() on this state change - 
-			 * as the whole point is that nobody can do anything
-			 * with the chip now anyway.
-			 */
-		case FL_PM_SUSPENDED:
+			if (chip->oldstate == FL_READY) {
+				chip->oldstate = chip->state;
+				chip->state = FL_PM_SUSPENDED;
+				/* No need to wake_up() on this state change - 
+				 * as the whole point is that nobody can do anything
+				 * with the chip now anyway.
+				 */
+			}
 			break;
-
 		default:
 			ret = -EAGAIN;
+		case FL_PM_SUSPENDED:
 			break;
 		}
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 	}
 
 	/* Unlock the chips again */
@@ -1555,7 +1614,7 @@
 		for (i--; i >=0; i--) {
 			chip = &cfi->chips[i];
 			
-			spin_lock_bh(chip->mutex);
+			spin_lock(chip->mutex);
 			
 			if (chip->state == FL_PM_SUSPENDED) {
 				/* No need to force it into a known state here,
@@ -1564,7 +1623,7 @@
 				chip->state = chip->oldstate;
 				wake_up(&chip->wq);
 			}
-			spin_unlock_bh(chip->mutex);
+			spin_unlock(chip->mutex);
 		}
 	} 
 	
@@ -1582,7 +1641,7 @@
 	
 		chip = &cfi->chips[i];
 
-		spin_lock_bh(chip->mutex);
+		spin_lock(chip->mutex);
 		
 		/* Go to known state. Chip may have been power cycled */
 		if (chip->state == FL_PM_SUSPENDED) {
@@ -1591,7 +1650,7 @@
 			wake_up(&chip->wq);
 		}
 
-		spin_unlock_bh(chip->mutex);
+		spin_unlock(chip->mutex);
 	}
 }
 
@@ -1600,7 +1659,9 @@
 	struct map_info *map = mtd->priv;
 	struct cfi_private *cfi = map->fldrv_priv;
 	kfree(cfi->cmdset_priv);
+	kfree(cfi->cfiq);
 	kfree(cfi);
+	kfree(mtd->eraseregions);
 }
 
 static char im_name_1[]="cfi_cmdset_0001";
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 May 14 23:43:59 2003
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c	Wed May 28 08:01:01 2003
@@ -8,7 +8,7 @@
  *
  * This code is GPL
  *
- * $Id: cfi_cmdset_0002.c,v 1.52 2001/10/24 09:37:30 dwmw2 Exp $
+ * $Id: cfi_cmdset_0002.c,v 1.74 2003/05/28 12:51:48 dwmw2 Exp $
  *
  */
 
@@ -16,6 +16,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 
@@ -24,17 +25,21 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/map.h>
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/cfi.h>
+#include <linux/mtd/compatmac.h>
 
 #define AMD_BOOTLOC_BUG
 
 static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_amdstd_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *);
 static int cfi_amdstd_erase_onesize(struct mtd_info *, struct erase_info *);
 static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *);
 static void cfi_amdstd_sync (struct mtd_info *);
 static int cfi_amdstd_suspend (struct mtd_info *);
 static void cfi_amdstd_resume (struct mtd_info *);
+static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 
 static void cfi_amdstd_destroy(struct mtd_info *);
 
@@ -49,6 +54,7 @@
 	.module		= THIS_MODULE
 };
 
+
 struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
@@ -58,7 +64,7 @@
 	__u8 major, minor;
 	__u32 base = cfi->chips[0].start;
 
-	if (cfi->cfi_mode==1){
+	if (cfi->cfi_mode==CFI_MODE_CFI){
 		__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
 
 		cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
@@ -73,8 +79,9 @@
 		cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
 		cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
 		cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
+		/* FIXME - should have a delay before continuing */
 		cfi->mfr = cfi_read_query(map, base);
-		cfi->id = cfi_read_query(map, base + ofs_factor);
+		cfi->id = cfi_read_query(map, base + ofs_factor);    
 
 		/* Wheee. Bring me the head of someone at AMD. */
 #ifdef AMD_BOOTLOC_BUG
@@ -104,6 +111,10 @@
 				cfi->cfiq->EraseRegionInfo[j] = swap;
 			}
 		}
+		/*
+		 * FIXME - These might already be setup (more correctly)
+		 * buy jedec_probe.c.
+		 */
 		switch (cfi->device_type) {
 		case CFI_DEVICETYPE_X8:
 			cfi->addr_unlock1 = 0x555; 
@@ -135,7 +146,6 @@
 	}		
 	
 	map->fldrv = &cfi_amdstd_chipdrv;
-	MOD_INC_USE_COUNT;
 
 	cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
 	return cfi_amdstd_setup(map);
@@ -148,12 +158,12 @@
 	unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
 
 	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
-	printk(KERN_NOTICE "number of %s chips: %d\n", (cfi->cfi_mode)?"CFI":"JEDEC",cfi->numchips);
+	printk(KERN_NOTICE "number of %s chips: %d\n", 
+		(cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips);
 
 	if (!mtd) {
 	  printk(KERN_WARNING "Failed to allocate memory for MTD device\n");
-	  kfree(cfi->cmdset_priv);
-	  return NULL;
+	  goto setup_err;
 	}
 
 	memset(mtd, 0, sizeof(*mtd));
@@ -173,9 +183,7 @@
 		mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL);
 		if (!mtd->eraseregions) { 
 			printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n");
-			kfree(cfi->cmdset_priv);
-			kfree(mtd);
-			return NULL;
+			goto setup_err;
 		}
 			
 		for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
@@ -196,10 +204,7 @@
 		if (offset != devsize) {
 			/* Argh */
 			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;
+			goto setup_err;
 		}
 #if 0
 		// debug
@@ -222,6 +227,9 @@
 			mtd->erase = cfi_amdstd_erase_varsize;
 		else
 #endif
+		if (((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1)
+			mtd->erase = cfi_amdstd_erase_chip;
+		else
 			mtd->erase = cfi_amdstd_erase_onesize;
 		mtd->read = cfi_amdstd_read;
 		mtd->write = cfi_amdstd_write;
@@ -229,19 +237,56 @@
 
 	default:
 	        printk(KERN_WARNING "Unsupported buswidth\n");
-		kfree(mtd);
-		kfree(cfi->cmdset_priv);
-		return NULL;
+		goto setup_err;
 		break;
 	}
+	if (cfi->fast_prog) {
+		/* In cfi_amdstd_write() we frob the protection stuff
+		   without paying any attention to the state machine.
+		   This upsets in-progress erases. So we turn this flag
+		   off for now till the code gets fixed. */
+		printk(KERN_NOTICE "cfi_cmdset_0002: Disabling fast programming due to code brokenness.\n");
+		cfi->fast_prog = 0;
+	}
+
+
+        /* does this chip have a secsi area? */
+	if(cfi->mfr==1){
+		
+		switch(cfi->id){
+		case 0x50:
+		case 0x53:
+		case 0x55:
+		case 0x56:
+		case 0x5C:
+		case 0x5F:
+			/* Yes */
+			mtd->read_user_prot_reg = cfi_amdstd_secsi_read;
+			mtd->read_fact_prot_reg = cfi_amdstd_secsi_read;
+		default:		       
+			;
+		}
+	}
+	
+		
 	mtd->sync = cfi_amdstd_sync;
 	mtd->suspend = cfi_amdstd_suspend;
 	mtd->resume = cfi_amdstd_resume;
 	mtd->flags = MTD_CAP_NORFLASH;
 	map->fldrv = &cfi_amdstd_chipdrv;
 	mtd->name = map->name;
-	MOD_INC_USE_COUNT;
+	__module_get(THIS_MODULE);
 	return mtd;
+
+ setup_err:
+	if(mtd) {
+		if(mtd->eraseregions)
+			kfree(mtd->eraseregions);
+		kfree(mtd);
+	}
+	kfree(cfi->cmdset_priv);
+	kfree(cfi->cfiq);
+	return NULL;
 }
 
 static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
@@ -276,7 +321,7 @@
 
 	chip->state = FL_READY;
 
-	map->copy_from(map, buf, adr, len);
+	map_copy_from(map, buf, adr, len);
 
 	wake_up(&chip->wq);
 	cfi_spin_unlock(chip->mutex);
@@ -325,19 +370,122 @@
 	return ret;
 }
 
-static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum, int fast)
+static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
 {
+	DECLARE_WAITQUEUE(wait, current);
 	unsigned long timeo = jiffies + HZ;
-	unsigned int Last[4];
-	unsigned long Count = 0;
 	struct cfi_private *cfi = map->fldrv_priv;
+
+ retry:
+	cfi_spin_lock(chip->mutex);
+
+	if (chip->state != FL_READY){
+#if 0
+	        printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);
+#endif
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+                
+		cfi_spin_unlock(chip->mutex);
+
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+#if 0
+		if(signal_pending(current))
+			return -EINTR;
+#endif
+		timeo = jiffies + HZ;
+
+		goto retry;
+	}	
+
+	adr += chip->start;
+
+	chip->state = FL_READY;
+	
+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	
+	map_copy_from(map, buf, adr, len);
+
+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
+	
+	wake_up(&chip->wq);
+	cfi_spin_unlock(chip->mutex);
+
+	return 0;
+}
+
+static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long ofs;
+	int chipnum;
+	int ret = 0;
+
+
+	/* ofs: offset within the first chip that the first read should start */
+
+	/* 8 secsi bytes per chip */
+	chipnum=from>>3;
+	ofs=from & 7;
+
+
+	*retlen = 0;
+
+	while (len) {
+		unsigned long thislen;
+
+		if (chipnum >= cfi->numchips)
+			break;
+
+		if ((len + ofs -1) >> 3)
+			thislen = (1<<3) - ofs;
+		else
+			thislen = len;
+
+		ret = do_read_secsi_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
+		if (ret)
+			break;
+
+		*retlen += thislen;
+		len -= thislen;
+		buf += thislen;
+
+		ofs = 0;
+		chipnum++;
+	}
+	return ret;
+}
+
+static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum, int fast)
+{
+	unsigned long timeo = jiffies + HZ;
+	unsigned int oldstatus, status, prev_oldstatus, prev_status;
+	unsigned int dq6;
+	struct cfi_private *cfi = map->fldrv_priv;
+    /* We use a 1ms + 1 jiffies generic timeout for writes (most devices have
+       a max write time of a few hundreds usec). However, we should use the
+       maximum timeout value given by the chip at probe time instead. 
+       Unfortunately, struct flchip does have a field for maximum timeout, 
+       only for typical which can be far too short depending of the conditions.
+       The ' + 1' is to avoid having a timeout of 0 jiffies if HZ is smaller
+       than 1000. Using a static variable allows makes us save the costly
+       divide operation at each word write.*/ 
+    static unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
 	DECLARE_WAITQUEUE(wait, current);
 	int ret = 0;
+	int ta = 0;
 
  retry:
 	cfi_spin_lock(chip->mutex);
 
-	if (chip->state != FL_READY){
+	if (chip->state != FL_READY) {
 #if 0
 	        printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", chip->state);
 #endif
@@ -361,6 +509,9 @@
 	chip->state = FL_WRITING;
 
 	adr += chip->start;
+	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8x)\n",
+	       __func__, adr, datum );
+
 	ENABLE_VPP(map);
 	if (fast) { /* Unlock bypass */
 		cfi_send_gen_cmd(0xA0, 0, chip->start, map, cfi, cfi->device_type, NULL);
@@ -370,40 +521,147 @@
 	        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 	        cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 	}
-
 	cfi_write(map, datum, adr);
 
 	cfi_spin_unlock(chip->mutex);
 	cfi_udelay(chip->word_write_time);
 	cfi_spin_lock(chip->mutex);
 
-	Last[0] = cfi_read(map, adr);
-	//	printk("Last[0] is %x\n", Last[0]);
-	Last[1] = cfi_read(map, adr);
-	//	printk("Last[1] is %x\n", Last[1]);
-	Last[2] = cfi_read(map, adr);
-	//	printk("Last[2] is %x\n", Last[2]);
-
-	for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && Count < 10000; Count++){
-		cfi_spin_unlock(chip->mutex);
-		cfi_udelay(10);
-		cfi_spin_lock(chip->mutex);
+	/*
+	 * Polling toggle bits instead of reading back many times
+	 * This ensures that write operation is really completed,
+	 * or tells us why it failed.
+	 *
+	 * It appears tha the polling and decoding of error state might
+	 * be simplified.  Don't do it unless you really know what you
+	 * are doing.  You must remember that JESD21-C 3.5.3 states that
+	 * the status must be read back an _additional_ two times before
+	 * a failure is determined.  This is because these devices have
+	 * internal state machines that are asynchronous to the external
+	 * data bus.  During an erase or write the read-back status of the
+	 * polling bits might be transitioning internaly when the external
+	 * read-back occurs.  This means that the bits aren't in the final
+	 * state and they might appear to report an error as they transition
+	 * and are in a weird state.  This will produce infrequent errors
+	 * that will usually disappear the next time an erase or write
+	 * happens (Try tracking those errors down!).  To ensure that
+	 * the bits are not in transition the location must be read-back
+	 * two more times and compared against what was written - BOTH reads
+	 * MUST match what was written - don't think this can be simplified
+	 * to only the last read matching.  If the comparison fails, error
+	 * state can then be decoded.
+	 *
+	 * - Thayne Harbaugh
+	 */
+	dq6 = CMD(1<<6);
+	/* See comment above for timeout value. */
+	timeo = jiffies + uWriteTimeout; 
 		
-	        Last[Count % 4] = cfi_read(map, adr);
-		//		printk("Last[%d%%4] is %x\n", Count, Last[Count%4]);
+	oldstatus = cfi_read(map, adr);
+	status = cfi_read(map, adr);
+	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
+	       __func__, oldstatus, status );
+
+	/*
+	 * This only checks if dq6 is still toggling and that our
+	 * timer hasn't expired.  We purposefully ignore the chips
+	 * internal timer that will assert dq5 and leave dq6 toggling.
+	 * This is done for a variety of reasons:
+	 * 1) Not all chips support dq5.
+	 * 2) Dealing with asynchronous status bit and data updates
+	 *    and reading a device two more times creates _messy_
+	 *    logic when trying to deal with interleaved devices -
+	 *    some may be changing while others are still busy.
+	 * 3) Checking dq5 only helps to optimize an error case that
+	 *    should at worst be infrequent and at best non-existent.
+	 *
+	 * If our timeout occurs _then_ we will check dq5 to see
+	 * if the device also had an internal timeout.
+	 */
+	while( ( ( status ^ oldstatus ) & dq6 )
+	       && ! ( ta = time_after(jiffies, timeo) ) ) {
+
+		if (need_resched()) {
+			cfi_spin_unlock(chip->mutex);
+			yield();
+			cfi_spin_lock(chip->mutex);
+		} else 
+			udelay(1);
+
+		oldstatus = cfi_read( map, adr );
+		status = cfi_read( map, adr );
+		DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
+		       __func__, oldstatus, status );
 	}
-	
-	if (Last[(Count - 1) % 4] != datum){
-		printk(KERN_WARNING "Last[%ld] is %x, datum is %x\n",(Count - 1) % 4,Last[(Count - 1) % 4],datum);
-	        cfi_send_gen_cmd(0xF0, 0, chip->start, map, cfi, cfi->device_type, NULL);
-		DISABLE_VPP(map);
-		ret = -EIO;
-	}       
+
+	/*
+	 * Something kicked us out of the read-back loop.  We'll
+	 * check success befor checking failure.
+	 * Even though dq6 might be true data, it is unkown if
+	 * all of the other bits have changed to true data due to
+	 * the asynchronous nature of the internal state machine.
+	 * We will read two more times and use this to either
+	 * verify that the write completed successfully or
+	 * that something really went wrong.  BOTH reads
+	 * must match what was written - this certifies that
+	 * bits aren't still changing  and that the status
+	 * bits erroneously match the datum that was written.
+	 */
+	prev_oldstatus = oldstatus;
+	prev_status = status;
+	oldstatus = cfi_read(map, adr);
+	status = cfi_read(map, adr);
+	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
+	       __func__, oldstatus, status );
+
+	if ( oldstatus == datum && status == datum ) {
+		/* success - do nothing */
+		goto write_done;
+	}
+
+	if ( ta ) {
+		int dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
+		if ( status & dq5mask ) {
+			/* dq5 asserted - decode interleave chips */
+			printk( KERN_WARNING
+				"MTD %s(): FLASH internal timeout: 0x%.8x\n",
+				__func__,
+				status & dq5mask );
+		} else {
+			printk( KERN_WARNING
+				"MTD %s(): Software timed out during write.\n",
+				__func__ );
+		}
+		goto write_failed;
+	}
+
+	/*
+	 * If we get to here then it means that something
+	 * is wrong and it's not a timeout.  Something
+	 * is seriously wacky!  Dump some debug info.
+	 */
+	printk(KERN_WARNING
+	       "MTD %s(): Wacky!  Unable to decode failure status\n",
+	       __func__ );
+
+	printk(KERN_WARNING
+	       "MTD %s(): 0x%.8lx(0x%.8x): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
+	       __func__, adr, datum,
+	       prev_oldstatus, prev_status,
+	       oldstatus, status);
+
+ write_failed:
+	ret = -EIO;
+	/* reset on all failures. */
+	cfi_write( map, CMD(0xF0), chip->start );
+	/* FIXME - should have reset delay before continuing */
+
+ write_done:
 	DISABLE_VPP(map);
 	chip->state = FL_READY;
 	wake_up(&chip->wq);
 	cfi_spin_unlock(chip->mutex);
-	
+
 	return ret;
 }
 
@@ -428,10 +686,10 @@
 		unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);
 		int i = ofs - bus_ofs;
 		int n = 0;
-		u_char tmp_buf[4];
-		__u32 datum;
+		u_char tmp_buf[8];
+		cfi_word datum;
 
-		map->copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
+		map_copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
 		while (len && i < CFIDEV_BUSWIDTH)
 			tmp_buf[i++] = buf[n++], len--;
 
@@ -444,7 +702,7 @@
 		}
 
 		ret = do_write_oneword(map, &cfi->chips[chipnum], 
-				bus_ofs, datum, 0);
+				       bus_ofs, datum, 0);
 		if (ret) 
 			return ret;
 		
@@ -460,14 +718,16 @@
 		}
 	}
 	
-	/* Go into unlock bypass mode */
-	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-	cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	if (cfi->fast_prog) {
+		/* Go into unlock bypass mode */
+		cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
+		cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
+		cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	}
 
 	/* We are now aligned, write as much as possible */
 	while(len >= CFIDEV_BUSWIDTH) {
-		__u32 datum;
+		cfi_word datum;
 
 		if (cfi_buswidth_is_1()) {
 			datum = *(__u8*)buf;
@@ -521,12 +781,13 @@
 		cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
 	}
 
+	/* Write the trailing bytes if any */
 	if (len & (CFIDEV_BUSWIDTH-1)) {
 		int i = 0, n = 0;
-		u_char tmp_buf[4];
-		__u32 datum;
+		u_char tmp_buf[8];
+		cfi_word datum;
 
-		map->copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
+		map_copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
 		while (len--)
 			tmp_buf[i++] = buf[n++];
 
@@ -549,13 +810,197 @@
 	return 0;
 }
 
+static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
+{
+	unsigned int oldstatus, status, prev_oldstatus, prev_status;
+	unsigned int dq6;
+	unsigned long timeo = jiffies + HZ;
+	unsigned long int adr;
+	struct cfi_private *cfi = map->fldrv_priv;
+	DECLARE_WAITQUEUE(wait, current);
+	int ret = 0;
+	int ta = 0;
+	cfi_word ones = 0;
+
+ retry:
+	cfi_spin_lock(chip->mutex);
+
+	if (chip->state != FL_READY){
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+                
+		cfi_spin_unlock(chip->mutex);
+
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+#if 0
+		if(signal_pending(current))
+			return -EINTR;
+#endif
+		timeo = jiffies + HZ;
+
+		goto retry;
+	}	
+
+	chip->state = FL_ERASING;
+	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
+	       __func__, chip->start );
+	
+	/* Handle devices with one erase region, that only implement
+	 * the chip erase command.
+	 */
+	ENABLE_VPP(map);
+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	timeo = jiffies + (HZ*20);
+	adr = cfi->addr_unlock1;
+
+	/* Wait for the end of programing/erasure by using the toggle method.
+	 * As long as there is a programming procedure going on, bit 6
+	 * is toggling it's state with each consecutive read.
+	 * The toggling stops as soon as the procedure is completed.
+	 *
+	 * If the process has gone on for too long on the chip bit 5 gets.
+	 * After bit5 is set you can kill the operation by sending a reset
+	 * command to the chip.
+	 */
+	/* see comments in do_write_oneword */
+	dq6 = CMD(1<<6);
+
+	oldstatus = cfi_read(map, adr);
+	status = cfi_read(map, adr);
+	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
+	       __func__, oldstatus, status );
+
+	while( ( ( status ^ oldstatus ) & dq6 )
+	       && ! ( ta = time_after(jiffies, timeo) ) ) {
+		int wait_reps;
+
+		/* an initial short sleep */
+		cfi_spin_unlock(chip->mutex);
+		schedule_timeout(HZ/100);
+		cfi_spin_lock(chip->mutex);
+		
+		if (chip->state != FL_ERASING) {
+			/* Someone's suspended the erase. Sleep */
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			add_wait_queue(&chip->wq, &wait);
+			
+			cfi_spin_unlock(chip->mutex);
+			printk("erase suspended. Sleeping\n");
+			
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+#if 0			
+			if (signal_pending(current))
+				return -EINTR;
+#endif			
+			timeo = jiffies + (HZ*2); /* FIXME */
+			cfi_spin_lock(chip->mutex);
+			continue;
+		}
+
+		/* Busy wait for 1/10 of a milisecond */
+		for(wait_reps = 0;
+		    (wait_reps < 100)
+			    && ( ( status ^ oldstatus ) & dq6 );
+		    wait_reps++) {
+			
+			/* Latency issues. Drop the lock, wait a while and retry */
+			cfi_spin_unlock(chip->mutex);
+
+			cfi_udelay(1);
+
+			cfi_spin_lock(chip->mutex);
+			oldstatus = cfi_read(map, adr);
+			status = cfi_read(map, adr);
+			DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
+			       __func__, oldstatus, status );
+		}
+		oldstatus = cfi_read(map, adr);
+		status = cfi_read(map, adr);
+		DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
+		       __func__, oldstatus, status );
+	}
+
+	prev_oldstatus = oldstatus;
+	prev_status = status;
+	oldstatus = cfi_read(map, adr);
+	status = cfi_read(map, adr);
+	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
+	       __func__, oldstatus, status );
+
+	if ( cfi_buswidth_is_1() ) {
+		ones =  (__u8)~0;
+	} else if ( cfi_buswidth_is_2() ) {
+		ones = (__u16)~0;
+	} else if ( cfi_buswidth_is_4() ) {
+		ones = (__u32)~0;
+	} else {
+		printk(KERN_WARNING "Unsupported buswidth\n");
+		goto erase_failed;
+	}
+	
+	if ( oldstatus == ones && status == ones ) {
+		/* success - do nothing */
+		goto erase_done;
+	}
+
+	if ( ta ) {
+		int dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
+		if ( status & dq5mask ) {
+			/* dq5 asserted - decode interleave chips */
+			printk( KERN_WARNING
+				"MTD %s(): FLASH internal timeout: 0x%.8x\n",
+				__func__,
+				status & dq5mask );
+		} else {
+			printk( KERN_WARNING
+				"MTD %s(): Software timed out during write.\n",
+				__func__ );
+		}
+		goto erase_failed;
+	}
+
+	printk(KERN_WARNING
+	       "MTD %s(): Wacky!  Unable to decode failure status\n",
+	       __func__ );
+
+	printk(KERN_WARNING
+	       "MTD %s(): 0x%.8lx(0x%.8x): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
+	       __func__, adr, ones,
+	       prev_oldstatus, prev_status,
+	       oldstatus, status);
+
+ erase_failed:
+	ret = -EIO;
+	/* reset on all failures. */
+	cfi_write( map, CMD(0xF0), chip->start );
+	/* FIXME - should have reset delay before continuing */
+
+ erase_done:
+	DISABLE_VPP(map);
+	chip->state = FL_READY;
+	wake_up(&chip->wq);
+	cfi_spin_unlock(chip->mutex);
+	return ret;
+}
+
+
 static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
 {
-	unsigned int status;
+	unsigned int oldstatus, status, prev_oldstatus, prev_status;
+	unsigned int dq6;
 	unsigned long timeo = jiffies + HZ;
 	struct cfi_private *cfi = map->fldrv_priv;
-	unsigned int rdy_mask;
 	DECLARE_WAITQUEUE(wait, current);
+	int ret = 0;
+	int ta = 0;
+	cfi_word ones = 0;
 
  retry:
 	cfi_spin_lock(chip->mutex);
@@ -580,28 +1025,46 @@
 	chip->state = FL_ERASING;
 
 	adr += chip->start;
+	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
+	       __func__, adr );
+
 	ENABLE_VPP(map);
 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+
 	cfi_write(map, CMD(0x30), adr);
 	
 	timeo = jiffies + (HZ*20);
 
-	cfi_spin_unlock(chip->mutex);
-	schedule_timeout(HZ);
-	cfi_spin_lock(chip->mutex);
-	
-	rdy_mask = CMD(0x80);
-
-	/* FIXME. Use a timer to check this, and return immediately. */
-	/* Once the state machine's known to be working I'll do that */
+	/* Wait for the end of programing/erasure by using the toggle method.
+	 * As long as there is a programming procedure going on, bit 6
+	 * is toggling it's state with each consecutive read.
+	 * The toggling stops as soon as the procedure is completed.
+	 *
+	 * If the process has gone on for too long on the chip bit 5 gets.
+	 * After bit5 is set you can kill the operation by sending a reset
+	 * command to the chip.
+	 */
+	/* see comments in do_write_oneword */
+	dq6 = CMD(1<<6);
 
-	while ( ( (status = cfi_read(map,adr)) & rdy_mask ) != rdy_mask ) {
-		static int z=0;
+	oldstatus = cfi_read(map, adr);
+	status = cfi_read(map, adr);
+	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
+	       __func__, oldstatus, status );
+
+	while( ( ( status ^ oldstatus ) & dq6 )
+	       && ! ( ta = time_after(jiffies, timeo) ) ) {
+		int wait_reps;
 
+		/* an initial short sleep */
+		cfi_spin_unlock(chip->mutex);
+		schedule_timeout(HZ/100);
+		cfi_spin_lock(chip->mutex);
+		
 		if (chip->state != FL_ERASING) {
 			/* Someone's suspended the erase. Sleep */
 			set_current_state(TASK_UNINTERRUPTIBLE);
@@ -621,34 +1084,90 @@
 			continue;
 		}
 
-		/* OK Still waiting */
-		if (time_after(jiffies, timeo)) {
-			chip->state = FL_READY;
+		/* Busy wait for 1/10 of a milisecond */
+		for(wait_reps = 0;
+		    (wait_reps < 100)
+			    && ( ( status ^ oldstatus ) & dq6 );
+		    wait_reps++) {
+			
+			/* Latency issues. Drop the lock, wait a while and retry */
 			cfi_spin_unlock(chip->mutex);
-			printk(KERN_WARNING "waiting for erase to complete timed out.");
-			DISABLE_VPP(map);
-			return -EIO;
-		}
+			
+			cfi_udelay(1);
 		
-		/* Latency issues. Drop the lock, wait a while and retry */
-		cfi_spin_unlock(chip->mutex);
+			cfi_spin_lock(chip->mutex);
+			oldstatus = cfi_read(map, adr);
+			status = cfi_read(map, adr);
+			DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
+			       __func__, oldstatus, status );
+		}
+		oldstatus = cfi_read(map, adr);
+		status = cfi_read(map, adr);
+		DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
+		       __func__, oldstatus, status );
+	}
 
-		z++;
-		if ( 0 && !(z % 100 )) 
-			printk(KERN_WARNING "chip not ready yet after erase. looping\n");
+	prev_oldstatus = oldstatus;
+	prev_status = status;
+	oldstatus = cfi_read(map, adr);
+	status = cfi_read(map, adr);
+	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
+	       __func__, oldstatus, status );
+
+	if ( cfi_buswidth_is_1() ) {
+		ones =  (__u8)~0;
+	} else if ( cfi_buswidth_is_2() ) {
+		ones = (__u16)~0;
+	} else if ( cfi_buswidth_is_4() ) {
+		ones = (__u32)~0;
+	} else {
+		printk(KERN_WARNING "Unsupported buswidth\n");
+		goto erase_failed;
+	}
 
-		cfi_udelay(1);
-		
-		cfi_spin_lock(chip->mutex);
-		continue;
+	if ( oldstatus == ones && status == ones ) {
+		/* success - do nothing */
+		goto erase_done;
 	}
-	
-	/* Done and happy. */
+
+	if ( ta ) {
+		int dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
+		if ( status & dq5mask ) {
+			/* dq5 asserted - decode interleave chips */
+			printk( KERN_WARNING
+				"MTD %s(): FLASH internal timeout: 0x%.8x\n",
+				__func__,
+				status & dq5mask );
+		} else {
+			printk( KERN_WARNING
+				"MTD %s(): Software timed out during write.\n",
+				__func__ );
+		}
+		goto erase_failed;
+	}
+
+	printk(KERN_WARNING
+	       "MTD %s(): Wacky!  Unable to decode failure status\n",
+	       __func__ );
+
+	printk(KERN_WARNING
+	       "MTD %s(): 0x%.8lx(0x%.8x): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
+	       __func__, adr, ones,
+	       prev_oldstatus, prev_status,
+	       oldstatus, status);
+
+ erase_failed:
+	ret = -EIO;
+	/* reset on all failures. */
+	cfi_write( map, CMD(0xF0), chip->start );
+	/* FIXME - should have reset delay before continuing */
+
+ erase_done:
 	DISABLE_VPP(map);
 	chip->state = FL_READY;
 	wake_up(&chip->wq);
 	cfi_spin_unlock(chip->mutex);
-	return 0;
+	return ret;
 }
 
 static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
@@ -788,6 +1307,29 @@
 	return 0;
 }
 
+static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int ret = 0;
+
+	if (instr->addr != 0)
+		return -EINVAL;
+
+	if (instr->len != mtd->size)
+		return -EINVAL;
+
+	ret = do_erase_chip(map, &cfi->chips[0]);
+	if (ret)
+		return ret;
+
+	instr->state = MTD_ERASE_DONE;
+	if (instr->callback)
+		instr->callback(instr);
+	
+	return 0;
+}
+
 static void cfi_amdstd_sync (struct mtd_info *mtd)
 {
 	struct map_info *map = mtd->priv;
@@ -855,7 +1397,6 @@
 	int i;
 	struct flchip *chip;
 	int ret = 0;
-//printk("suspend\n");
 
 	for (i=0; !ret && i<cfi->numchips; i++) {
 		chip = &cfi->chips[i];
@@ -908,7 +1449,6 @@
 	struct cfi_private *cfi = map->fldrv_priv;
 	int i;
 	struct flchip *chip;
-//printk("resume\n");
 
 	for (i=0; i<cfi->numchips; i++) {
 	
@@ -933,7 +1473,9 @@
 	struct map_info *map = mtd->priv;
 	struct cfi_private *cfi = map->fldrv_priv;
 	kfree(cfi->cmdset_priv);
+	kfree(cfi->cfiq);
 	kfree(cfi);
+	kfree(mtd->eraseregions);
 }
 
 static char im_name[]="cfi_cmdset_0002";
@@ -955,3 +1497,4 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al.");
 MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
+
diff -Nru a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/chips/cfi_cmdset_0020.c	Wed May 28 08:01:08 2003
@@ -0,0 +1,1451 @@
+/*
+ * Common Flash Interface support:
+ *   ST Advanced Architecture Command Set (ID 0x0020)
+ *
+ * (C) 2000 Red Hat. GPL'd
+ *
+ * 
+ * 10/10/2000	Nicolas Pitre <nico@cam.org>
+ * 	- completely revamped method functions so they are aware and
+ * 	  independent of the flash geometry (buswidth, interleave, etc.)
+ * 	- scalability vs code size is completely set at compile-time
+ * 	  (see include/linux/mtd/cfi.h for selection)
+ *	- optimized write buffer method
+ * 06/21/2002	Joern Engel <joern@wh.fh-wedel.de> and others
+ *	- modified Intel Command Set 0x0001 to support ST Advanced Architecture
+ *	  (command set 0x0020)
+ *	- added a writev function
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/compatmac.h>
+
+
+static int cfi_staa_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_staa_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static int cfi_staa_writev(struct mtd_info *mtd, const struct iovec *vecs,
+		unsigned long count, loff_t to, size_t *retlen);
+static int cfi_staa_erase_varsize(struct mtd_info *, struct erase_info *);
+static void cfi_staa_sync (struct mtd_info *);
+static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
+static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
+static int cfi_staa_suspend (struct mtd_info *);
+static void cfi_staa_resume (struct mtd_info *);
+
+static void cfi_staa_destroy(struct mtd_info *);
+
+struct mtd_info *cfi_cmdset_0020(struct map_info *, int);
+
+static struct mtd_info *cfi_staa_setup (struct map_info *);
+
+static struct mtd_chip_driver cfi_staa_chipdrv = {
+	.probe		= NULL, /* Not usable directly */
+	.destroy	= cfi_staa_destroy,
+	.name		= "cfi_cmdset_0020",
+	.module		= THIS_MODULE
+};
+
+/* #define DEBUG_LOCK_BITS */
+//#define DEBUG_CFI_FEATURES
+
+#ifdef DEBUG_CFI_FEATURES
+static void cfi_tell_features(struct cfi_pri_intelext *extp)
+{
+        int i;
+        printk("  Feature/Command Support: %4.4X\n", extp->FeatureSupport);
+	printk("     - Chip Erase:         %s\n", extp->FeatureSupport&1?"supported":"unsupported");
+	printk("     - Suspend Erase:      %s\n", extp->FeatureSupport&2?"supported":"unsupported");
+	printk("     - Suspend Program:    %s\n", extp->FeatureSupport&4?"supported":"unsupported");
+	printk("     - Legacy Lock/Unlock: %s\n", extp->FeatureSupport&8?"supported":"unsupported");
+	printk("     - Queued Erase:       %s\n", extp->FeatureSupport&16?"supported":"unsupported");
+	printk("     - Instant block lock: %s\n", extp->FeatureSupport&32?"supported":"unsupported");
+	printk("     - Protection Bits:    %s\n", extp->FeatureSupport&64?"supported":"unsupported");
+	printk("     - Page-mode read:     %s\n", extp->FeatureSupport&128?"supported":"unsupported");
+	printk("     - Synchronous read:   %s\n", extp->FeatureSupport&256?"supported":"unsupported");
+	for (i=9; i<32; i++) {
+		if (extp->FeatureSupport & (1<<i)) 
+			printk("     - Unknown Bit %X:      supported\n", i);
+	}
+	
+	printk("  Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport);
+	printk("     - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported");
+	for (i=1; i<8; i++) {
+		if (extp->SuspendCmdSupport & (1<<i))
+			printk("     - Unknown Bit %X:               supported\n", i);
+	}
+	
+	printk("  Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask);
+	printk("     - Lock Bit Active:      %s\n", extp->BlkStatusRegMask&1?"yes":"no");
+	printk("     - Valid Bit Active:     %s\n", extp->BlkStatusRegMask&2?"yes":"no");
+	for (i=2; i<16; i++) {
+		if (extp->BlkStatusRegMask & (1<<i))
+			printk("     - Unknown Bit %X Active: yes\n",i);
+	}
+	
+	printk("  Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", 
+	       extp->VccOptimal >> 8, extp->VccOptimal & 0xf);
+	if (extp->VppOptimal)
+		printk("  Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", 
+		       extp->VppOptimal >> 8, extp->VppOptimal & 0xf);
+}
+#endif
+
+/* This routine is made available to other mtd code via
+ * inter_module_register.  It must only be accessed through
+ * inter_module_get which will bump the use count of this module.  The
+ * addresses passed back in cfi are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
+struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	__u32 base = cfi->chips[0].start;
+
+	if (cfi->cfi_mode) {
+		/* 
+		 * It's a real CFI chip, not one for which the probe
+		 * routine faked a CFI structure. So we read the feature
+		 * table from it.
+		 */
+		__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
+		struct cfi_pri_intelext *extp;
+		int ofs_factor = cfi->interleave * cfi->device_type;
+
+                printk(" ST Microelectronics Extended Query Table at 0x%4.4X\n", adr);
+		if (!adr)
+			return NULL;
+
+		/* Switch it into Query Mode */
+		cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
+
+		extp = kmalloc(sizeof(*extp), GFP_KERNEL);
+		if (!extp) {
+			printk(KERN_ERR "Failed to allocate memory\n");
+			return NULL;
+		}
+		
+		/* Read in the Extended Query Table */
+		for (i=0; i<sizeof(*extp); i++) {
+			((unsigned char *)extp)[i] = 
+				cfi_read_query(map, (base+((adr+i)*ofs_factor)));
+		}
+		
+		if (extp->MajorVersion != '1' || 
+                    (extp->MinorVersion < '0' || extp->MinorVersion > '2')) {
+                    printk(KERN_WARNING "  Unknown staa Extended Query "
+                           "version %c.%c.\n",  extp->MajorVersion,
+                           extp->MinorVersion);
+                    kfree(extp);
+                    return NULL;
+		}
+		
+		/* Do some byteswapping if necessary */
+		extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport);
+		extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask);
+		
+#ifdef DEBUG_CFI_FEATURES
+		/* Tell the user about it in lots of lovely detail */
+		cfi_tell_features(extp);
+#endif	
+
+		/* Install our own private info structure */
+		cfi->cmdset_priv = extp;
+	}	
+
+	for (i=0; i< cfi->numchips; i++) {
+		cfi->chips[i].word_write_time = 128;
+		cfi->chips[i].buffer_write_time = 128;
+		cfi->chips[i].erase_time = 1024;
+	}		
+
+	/* Make sure it's in read mode */
+	cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
+	return cfi_staa_setup(map);
+}
+
+static struct mtd_info *cfi_staa_setup(struct map_info *map)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct mtd_info *mtd;
+	unsigned long offset = 0;
+	int i,j;
+	unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
+
+	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+	//printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips);
+
+	if (!mtd) {
+		printk(KERN_ERR "Failed to allocate memory for MTD device\n");
+		kfree(cfi->cmdset_priv);
+		return NULL;
+	}
+
+	memset(mtd, 0, sizeof(*mtd));
+	mtd->priv = map;
+	mtd->type = MTD_NORFLASH;
+	mtd->size = devsize * cfi->numchips;
+
+	mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
+	mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) 
+			* mtd->numeraseregions, GFP_KERNEL);
+	if (!mtd->eraseregions) { 
+		printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
+		kfree(cfi->cmdset_priv);
+		return NULL;
+	}
+	
+	for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
+		unsigned long ernum, ersize;
+		ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
+		ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
+
+		if (mtd->erasesize < ersize) {
+			mtd->erasesize = ersize;
+		}
+		for (j=0; j<cfi->numchips; j++) {
+			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
+			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
+			mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
+		}
+		offset += (ersize * ernum);
+		}
+
+		if (offset != devsize) {
+			/* Argh */
+			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);
+			return NULL;
+		}
+
+		for (i=0; i<mtd->numeraseregions;i++){
+			printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",
+			       i,mtd->eraseregions[i].offset,
+			       mtd->eraseregions[i].erasesize,
+			       mtd->eraseregions[i].numblocks);
+		}
+
+	/* Also select the correct geometry setup too */ 
+	mtd->erase = cfi_staa_erase_varsize;
+	mtd->read = cfi_staa_read;
+        mtd->write = cfi_staa_write_buffers;
+	mtd->writev = cfi_staa_writev;
+	mtd->sync = cfi_staa_sync;
+	mtd->lock = cfi_staa_lock;
+	mtd->unlock = cfi_staa_unlock;
+	mtd->suspend = cfi_staa_suspend;
+	mtd->resume = cfi_staa_resume;
+	mtd->flags = MTD_CAP_NORFLASH;
+	mtd->flags |= MTD_ECC; /* FIXME: Not all STMicro flashes have this */
+	mtd->eccsize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
+	map->fldrv = &cfi_staa_chipdrv;
+	__module_get(THIS_MODULE);
+	mtd->name = map->name;
+	return mtd;
+}
+
+
+static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
+{
+	__u32 status, status_OK;
+	unsigned long timeo;
+	DECLARE_WAITQUEUE(wait, current);
+	int suspended = 0;
+	unsigned long cmd_addr;
+	struct cfi_private *cfi = map->fldrv_priv;
+
+	adr += chip->start;
+
+	/* Ensure cmd read/writes are aligned. */ 
+	cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); 
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+ retry:
+	spin_lock_bh(chip->mutex);
+
+	/* Check that the chip's ready to talk to us.
+	 * If it's in FL_ERASING state, suspend it and make it talk now.
+	 */
+	switch (chip->state) {
+	case FL_ERASING:
+		if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)
+			goto sleep; /* We don't support erase suspend */
+		
+		cfi_write (map, CMD(0xb0), cmd_addr);
+		/* If the flash has finished erasing, then 'erase suspend'
+		 * appears to make some (28F320) flash devices switch to
+		 * 'read' mode.  Make sure that we switch to 'read status'
+		 * mode so we get the right data. --rmk
+		 */
+		cfi_write(map, CMD(0x70), cmd_addr);
+		chip->oldstate = FL_ERASING;
+		chip->state = FL_ERASE_SUSPENDING;
+		//		printk("Erase suspending at 0x%lx\n", cmd_addr);
+		for (;;) {
+			status = cfi_read(map, cmd_addr);
+			if ((status & status_OK) == status_OK)
+				break;
+			
+			if (time_after(jiffies, timeo)) {
+				/* Urgh */
+				cfi_write(map, CMD(0xd0), cmd_addr);
+				/* make sure we're in 'read status' mode */
+				cfi_write(map, CMD(0x70), cmd_addr);
+				chip->state = FL_ERASING;
+				spin_unlock_bh(chip->mutex);
+				printk(KERN_ERR "Chip not ready after erase "
+				       "suspended: status = 0x%x\n", status);
+				return -EIO;
+			}
+			
+			spin_unlock_bh(chip->mutex);
+			cfi_udelay(1);
+			spin_lock_bh(chip->mutex);
+		}
+		
+		suspended = 1;
+		cfi_write(map, CMD(0xff), cmd_addr);
+		chip->state = FL_READY;
+		break;
+	
+#if 0
+	case FL_WRITING:
+		/* Not quite yet */
+#endif
+
+	case FL_READY:
+		break;
+
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+		cfi_write(map, CMD(0x70), cmd_addr);
+		chip->state = FL_STATUS;
+
+	case FL_STATUS:
+		status = cfi_read(map, cmd_addr);
+		if ((status & status_OK) == status_OK) {
+			cfi_write(map, CMD(0xff), cmd_addr);
+			chip->state = FL_READY;
+			break;
+		}
+		
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %x\n", status);
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+	sleep:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	map_copy_from(map, buf, adr, len);
+
+	if (suspended) {
+		chip->state = chip->oldstate;
+		/* What if one interleaved chip has finished and the 
+		   other hasn't? The old code would leave the finished
+		   one in READY mode. That's bad, and caused -EROFS 
+		   errors to be returned from do_erase_oneblock because
+		   that's the only bit it checked for at the time.
+		   As the state machine appears to explicitly allow 
+		   sending the 0x70 (Read Status) command to an erasing
+		   chip and expecting it to be ignored, that's what we 
+		   do. */
+		cfi_write(map, CMD(0xd0), cmd_addr);
+		cfi_write(map, CMD(0x70), cmd_addr);		
+	}
+
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return 0;
+}
+
+static int cfi_staa_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long ofs;
+	int chipnum;
+	int ret = 0;
+
+	/* ofs: offset within the first chip that the first read should start */
+	chipnum = (from >> cfi->chipshift);
+	ofs = from - (chipnum <<  cfi->chipshift);
+
+	*retlen = 0;
+
+	while (len) {
+		unsigned long thislen;
+
+		if (chipnum >= cfi->numchips)
+			break;
+
+		if ((len + ofs -1) >> cfi->chipshift)
+			thislen = (1<<cfi->chipshift) - ofs;
+		else
+			thislen = len;
+
+		ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
+		if (ret)
+			break;
+
+		*retlen += thislen;
+		len -= thislen;
+		buf += thislen;
+		
+		ofs = 0;
+		chipnum++;
+	}
+	return ret;
+}
+
+static inline int do_write_buffer(struct map_info *map, struct flchip *chip, 
+				  unsigned long adr, const u_char *buf, int len)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	__u32 status, status_OK;
+	unsigned long cmd_adr, timeo;
+	DECLARE_WAITQUEUE(wait, current);
+	int wbufsize, z;
+        
+        /* M58LW064A requires bus alignment for buffer wriets -- saw */
+        if (adr & (CFIDEV_BUSWIDTH-1))
+            return -EINVAL;
+
+        wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
+        adr += chip->start;
+	cmd_adr = adr & ~(wbufsize-1);
+	
+	/* Let's determine this according to the interleave only once */
+        status_OK = CMD(0x80);
+        
+	timeo = jiffies + HZ;
+ retry:
+
+#ifdef DEBUG_CFI_FEATURES
+       printk("%s: chip->state[%d]\n", __FUNCTION__, chip->state);
+#endif
+	spin_lock_bh(chip->mutex);
+ 
+	/* Check that the chip's ready to talk to us.
+	 * Later, we can actually think about interrupting it
+	 * if it's in FL_ERASING state.
+	 * Not just yet, though.
+	 */
+	switch (chip->state) {
+	case FL_READY:
+		break;
+		
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+		cfi_write(map, CMD(0x70), cmd_adr);
+                chip->state = FL_STATUS;
+#ifdef DEBUG_CFI_FEATURES
+        printk("%s: 1 status[%x]\n", __FUNCTION__, cfi_read(map, cmd_adr));
+#endif
+
+	case FL_STATUS:
+		status = cfi_read(map, cmd_adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+                        printk(KERN_ERR "waiting for chip to be ready timed out in buffer write Xstatus = %x, status = %x\n",
+                               status, cfi_read(map, cmd_adr));
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	cfi_write(map, CMD(0xe8), cmd_adr);
+	chip->state = FL_WRITING_TO_BUFFER;
+
+	z = 0;
+	for (;;) {
+		status = cfi_read(map, cmd_adr);
+		if ((status & status_OK) == status_OK)
+			break;
+
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+
+		if (++z > 100) {
+			/* Argh. Not ready for write to buffer */
+			DISABLE_VPP(map);
+                        cfi_write(map, CMD(0x70), cmd_adr);
+			chip->state = FL_STATUS;
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %x\n", status);
+			return -EIO;
+		}
+	}
+
+	/* Write length of data to come */
+	cfi_write(map, CMD(len/CFIDEV_BUSWIDTH-1), cmd_adr );
+        
+	/* Write data */
+	for (z = 0; z < len; z += CFIDEV_BUSWIDTH) {
+		if (cfi_buswidth_is_1()) {
+			map_write8 (map, *((__u8*)buf)++, adr+z);
+		} else if (cfi_buswidth_is_2()) {
+			map_write16 (map, *((__u16*)buf)++, adr+z);
+		} else if (cfi_buswidth_is_4()) {
+			map_write32 (map, *((__u32*)buf)++, adr+z);
+		} else {
+			DISABLE_VPP(map);
+			return -EINVAL;
+		}
+	}
+	/* GO GO GO */
+	cfi_write(map, CMD(0xd0), cmd_adr);
+	chip->state = FL_WRITING;
+
+	spin_unlock_bh(chip->mutex);
+	cfi_udelay(chip->buffer_write_time);
+	spin_lock_bh(chip->mutex);
+
+	timeo = jiffies + (HZ/2);
+	z = 0;
+	for (;;) {
+		if (chip->state != FL_WRITING) {
+			/* Someone's suspended the write. Sleep */
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			add_wait_queue(&chip->wq, &wait);
+			spin_unlock_bh(chip->mutex);
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+			timeo = jiffies + (HZ / 2); /* FIXME */
+			spin_lock_bh(chip->mutex);
+			continue;
+		}
+
+		status = cfi_read(map, cmd_adr);
+		if ((status & status_OK) == status_OK)
+			break;
+
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+                        /* clear status */
+                        cfi_write(map, CMD(0x50), cmd_adr);
+                        /* put back into read status register mode */
+                        cfi_write(map, CMD(0x70), adr);
+			chip->state = FL_STATUS;
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n");
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		z++;
+		spin_lock_bh(chip->mutex);
+	}
+	if (!z) {
+		chip->buffer_write_time--;
+		if (!chip->buffer_write_time)
+			chip->buffer_write_time++;
+	}
+	if (z > 1) 
+		chip->buffer_write_time++;
+        
+	/* Done and happy. */
+	DISABLE_VPP(map);
+	chip->state = FL_STATUS;
+
+        /* check for errors: 'lock bit', 'VPP', 'dead cell'/'unerased cell' or 'incorrect cmd' -- saw */
+        if ((status & CMD(0x02)) || (status & CMD(0x08)) ||
+            (status & CMD(0x10)) || (status & CMD(0x20))) {
+#ifdef DEBUG_CFI_FEATURES
+            printk("%s: 2 status[%x]\n", __FUNCTION__, status);
+#endif
+            /* clear status */
+            cfi_write(map, CMD(0x50), cmd_adr);
+            /* put back into read status register mode */
+            cfi_write(map, CMD(0x70), adr);
+            wake_up(&chip->wq);
+            spin_unlock_bh(chip->mutex);
+            return (status & CMD(0x02)) ? -EROFS : -EIO;
+        }
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+
+        return 0;
+}
+
+static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, 
+				       size_t len, size_t *retlen, const u_char *buf)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
+	int ret = 0;
+	int chipnum;
+	unsigned long ofs;
+
+	*retlen = 0;
+	if (!len)
+		return 0;
+
+	chipnum = to >> cfi->chipshift;
+	ofs = to  - (chipnum << cfi->chipshift);
+
+#ifdef DEBUG_CFI_FEATURES
+        printk("%s: CFIDEV_BUSWIDTH[%x]\n", __FUNCTION__, CFIDEV_BUSWIDTH);
+        printk("%s: chipnum[%x] wbufsize[%x]\n", __FUNCTION__, chipnum, wbufsize);
+        printk("%s: ofs[%x] len[%x]\n", __FUNCTION__, ofs, len);
+#endif
+        
+        /* Write buffer is worth it only if more than one word to write... */
+        while (len > 0) {
+		/* We must not cross write block boundaries */
+		int size = wbufsize - (ofs & (wbufsize-1));
+
+                if (size > len)
+                    size = len;
+
+                ret = do_write_buffer(map, &cfi->chips[chipnum], 
+				      ofs, buf, size);
+		if (ret)
+			return ret;
+
+		ofs += size;
+		buf += size;
+		(*retlen) += size;
+		len -= size;
+
+		if (ofs >> cfi->chipshift) {
+			chipnum ++; 
+			ofs = 0;
+			if (chipnum == cfi->numchips)
+				return 0;
+		}
+	}
+        
+	return 0;
+}
+
+/*
+ * Writev for ECC-Flashes is a little more complicated. We need to maintain
+ * a small buffer for this.
+ * XXX: If the buffer size is not a multiple of 2, this will break
+ */
+#define ECCBUF_SIZE (mtd->eccsize)
+#define ECCBUF_DIV(x) ((x) & ~(ECCBUF_SIZE - 1))
+#define ECCBUF_MOD(x) ((x) &  (ECCBUF_SIZE - 1))
+static int
+cfi_staa_writev(struct mtd_info *mtd, const struct iovec *vecs,
+		unsigned long count, loff_t to, size_t *retlen)
+{
+	unsigned long i;
+	size_t	 totlen = 0, thislen;
+	int	 ret = 0;
+	size_t	 buflen = 0;
+	static char *buffer;
+
+	if (!ECCBUF_SIZE) {
+		/* We should fall back to a general writev implementation.
+		 * Until that is written, just break.
+		 */
+		return -EIO;
+	}
+	buffer = kmalloc(ECCBUF_SIZE, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	for (i=0; i<count; i++) {
+		size_t elem_len = vecs[i].iov_len;
+		void *elem_base = vecs[i].iov_base;
+		if (!elem_len) /* FIXME: Might be unnecessary. Check that */
+			continue;
+		if (buflen) { /* cut off head */
+			if (buflen + elem_len < ECCBUF_SIZE) { /* just accumulate */
+				memcpy(buffer+buflen, elem_base, elem_len);
+				buflen += elem_len;
+				continue;
+			}
+			memcpy(buffer+buflen, elem_base, ECCBUF_SIZE-buflen);
+			ret = mtd->write(mtd, to, ECCBUF_SIZE, &thislen, buffer);
+			totlen += thislen;
+			if (ret || thislen != ECCBUF_SIZE)
+				goto write_error;
+			elem_len -= thislen-buflen;
+			elem_base += thislen-buflen;
+			to += ECCBUF_SIZE;
+		}
+		if (ECCBUF_DIV(elem_len)) { /* write clean aligned data */
+			ret = mtd->write(mtd, to, ECCBUF_DIV(elem_len), &thislen, elem_base);
+			totlen += thislen;
+			if (ret || thislen != ECCBUF_DIV(elem_len))
+				goto write_error;
+			to += thislen;
+		}
+		buflen = ECCBUF_MOD(elem_len); /* cut off tail */
+		if (buflen) {
+			memset(buffer, 0xff, ECCBUF_SIZE);
+			memcpy(buffer, elem_base + thislen, buflen);
+		}
+	}
+	if (buflen) { /* flush last page, even if not full */
+		/* This is sometimes intended behaviour, really */
+		ret = mtd->write(mtd, to, buflen, &thislen, buffer);
+		totlen += thislen;
+		if (ret || thislen != ECCBUF_SIZE)
+			goto write_error;
+	}
+write_error:
+	if (retlen)
+		*retlen = totlen;
+	return ret;
+}
+
+
+static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	__u32 status, status_OK;
+	unsigned long timeo;
+	int retries = 3;
+	DECLARE_WAITQUEUE(wait, current);
+	int ret = 0;
+
+	adr += chip->start;
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+retry:
+	spin_lock_bh(chip->mutex);
+
+	/* Check that the chip's ready to talk to us. */
+	switch (chip->state) {
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+	case FL_READY:
+		cfi_write(map, CMD(0x70), adr);
+		chip->state = FL_STATUS;
+
+	case FL_STATUS:
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in erase\n");
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	/* Clear the status register first */
+	cfi_write(map, CMD(0x50), adr);
+
+	/* Now erase */
+	cfi_write(map, CMD(0x20), adr);
+	cfi_write(map, CMD(0xD0), adr);
+	chip->state = FL_ERASING;
+	
+	spin_unlock_bh(chip->mutex);
+	schedule_timeout(HZ);
+	spin_lock_bh(chip->mutex);
+
+	/* FIXME. Use a timer to check this, and return immediately. */
+	/* Once the state machine's known to be working I'll do that */
+
+	timeo = jiffies + (HZ*20);
+	for (;;) {
+		if (chip->state != FL_ERASING) {
+			/* Someone's suspended the erase. Sleep */
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			add_wait_queue(&chip->wq, &wait);
+			spin_unlock_bh(chip->mutex);
+			schedule();
+			remove_wait_queue(&chip->wq, &wait);
+			timeo = jiffies + (HZ*20); /* FIXME */
+			spin_lock_bh(chip->mutex);
+			continue;
+		}
+
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			cfi_write(map, CMD(0x70), adr);
+			chip->state = FL_STATUS;
+			printk(KERN_ERR "waiting for erase to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+	}
+	
+	DISABLE_VPP(map);
+	ret = 0;
+
+	/* We've broken this before. It doesn't hurt to be safe */
+	cfi_write(map, CMD(0x70), adr);
+	chip->state = FL_STATUS;
+	status = cfi_read(map, adr);
+
+	/* check for lock bit */
+	if (status & CMD(0x3a)) {
+		unsigned char chipstatus = status;
+		if (status != CMD(status & 0xff)) {
+			int i;
+			for (i = 1; i<CFIDEV_INTERLEAVE; i++) {
+				      chipstatus |= status >> (cfi->device_type * 8);
+			}
+			printk(KERN_WARNING "Status is not identical for all chips: 0x%x. Merging to give 0x%02x\n", status, chipstatus);
+		}
+		/* Reset the error bits */
+		cfi_write(map, CMD(0x50), adr);
+		cfi_write(map, CMD(0x70), adr);
+		
+		if ((chipstatus & 0x30) == 0x30) {
+			printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", status);
+			ret = -EIO;
+		} else if (chipstatus & 0x02) {
+			/* Protection bit set */
+			ret = -EROFS;
+		} else if (chipstatus & 0x8) {
+			/* Voltage */
+			printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", status);
+			ret = -EIO;
+		} else if (chipstatus & 0x20) {
+			if (retries--) {
+				printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, status);
+				timeo = jiffies + HZ;
+				chip->state = FL_STATUS;
+				spin_unlock_bh(chip->mutex);
+				goto retry;
+			}
+			printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, status);
+			ret = -EIO;
+		}
+	}
+
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return ret;
+}
+
+int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
+{	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long adr, len;
+	int chipnum, ret = 0;
+	int i, first;
+	struct mtd_erase_region_info *regions = mtd->eraseregions;
+
+	if (instr->addr > mtd->size)
+		return -EINVAL;
+
+	if ((instr->len + instr->addr) > mtd->size)
+		return -EINVAL;
+
+	/* Check that both start and end of the requested erase are
+	 * aligned with the erasesize at the appropriate addresses.
+	 */
+
+	i = 0;
+
+	/* Skip all erase regions which are ended before the start of 
+	   the requested erase. Actually, to save on the calculations,
+	   we skip to the first erase region which starts after the
+	   start of the requested erase, and then go back one.
+	*/
+	
+	while (i < mtd->numeraseregions && instr->addr >= regions[i].offset)
+	       i++;
+	i--;
+
+	/* OK, now i is pointing at the erase region in which this 
+	   erase request starts. Check the start of the requested
+	   erase range is aligned with the erase size which is in
+	   effect here.
+	*/
+
+	if (instr->addr & (regions[i].erasesize-1))
+		return -EINVAL;
+
+	/* Remember the erase region we start on */
+	first = i;
+
+	/* Next, check that the end of the requested erase is aligned
+	 * with the erase region at that address.
+	 */
+
+	while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)
+		i++;
+
+	/* As before, drop back one to point at the region in which
+	   the address actually falls
+	*/
+	i--;
+	
+	if ((instr->addr + instr->len) & (regions[i].erasesize-1))
+		return -EINVAL;
+
+	chipnum = instr->addr >> cfi->chipshift;
+	adr = instr->addr - (chipnum << cfi->chipshift);
+	len = instr->len;
+
+	i=first;
+
+	while(len) {
+		ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
+		
+		if (ret)
+			return ret;
+
+		adr += regions[i].erasesize;
+		len -= regions[i].erasesize;
+
+		if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
+			i++;
+
+		if (adr >> cfi->chipshift) {
+			adr = 0;
+			chipnum++;
+			
+			if (chipnum >= cfi->numchips)
+			break;
+		}
+	}
+		
+	instr->state = MTD_ERASE_DONE;
+	if (instr->callback)
+		instr->callback(instr);
+	
+	return 0;
+}
+
+static void cfi_staa_sync (struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+	int ret = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	for (i=0; !ret && i<cfi->numchips; i++) {
+		chip = &cfi->chips[i];
+
+	retry:
+		spin_lock_bh(chip->mutex);
+
+		switch(chip->state) {
+		case FL_READY:
+		case FL_STATUS:
+		case FL_CFI_QUERY:
+		case FL_JEDEC_QUERY:
+			chip->oldstate = chip->state;
+			chip->state = FL_SYNCING;
+			/* No need to wake_up() on this state change - 
+			 * as the whole point is that nobody can do anything
+			 * with the chip now anyway.
+			 */
+		case FL_SYNCING:
+			spin_unlock_bh(chip->mutex);
+			break;
+
+		default:
+			/* Not an idle state */
+			add_wait_queue(&chip->wq, &wait);
+			
+			spin_unlock_bh(chip->mutex);
+			schedule();
+		        remove_wait_queue(&chip->wq, &wait);
+			
+			goto retry;
+		}
+	}
+
+	/* Unlock the chips again */
+
+	for (i--; i >=0; i--) {
+		chip = &cfi->chips[i];
+
+		spin_lock_bh(chip->mutex);
+		
+		if (chip->state == FL_SYNCING) {
+			chip->state = chip->oldstate;
+			wake_up(&chip->wq);
+		}
+		spin_unlock_bh(chip->mutex);
+	}
+}
+
+static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	__u32 status, status_OK;
+	unsigned long timeo = jiffies + HZ;
+	DECLARE_WAITQUEUE(wait, current);
+
+	adr += chip->start;
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+retry:
+	spin_lock_bh(chip->mutex);
+
+	/* Check that the chip's ready to talk to us. */
+	switch (chip->state) {
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+	case FL_READY:
+		cfi_write(map, CMD(0x70), adr);
+		chip->state = FL_STATUS;
+
+	case FL_STATUS:
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK) 
+			break;
+		
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in lock\n");
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	cfi_write(map, CMD(0x60), adr);
+	cfi_write(map, CMD(0x01), adr);
+	chip->state = FL_LOCKING;
+	
+	spin_unlock_bh(chip->mutex);
+	schedule_timeout(HZ);
+	spin_lock_bh(chip->mutex);
+
+	/* FIXME. Use a timer to check this, and return immediately. */
+	/* Once the state machine's known to be working I'll do that */
+
+	timeo = jiffies + (HZ*2);
+	for (;;) {
+
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			cfi_write(map, CMD(0x70), adr);
+			chip->state = FL_STATUS;
+			printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+	}
+	
+	/* Done and happy. */
+	chip->state = FL_STATUS;
+	DISABLE_VPP(map);
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return 0;
+}
+static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long adr;
+	int chipnum, ret = 0;
+#ifdef DEBUG_LOCK_BITS
+	int ofs_factor = cfi->interleave * cfi->device_type;
+#endif
+
+	if (ofs & (mtd->erasesize - 1))
+		return -EINVAL;
+
+	if (len & (mtd->erasesize -1))
+		return -EINVAL;
+
+	if ((len + ofs) > mtd->size)
+		return -EINVAL;
+
+	chipnum = ofs >> cfi->chipshift;
+	adr = ofs - (chipnum << cfi->chipshift);
+
+	while(len) {
+
+#ifdef DEBUG_LOCK_BITS
+		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+		printk("before lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
+		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+#endif
+
+		ret = do_lock_oneblock(map, &cfi->chips[chipnum], adr);
+
+#ifdef DEBUG_LOCK_BITS
+		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+		printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
+		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+#endif	
+		
+		if (ret)
+			return ret;
+
+		adr += mtd->erasesize;
+		len -= mtd->erasesize;
+
+		if (adr >> cfi->chipshift) {
+			adr = 0;
+			chipnum++;
+			
+			if (chipnum >= cfi->numchips)
+			break;
+		}
+	}
+	return 0;
+}
+static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	__u32 status, status_OK;
+	unsigned long timeo = jiffies + HZ;
+	DECLARE_WAITQUEUE(wait, current);
+
+	adr += chip->start;
+
+	/* Let's determine this according to the interleave only once */
+	status_OK = CMD(0x80);
+
+	timeo = jiffies + HZ;
+retry:
+	spin_lock_bh(chip->mutex);
+
+	/* Check that the chip's ready to talk to us. */
+	switch (chip->state) {
+	case FL_CFI_QUERY:
+	case FL_JEDEC_QUERY:
+	case FL_READY:
+		cfi_write(map, CMD(0x70), adr);
+		chip->state = FL_STATUS;
+
+	case FL_STATUS:
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* Urgh. Chip not yet ready to talk to us. */
+		if (time_after(jiffies, timeo)) {
+			spin_unlock_bh(chip->mutex);
+			printk(KERN_ERR "waiting for chip to be ready timed out in unlock\n");
+			return -EIO;
+		}
+
+		/* Latency issues. Drop the lock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		goto retry;
+
+	default:
+		/* Stick ourselves on a wait queue to be woken when
+		   someone changes the status */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&chip->wq, &wait);
+		spin_unlock_bh(chip->mutex);
+		schedule();
+		remove_wait_queue(&chip->wq, &wait);
+		timeo = jiffies + HZ;
+		goto retry;
+	}
+
+	ENABLE_VPP(map);
+	cfi_write(map, CMD(0x60), adr);
+	cfi_write(map, CMD(0xD0), adr);
+	chip->state = FL_UNLOCKING;
+	
+	spin_unlock_bh(chip->mutex);
+	schedule_timeout(HZ);
+	spin_lock_bh(chip->mutex);
+
+	/* FIXME. Use a timer to check this, and return immediately. */
+	/* Once the state machine's known to be working I'll do that */
+
+	timeo = jiffies + (HZ*2);
+	for (;;) {
+
+		status = cfi_read(map, adr);
+		if ((status & status_OK) == status_OK)
+			break;
+		
+		/* OK Still waiting */
+		if (time_after(jiffies, timeo)) {
+			cfi_write(map, CMD(0x70), adr);
+			chip->state = FL_STATUS;
+			printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr));
+			DISABLE_VPP(map);
+			spin_unlock_bh(chip->mutex);
+			return -EIO;
+		}
+		
+		/* Latency issues. Drop the unlock, wait a while and retry */
+		spin_unlock_bh(chip->mutex);
+		cfi_udelay(1);
+		spin_lock_bh(chip->mutex);
+	}
+	
+	/* Done and happy. */
+	chip->state = FL_STATUS;
+	DISABLE_VPP(map);
+	wake_up(&chip->wq);
+	spin_unlock_bh(chip->mutex);
+	return 0;
+}
+static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	unsigned long adr;
+	int chipnum, ret = 0;
+#ifdef DEBUG_LOCK_BITS
+	int ofs_factor = cfi->interleave * cfi->device_type;
+#endif
+
+	chipnum = ofs >> cfi->chipshift;
+	adr = ofs - (chipnum << cfi->chipshift);
+
+#ifdef DEBUG_LOCK_BITS
+	{
+		unsigned long temp_adr = adr;
+		unsigned long temp_len = len;
+                 
+		cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+                while (temp_len) {
+			printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor)));
+			temp_adr += mtd->erasesize;
+			temp_len -= mtd->erasesize;
+		}
+		cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+	}
+#endif
+
+	ret = do_unlock_oneblock(map, &cfi->chips[chipnum], adr);
+
+#ifdef DEBUG_LOCK_BITS
+	cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+	printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
+	cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+#endif
+	
+	return ret;
+}
+
+static int cfi_staa_suspend(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+	int ret = 0;
+
+	for (i=0; !ret && i<cfi->numchips; i++) {
+		chip = &cfi->chips[i];
+
+		spin_lock_bh(chip->mutex);
+
+		switch(chip->state) {
+		case FL_READY:
+		case FL_STATUS:
+		case FL_CFI_QUERY:
+		case FL_JEDEC_QUERY:
+			chip->oldstate = chip->state;
+			chip->state = FL_PM_SUSPENDED;
+			/* No need to wake_up() on this state change - 
+			 * as the whole point is that nobody can do anything
+			 * with the chip now anyway.
+			 */
+		case FL_PM_SUSPENDED:
+			break;
+
+		default:
+			ret = -EAGAIN;
+			break;
+		}
+		spin_unlock_bh(chip->mutex);
+	}
+
+	/* Unlock the chips again */
+
+	if (ret) {
+		for (i--; i >=0; i--) {
+			chip = &cfi->chips[i];
+			
+			spin_lock_bh(chip->mutex);
+			
+			if (chip->state == FL_PM_SUSPENDED) {
+				/* No need to force it into a known state here,
+				   because we're returning failure, and it didn't
+				   get power cycled */
+				chip->state = chip->oldstate;
+				wake_up(&chip->wq);
+			}
+			spin_unlock_bh(chip->mutex);
+		}
+	} 
+	
+	return ret;
+}
+
+static void cfi_staa_resume(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+
+	for (i=0; i<cfi->numchips; i++) {
+	
+		chip = &cfi->chips[i];
+
+		spin_lock_bh(chip->mutex);
+		
+		/* Go to known state. Chip may have been power cycled */
+		if (chip->state == FL_PM_SUSPENDED) {
+			cfi_write(map, CMD(0xFF), 0);
+			chip->state = FL_READY;
+			wake_up(&chip->wq);
+		}
+
+		spin_unlock_bh(chip->mutex);
+	}
+}
+
+static void cfi_staa_destroy(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	kfree(cfi->cmdset_priv);
+	kfree(cfi);
+}
+
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define cfi_staa_init init_module
+#define cfi_staa_exit cleanup_module
+#endif
+
+static char im_name[]="cfi_cmdset_0020";
+
+int __init cfi_staa_init(void)
+{
+	inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0020);
+	return 0;
+}
+
+static void __exit cfi_staa_exit(void)
+{
+	inter_module_unregister(im_name);
+}
+
+module_init(cfi_staa_init);
+module_exit(cfi_staa_exit);
diff -Nru a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c
--- a/drivers/mtd/chips/cfi_probe.c	Wed Feb 26 05:21:54 2003
+++ b/drivers/mtd/chips/cfi_probe.c	Wed May 28 08:01:01 2003
@@ -1,13 +1,14 @@
 /* 
    Common Flash Interface probe code.
    (C) 2000 Red Hat. GPL'd.
-   $Id: cfi_probe.c,v 1.66 2001/10/02 15:05:12 dwmw2 Exp $
+   $Id: cfi_probe.c,v 1.71 2003/05/28 12:51:48 dwmw2 Exp $
 */
 
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 #include <linux/errno.h>
@@ -24,16 +25,13 @@
 static void print_cfi_ident(struct cfi_ident *);
 #endif
 
-int cfi_jedec_setup(struct cfi_private *p_cfi, int index);
-int cfi_jedec_lookup(int index, int mfr_id, int dev_id);
-
 static int cfi_probe_chip(struct map_info *map, __u32 base,
 			  struct flchip *chips, struct cfi_private *cfi);
 static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi);
 
 struct mtd_info *cfi_probe(struct map_info *map);
 
-/* check for QRY, or search for jedec id.
+/* check for QRY.
    in: interleave,type,mode
    ret: table index, <0 for error
  */
@@ -55,6 +53,18 @@
 {
 	int i;
 	
+	if ((base + 0) >= map->size) {
+		printk(KERN_NOTICE
+			"Probe at base[0x00](0x%08lx) past the end of the map(0x%08lx)\n",
+			(unsigned long)base, map->size -1);
+		return 0;
+	}
+	if ((base + 0xff) >= map->size) {
+		printk(KERN_NOTICE
+			"Probe at base[0x55](0x%08lx) past the end of the map(0x%08lx)\n",
+			(unsigned long)base + 0x55, map->size -1);
+		return 0;
+	}
 	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
 	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
 
@@ -139,7 +149,7 @@
 	
 	memset(cfi->cfiq,0,sizeof(struct cfi_ident));	
 	
-	cfi->cfi_mode = 1;
+	cfi->cfi_mode = CFI_MODE_CFI;
 	cfi->fast_prog=1;		/* CFI supports fast programming */
 	
 	/* Read the CFI info structure */
@@ -250,11 +260,11 @@
 	else
 		printk("Full buffer write not supported\n");
 	
-	printk("Typical block erase timeout: %d µs\n", 1<<cfip->BlockEraseTimeoutTyp);
-	printk("Maximum block erase timeout: %d µs\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp));
+	printk("Typical block erase timeout: %d ms\n", 1<<cfip->BlockEraseTimeoutTyp);
+	printk("Maximum block erase timeout: %d ms\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp));
 	if (cfip->ChipEraseTimeoutTyp || cfip->ChipEraseTimeoutMax) {
-		printk("Typical chip erase timeout: %d µs\n", 1<<cfip->ChipEraseTimeoutTyp); 
-		printk("Maximum chip erase timeout: %d µs\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp));
+		printk("Typical chip erase timeout: %d ms\n", 1<<cfip->ChipEraseTimeoutTyp); 
+		printk("Maximum chip erase timeout: %d ms\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp));
 	}
 	else
 		printk("Chip erase not supported\n");
diff -Nru a/drivers/mtd/chips/chipreg.c b/drivers/mtd/chips/chipreg.c
--- a/drivers/mtd/chips/chipreg.c	Sat May 17 12:39:13 2003
+++ b/drivers/mtd/chips/chipreg.c	Wed May 28 08:01:01 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: chipreg.c,v 1.12 2001/10/02 15:29:53 dwmw2 Exp $
+ * $Id: chipreg.c,v 1.15 2003/05/21 15:15:05 dwmw2 Exp $
  *
  * Registration for chip drivers
  *
@@ -7,10 +7,13 @@
 
 #include <linux/kernel.h>
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kmod.h>
 #include <linux/spinlock.h>
-#include <linux/mtd/compatmac.h>
+#include <linux/slab.h>
 #include <linux/mtd/map.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/compatmac.h>
 
 spinlock_t chip_drvs_lock = SPIN_LOCK_UNLOCKED;
 static LIST_HEAD(chip_drvs_list);
@@ -29,7 +32,7 @@
 	spin_unlock(&chip_drvs_lock);
 }
 
-static struct mtd_chip_driver *get_mtd_chip_driver (char *name)
+static struct mtd_chip_driver *get_mtd_chip_driver (const char *name)
 {
 	struct list_head *pos;
 	struct mtd_chip_driver *ret = NULL, *this;
@@ -44,10 +47,8 @@
 			break;
 		}
 	}
-	if (ret && !try_module_get(ret->module)) {
-		/* Eep. Failed. */
+	if (ret && !try_module_get(ret->module))
 		ret = NULL;
-	}
 
 	spin_unlock(&chip_drvs_lock);
 
@@ -57,7 +58,7 @@
 	/* Hide all the horrid details, like some silly person taking
 	   get_module_symbol() away from us, from the caller. */
 
-struct mtd_info *do_map_probe(char *name, struct map_info *map)
+struct mtd_info *do_map_probe(const char *name, struct map_info *map)
 {
 	struct mtd_chip_driver *drv;
 	struct mtd_info *ret;
@@ -84,10 +85,26 @@
 	
 	return NULL;
 }
+/*
+ * Destroy an MTD device which was created for a map device.
+ * Make sure the MTD device is already unregistered before calling this
+ */
+void map_destroy(struct mtd_info *mtd)
+{
+	struct map_info *map = mtd->priv;
+
+	if (map->fldrv->destroy)
+		map->fldrv->destroy(mtd);
+
+	module_put(map->fldrv->module);
+
+	kfree(mtd);
+}
 
 EXPORT_SYMBOL(register_mtd_chip_driver);
 EXPORT_SYMBOL(unregister_mtd_chip_driver);
 EXPORT_SYMBOL(do_map_probe);
+EXPORT_SYMBOL(map_destroy);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
diff -Nru a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c
--- a/drivers/mtd/chips/gen_probe.c	Tue Feb  5 12:20:55 2002
+++ b/drivers/mtd/chips/gen_probe.c	Wed May 28 08:01:01 2003
@@ -2,13 +2,16 @@
  * Routines common to all CFI-type probes.
  * (C) 2001, 2001 Red Hat, Inc.
  * GPL'd
- * $Id: gen_probe.c,v 1.5 2001/10/02 15:05:12 dwmw2 Exp $
+ * $Id: gen_probe.c,v 1.11 2003/05/21 15:15:05 dwmw2 Exp $
  */
 
 #include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/cfi.h>
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/gen_probe.h>
 
 static struct mtd_info *check_cmd_set(struct map_info *, int);
@@ -38,7 +41,7 @@
 	if (mtd)
 		return mtd;
 
-	printk(KERN_WARNING"cfi_probe: No supported Vendor Command Set found\n");
+	printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n");
 	
 	kfree(cfi->cfiq);
 	kfree(cfi);
@@ -57,6 +60,7 @@
 	int i;
 
 	memset(&cfi, 0, sizeof(cfi));
+	memset(&chip[0], 0, sizeof(chip));
 
 	/* Call the probetype-specific code with all permutations of 
 	   interleave and device type, etc. */
@@ -106,6 +110,12 @@
 	 * Now probe for other chips, checking sensibly for aliases while
 	 * we're at it. The new_chip probe above should have let the first
 	 * chip in read mode.
+	 *
+	 * NOTE: Here, we're checking if there is room for another chip
+	 *       the same size within the mapping. Therefore, 
+	 *       base + chipsize <= map->size is the correct thing to do, 
+	 *       because, base + chipsize would be the  _first_ byte of the
+	 *       next chip, not the one we're currently pondering.
 	 */
 
 	for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size;
@@ -224,6 +234,41 @@
 		break;
 #endif /* CFIDEV_BUSWIDTH_4 */
 
+#ifdef CFIDEV_BUSWIDTH_8
+	case CFIDEV_BUSWIDTH_8:
+#if defined(CFIDEV_INTERLEAVE_2) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
+                cfi->interleave = CFIDEV_INTERLEAVE_2;
+
+                cfi->device_type = CFI_DEVICETYPE_X32;
+		if (cp->probe_chip(map, 0, NULL, cfi))
+			return 1;
+#endif /* CFIDEV_INTERLEAVE_2 */
+#ifdef CFIDEV_INTERLEAVE_4
+		cfi->interleave = CFIDEV_INTERLEAVE_4;
+
+#ifdef SOMEONE_ACTUALLY_MAKES_THESE
+		cfi->device_type = CFI_DEVICETYPE_X32;
+		if (cp->probe_chip(map, 0, NULL, cfi))
+			return 1;
+#endif
+		cfi->device_type = CFI_DEVICETYPE_X16;
+		if (cp->probe_chip(map, 0, NULL, cfi))
+			return 1;
+#endif /* CFIDEV_INTERLEAVE_4 */
+#ifdef CFIDEV_INTERLEAVE_8
+		cfi->interleave = CFIDEV_INTERLEAVE_8;
+
+		cfi->device_type = CFI_DEVICETYPE_X16;
+		if (cp->probe_chip(map, 0, NULL, cfi))
+			return 1;
+
+		cfi->device_type = CFI_DEVICETYPE_X8;
+		if (cp->probe_chip(map, 0, NULL, cfi))
+			return 1;
+#endif /* CFIDEV_INTERLEAVE_8 */
+		break;
+#endif /* CFIDEV_BUSWIDTH_8 */
+
 	default:
 		printk(KERN_WARNING "genprobe_new_chip called with unsupported buswidth %d\n", map->buswidth);
 		return 0;
@@ -288,6 +333,10 @@
 #ifdef CONFIG_MTD_CFI_AMDSTD
 	case 0x0002:
 		return cfi_cmdset_0002(map, primary);
+#endif
+#ifdef CONFIG_MTD_CFI_STAA
+        case 0x0020:
+		return cfi_cmdset_0020(map, primary);
 #endif
 	}
 
diff -Nru a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c
--- a/drivers/mtd/chips/jedec.c	Sun May 25 17:00:00 2003
+++ b/drivers/mtd/chips/jedec.c	Thu May 29 03:42:13 2003
@@ -11,10 +11,16 @@
  * not going to guess how to send commands to them, plus I expect they will
  * all speak CFI..
  *
- * $Id: jedec.c,v 1.12 2001/11/06 14:37:35 dwmw2 Exp $
+ * $Id: jedec.c,v 1.19 2003/05/29 09:25:23 dwmw2 Exp $
  */
 
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
 #include <linux/mtd/jedec.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/compatmac.h>
 
 static struct mtd_info *jedec_probe(struct map_info *);
 static int jedec_probe8(struct map_info *map,unsigned long base,
@@ -264,7 +270,7 @@
    MTD->priv = map;
    map->fldrv_priv = priv;
    map->fldrv = &jedec_chipdrv;
-   MOD_INC_USE_COUNT;
+   __module_get(THIS_MODULE);
    return MTD;
 }
 
@@ -386,8 +392,8 @@
 static int jedec_probe8(struct map_info *map,unsigned long base,
 		  struct jedec_private *priv)
 { 
-   #define flread(x) map->read8(map,base+x)
-   #define flwrite(v,x) map->write8(map,v,base+x)
+   #define flread(x) map_read8(map,base+x)
+   #define flwrite(v,x) map_write8(map,v,base+x)
 
    const unsigned long AutoSel1 = 0xAA;
    const unsigned long AutoSel2 = 0x55;
@@ -446,8 +452,8 @@
 static int jedec_probe32(struct map_info *map,unsigned long base,
 		  struct jedec_private *priv)
 {
-   #define flread(x) map->read32(map,base+((x)<<2))
-   #define flwrite(v,x) map->write32(map,v,base+((x)<<2))
+   #define flread(x) map_read32(map,base+((x)<<2))
+   #define flwrite(v,x) map_write32(map,v,base+((x)<<2))
 
    const unsigned long AutoSel1 = 0xAAAAAAAA;
    const unsigned long AutoSel2 = 0x55555555;
@@ -500,8 +506,8 @@
       we call this routine with the JEDEC return still enabled, if two or
       more flashes have a truncated address space the probe test will still
       work */
-   if (base + Size+0x555 < map->size &&
-       base + Size+0x555 < (base & (~(my_bank_size-1))) + my_bank_size)
+   if (base + (Size<<2)+0x555 < map->size &&
+       base + (Size<<2)+0x555 < (base & (~(my_bank_size-1))) + my_bank_size)
    {
       if (flread(base+Size) != flread(base+Size + 0x100) ||
 	  flread(base+Size + 1) != flread(base+Size + 0x101))
@@ -525,7 +531,7 @@
 {
    struct map_info *map = (struct map_info *)mtd->priv;
    
-   map->copy_from(map, buf, from, len);
+   map_copy_from(map, buf, from, len);
    *retlen = len;
    return 0;   
 }
@@ -549,7 +555,7 @@
 	 get = priv->bank_fill[0] - offset;
 
       bank /= priv->bank_fill[0];      
-      map->copy_from(map,buf + *retlen,bank*my_bank_size + offset,get);
+      map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get);
       
       len -= get;
       *retlen += get;
@@ -580,8 +586,8 @@
 static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
    // Does IO to the currently selected chip
-   #define flread(x) map->read8(map,chip->base+((x)<<chip->addrshift))
-   #define flwrite(v,x) map->write8(map,v,chip->base+((x)<<chip->addrshift))
+   #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift))
+   #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift))
    
    unsigned long Time = 0;
    unsigned long NoTime = 0;
@@ -686,19 +692,19 @@
   	    or this is not really flash ;> */
 	 switch (map->buswidth) {
 	 case 1:
-	    Last[0] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    Last[1] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    Last[2] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off);
+	    Last[0] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
+	    Last[1] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
+	    Last[2] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
 	    break;
 	 case 2:
-	    Last[0] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    Last[1] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    Last[2] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off);
+	    Last[0] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
+	    Last[1] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
+	    Last[2] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
 	    break;
 	 case 3:
-	    Last[0] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    Last[1] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-	    Last[2] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
+	    Last[0] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
+	    Last[1] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
+	    Last[2] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
 	    break;
 	 }
 	 Count = 3;
@@ -734,13 +740,13 @@
 
 	    switch (map->buswidth) {
 	    case 1:
-	       Last[Count % 4] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off);
+	       Last[Count % 4] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
 	      break;
 	    case 2:
-	       Last[Count % 4] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off);
+	       Last[Count % 4] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
 	      break;
 	    case 4:
-	       Last[Count % 4] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off);
+	       Last[Count % 4] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
 	      break;
 	    }
 	    Count++;
@@ -773,6 +779,7 @@
    }
        	    
    //printk("done\n");
+   instr->state = MTD_ERASE_DONE;
    if (instr->callback)
 	instr->callback(instr);
    return 0;
@@ -790,9 +797,9 @@
 {
    /* Does IO to the currently selected chip. It takes the bank addressing
       base (which is divisible by the chip size) adds the necessary lower bits
-      of addrshift (interleve index) and then adds the control register index. */
-   #define flread(x) map->read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-   #define flwrite(v,x) map->write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
+      of addrshift (interleave index) and then adds the control register index. */
+   #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
+   #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
    
    struct map_info *map = (struct map_info *)mtd->priv;
    struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv;
@@ -828,7 +835,7 @@
       // Loop over this page
       for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++)
       {
-	 unsigned char oldbyte = map->read8(map,base+off);
+	 unsigned char oldbyte = map_read8(map,base+off);
 	 unsigned char Last[4];
 	 unsigned long Count = 0;
 
@@ -843,10 +850,10 @@
 	 flwrite(0xAA,0x555);
 	 flwrite(0x55,0x2AA);
 	 flwrite(0xA0,0x555);
-	 map->write8(map,*buf,base + off);
-	 Last[0] = map->read8(map,base + off);
-	 Last[1] = map->read8(map,base + off);
-	 Last[2] = map->read8(map,base + off);
+	 map_write8(map,*buf,base + off);
+	 Last[0] = map_read8(map,base + off);
+	 Last[1] = map_read8(map,base + off);
+	 Last[2] = map_read8(map,base + off);
 	 
 	 /* Wait for the flash to finish the operation. We store the last 4
 	    status bytes that have been retrieved so we can determine why
@@ -854,7 +861,7 @@
 	    failure */
 	 for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] &&
 	      Count < 10000; Count++)
-	    Last[Count % 4] = map->read8(map,base + off);
+	    Last[Count % 4] = map_read8(map,base + off);
 	 if (Last[(Count - 1) % 4] != *buf)
 	 {
 	    jedec_flash_failed(Last[(Count - 3) % 4]);
diff -Nru a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
--- a/drivers/mtd/chips/jedec_probe.c	Wed Feb 26 05:27:14 2003
+++ b/drivers/mtd/chips/jedec_probe.c	Wed May 28 08:01:01 2003
@@ -1,7 +1,9 @@
 /* 
    Common Flash Interface probe code.
    (C) 2000 Red Hat. GPL'd.
-   $Id: jedec_probe.c,v 1.3 2001/10/02 15:05:12 dwmw2 Exp $
+   $Id: jedec_probe.c,v 1.29 2003/05/28 13:57:46 dwmw2 Exp $
+   See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
+   for the standard this probe goes back to.
 */
 
 #include <linux/config.h>
@@ -14,18 +16,23 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/cfi.h>
 #include <linux/mtd/gen_probe.h>
 
-
 /* Manufacturers */
 #define MANUFACTURER_AMD	0x0001
-#define MANUFACTURER_FUJITSU	0x0004
 #define MANUFACTURER_ATMEL	0x001f
-#define MANUFACTURER_ST		0x0020
+#define MANUFACTURER_FUJITSU	0x0004
+#define MANUFACTURER_INTEL	0x0089
+#define MANUFACTURER_MACRONIX	0x00C2
+#define MANUFACTURER_PMC	0x009D
 #define MANUFACTURER_SST	0x00BF
+#define MANUFACTURER_ST		0x0020
 #define MANUFACTURER_TOSHIBA	0x0098
+#define MANUFACTURER_WINBOND	0x00da
+
 
 /* AMD */
 #define AM29F800BB	0x2258
@@ -34,27 +41,167 @@
 #define AM29LV800BT	0x22DA
 #define AM29LV160DT	0x22C4
 #define AM29LV160DB	0x2249
+#define AM29F017D	0x003D
+#define AM29F016D	0x00AD
+#define AM29F080	0x00D5
+#define AM29F040	0x00A4
+#define AM29LV040B	0x004F
+#define AM29F032B	0x0041
 
 /* Atmel */
-#define AT49BV16X4	0x00c0
-#define AT49BV16X4T	0x00c2
+#define AT49BV512	0x0003
+#define AT29LV512	0x003d
+#define AT49BV16X	0x00C0
+#define AT49BV16XT	0x00C2
+#define AT49BV32X	0x00C8
+#define AT49BV32XT	0x00C9
 
 /* Fujitsu */
+#define MBM29LV650UE	0x22D7
+#define MBM29LV320TE	0x22F6
+#define MBM29LV320BE	0x22F9
 #define MBM29LV160TE	0x22C4
 #define MBM29LV160BE	0x2249
+#define MBM29LV800BA	0x225B
+#define MBM29LV800TA	0x22DA
+
+/* Intel */
+#define I28F004B3T	0x00d4
+#define I28F004B3B	0x00d5
+#define I28F400B3T	0x8894
+#define I28F400B3B	0x8895
+#define I28F008S5	0x00a6
+#define I28F016S5	0x00a0
+#define I28F008SA	0x00a2
+#define I28F008B3T	0x00d2
+#define I28F008B3B	0x00d3
+#define I28F800B3T	0x8892
+#define I28F800B3B	0x8893
+#define I28F016S3	0x00aa
+#define I28F016B3T	0x00d0
+#define I28F016B3B	0x00d1
+#define I28F160B3T	0x8890
+#define I28F160B3B	0x8891
+#define I28F320B3T	0x8896
+#define I28F320B3B	0x8897
+#define I28F640B3T	0x8898
+#define I28F640B3B	0x8899
+#define I82802AB	0x00ad
+#define I82802AC	0x00ac
+
+/* Macronix */
+#define MX29LV160T	0x22C4
+#define MX29LV160B	0x2249
+#define MX29F016	0x00AD
+#define MX29F004T	0x0045
+#define MX29F004B	0x0046
+
+/* PMC */
+#define PM49FL002	0x006D
+#define PM49FL004	0x006E
+#define PM49FL008	0x006A
 
 /* ST - www.st.com */
-#define M29W800T	0x00D7
+#define M29W800DT	0x00D7
+#define M29W800DB	0x005B
 #define M29W160DT	0x22C4
 #define M29W160DB	0x2249
+#define M29W040B	0x00E3
 
 /* SST */
+#define SST29EE512	0x005d
+#define SST29LE512	0x003d
 #define SST39LF800	0x2781
 #define SST39LF160	0x2782
+#define SST39LF512	0x00D4
+#define SST39LF010	0x00D5
+#define SST39LF020	0x00D6
+#define SST39LF040	0x00D7
+#define SST39SF010A	0x00B5
+#define SST39SF020A	0x00B6
+#define SST49LF030A	0x001C
+#define SST49LF040A	0x0051
+#define SST49LF080A	0x005B
 
 /* Toshiba */
 #define TC58FVT160	0x00C2
 #define TC58FVB160	0x0043
+#define TC58FVT321	0x009A
+#define TC58FVB321	0x009C
+#define TC58FVT641	0x0093
+#define TC58FVB641	0x0095
+
+/* Winbond */
+#define W49V002A	0x00b0
+
+
+/*
+ * Unlock address sets for AMD command sets.
+ * Intel command sets use the MTD_UADDR_UNNECESSARY.
+ * Each identifier, except MTD_UADDR_UNNECESSARY, and
+ * MTD_UADDR_NO_SUPPORT must be defined below in unlock_addrs[].
+ * MTD_UADDR_NOT_SUPPORTED must be 0 so that structure
+ * initialization need not require initializing all of the
+ * unlock addresses for all bit widths.
+ */
+enum uaddr {
+	MTD_UADDR_NOT_SUPPORTED = 0,	/* data width not supported */
+	MTD_UADDR_0x0555_0x02AA,
+	MTD_UADDR_0x0555_0x0AAA,
+	MTD_UADDR_0x5555_0x2AAA,
+	MTD_UADDR_0x0AAA_0x0555,
+	MTD_UADDR_DONT_CARE,		/* Requires an arbitrary address */
+	MTD_UADDR_UNNECESSARY,		/* Does not require any address */
+};
+
+
+struct unlock_addr {
+	int addr1;
+	int addr2;
+};
+
+
+/*
+ * I don't like the fact that the first entry in unlock_addrs[]
+ * exists, but is for MTD_UADDR_NOT_SUPPORTED - and, therefore,
+ * should not be used.  The  problem is that structures with
+ * initializers have extra fields initialized to 0.  It is _very_
+ * desireable to have the unlock address entries for unsupported
+ * data widths automatically initialized - that means that
+ * MTD_UADDR_NOT_SUPPORTED must be 0 and the first entry here
+ * must go unused.
+ */
+static const struct unlock_addr  unlock_addrs[] = {
+	[MTD_UADDR_NOT_SUPPORTED] = {
+		.addr1 = 0xffff,
+		.addr2 = 0xffff
+	},
+
+	[MTD_UADDR_0x0555_0x02AA] = {
+		.addr1 = 0x0555,
+		.addr2 = 0x02aa
+	},
+
+	[MTD_UADDR_0x0555_0x0AAA] = {
+		.addr1 = 0x0555,
+		.addr2 = 0x0aaa
+	},
+
+	[MTD_UADDR_0x5555_0x2AAA] = {
+		.addr1 = 0x5555,
+		.addr2 = 0x2aaa
+	},
+
+	[MTD_UADDR_0x0AAA_0x0555] = {
+		.addr1 = 0x0AAA,
+		.addr2 = 0x0555
+	},
+
+	[MTD_UADDR_DONT_CARE] = {
+		.addr1 = 0x0000,      /* Doesn't matter which address */
+		.addr2 = 0x0000       /* is used - must be last entry */
+	}
+};
 
 
 struct amd_flash_info {
@@ -64,190 +211,1137 @@
 	const int DevSize;
 	const int InterfaceDesc;
 	const int NumEraseRegions;
+	const int CmdSet;
+	const __u8 uaddr[3];		/* unlock addrs for 8, 16, 32 modes */
 	const ulong regions[4];
 };
 
 #define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
 
-#define SIZE_1MiB 20
-#define SIZE_2MiB 21
-#define SIZE_4MiB 22
+#define SIZE_64KiB  16
+#define SIZE_128KiB 17
+#define SIZE_256KiB 18
+#define SIZE_512KiB 19
+#define SIZE_1MiB   20
+#define SIZE_2MiB   21
+#define SIZE_4MiB   22
+#define SIZE_8MiB   23
+
 
+/*
+ * Please keep this list ordered by manufacturer!
+ * Fortunately, the list isn't searched often and so a
+ * slow, linear search isn't so bad.
+ */
 static const struct amd_flash_info jedec_table[] = {
 	{
-		.mfr_id = MANUFACTURER_AMD,
-		.dev_id = AM29LV160DT,
-		.name = "AMD AM29LV160DT",
-		.DevSize = SIZE_2MiB,
-		.NumEraseRegions = 4,
-		.regions = {ERASEINFO(0x10000,31),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x04000,1)
-		}
-	}, {
-		.mfr_id = MANUFACTURER_AMD,
-		.dev_id = AM29LV160DB,
-		.name = "AMD AM29LV160DB",
-		.DevSize = SIZE_2MiB,
-		.NumEraseRegions = 4,
-		.regions = {ERASEINFO(0x04000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x10000,31)
-		}
-	}, {
-		.mfr_id = MANUFACTURER_TOSHIBA,
-		.dev_id = TC58FVT160,
-		.name = "Toshiba TC58FVT160",
-		.DevSize = SIZE_2MiB,
-		.NumEraseRegions = 4,
-		.regions = {ERASEINFO(0x10000,31),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x04000,1)
-		}
-	}, {
-		.mfr_id = MANUFACTURER_FUJITSU,
-		.dev_id = MBM29LV160TE,
-		.name = "Fujitsu MBM29LV160TE",
-		.DevSize = SIZE_2MiB,
-		.NumEraseRegions = 4,
-		.regions = {ERASEINFO(0x10000,31),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x04000,1)
-		}
-	}, {
-		.mfr_id = MANUFACTURER_TOSHIBA,
-		.dev_id = TC58FVB160,
-		.name = "Toshiba TC58FVB160",
-		.DevSize = SIZE_2MiB,
-		.NumEraseRegions = 4,
-		.regions = {ERASEINFO(0x04000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x10000,31)
-		}
-	}, {
-		.mfr_id = MANUFACTURER_FUJITSU,
-		.dev_id = MBM29LV160BE,
-		.name = "Fujitsu MBM29LV160BE",
-		.DevSize = SIZE_2MiB,
-		.NumEraseRegions = 4,
-		.regions = {ERASEINFO(0x04000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x10000,31)
-		}
-	}, {
-		.mfr_id = MANUFACTURER_AMD,
-		.dev_id = AM29LV800BB,
-		.name = "AMD AM29LV800BB",
-		.DevSize = SIZE_1MiB,
-		.NumEraseRegions = 4,
-		.regions = {ERASEINFO(0x04000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x10000,15),
-		}
-	}, {
-		.mfr_id = MANUFACTURER_AMD,
-		.dev_id = AM29F800BB,
-		.name = "AMD AM29F800BB",
-		.DevSize = SIZE_1MiB,
-		.NumEraseRegions = 4,
-		.regions = {ERASEINFO(0x04000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x10000,15),
-		}
-	}, {
-		.mfr_id = MANUFACTURER_AMD,
-		.dev_id = AM29LV800BT,
-		.name = "AMD AM29LV800BT",
-		.DevSize = SIZE_1MiB,
-		.NumEraseRegions = 4,
-		.regions = {ERASEINFO(0x10000,15),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x04000,1)
-		}
-	}, {
-		.mfr_id = MANUFACTURER_AMD,
-		.dev_id = AM29F800BT,
-		.name = "AMD AM29F800BT",
-		.DevSize = SIZE_1MiB,
-		.NumEraseRegions = 4,
-		.regions = {ERASEINFO(0x10000,15),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x04000,1)
-		}
-	}, {
-		.mfr_id = MANUFACTURER_AMD,
-		.dev_id = AM29LV800BB,
-		.name = "AMD AM29LV800BB",
-		.DevSize = SIZE_1MiB,
-		.NumEraseRegions = 4,
-		.regions = {ERASEINFO(0x10000,15),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x04000,1)
-		}
-	}, {
-		.mfr_id = MANUFACTURER_ST,
-		.dev_id = M29W800T,
-		.name = "ST M29W800T",
-		.DevSize = SIZE_1MiB,
-		.NumEraseRegions = 4,
-		.regions = {ERASEINFO(0x10000,15),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x04000,1)
-		}
-	}, {
-		.mfr_id = MANUFACTURER_ST,
-		.dev_id = M29W160DT,
-		.name = "ST M29W160DT",
-		.DevSize = SIZE_2MiB,
-		.NumEraseRegions = 4,
-		.regions = {ERASEINFO(0x10000,31),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x04000,1)
-		}
-	}, {
-		.mfr_id = MANUFACTURER_ST,
-		.dev_id = M29W160DB,
-		.name = "ST M29W160DB",
-		.DevSize = SIZE_2MiB,
-		.NumEraseRegions = 4,
-		.regions = {ERASEINFO(0x04000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x10000,31)
-		}
-	}, {
-		.mfr_id = MANUFACTURER_ATMEL,
-		.dev_id = AT49BV16X4,
-		.name = "Atmel AT49BV16X4",
-		.DevSize = SIZE_2MiB,
-		.NumEraseRegions = 3,
-		.regions = {ERASEINFO(0x02000,8),
-			  ERASEINFO(0x08000,2),
-			  ERASEINFO(0x10000,30)
-		}
-	}, {
-                .mfr_id = MANUFACTURER_ATMEL,
-                .dev_id = AT49BV16X4T,
-                .name = "Atmel AT49BV16X4T",
-                .DevSize = SIZE_2MiB,
-                .NumEraseRegions = 3,
-                .regions = {ERASEINFO(0x10000,30),
-                          ERASEINFO(0x08000,2),
-			  ERASEINFO(0x02000,8)
-                }
+		.mfr_id		= MANUFACTURER_AMD,
+		.dev_id		= AM29F032B,
+		.name		= "AMD AM29F032B",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+		},
+		.DevSize	= SIZE_4MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000,64)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_AMD,
+		.dev_id		= AM29LV160DT,
+		.name		= "AMD AM29LV160DT",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA   /* x16 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x10000,31),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x04000,1)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_AMD,
+		.dev_id		= AM29LV160DB,
+		.name		= "AMD AM29LV160DB",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA   /* x16 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x04000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x10000,31)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_AMD,
+		.dev_id		= AM29LV800BB,
+		.name		= "AMD AM29LV800BB",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x04000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x10000,15),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_AMD,
+		.dev_id		= AM29F800BB,
+		.name		= "AMD AM29F800BB",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x04000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x10000,15),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_AMD,
+		.dev_id		= AM29LV800BT,
+		.name		= "AMD AM29LV800BT",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x10000,15),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x04000,1)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_AMD,
+		.dev_id		= AM29F800BT,
+		.name		= "AMD AM29F800BT",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x10000,15),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x04000,1)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_AMD,
+		.dev_id		= AM29F017D,
+		.name		= "AMD AM29F017D",
+		.uaddr		= {
+			[0] = MTD_UADDR_DONT_CARE     /* x8 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000,32),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_AMD,
+		.dev_id		= AM29F016D,
+		.name		= "AMD AM29F016D",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000,32),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_AMD,
+		.dev_id		= AM29F080,
+		.name		= "AMD AM29F080",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000,16),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_AMD,
+		.dev_id		= AM29F040,
+		.name		= "AMD AM29F040",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000,8),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_AMD,
+		.dev_id		= AM29LV040B,
+		.name		= "AMD AM29LV040B",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000,8),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_ATMEL,
+		.dev_id		= AT49BV512,
+		.name		= "Atmel AT49BV512",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_64KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000,1)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_ATMEL,
+		.dev_id		= AT29LV512,
+		.name		= "Atmel AT29LV512",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_64KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x80,256),
+			ERASEINFO(0x80,256)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_ATMEL,
+		.dev_id		= AT49BV16X,
+		.name		= "Atmel AT49BV16X",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x0AAA,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x0AAA   /* x16 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x02000,8),
+			ERASEINFO(0x10000,31)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_ATMEL,
+		.dev_id		= AT49BV16XT,
+		.name		= "Atmel AT49BV16XT",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x0AAA,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x0AAA   /* x16 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x10000,31),
+			ERASEINFO(0x02000,8)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_ATMEL,
+		.dev_id		= AT49BV32X,
+		.name		= "Atmel AT49BV32X",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x0AAA,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x0AAA   /* x16 */
+		},
+		.DevSize	= SIZE_4MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x02000,8),
+			ERASEINFO(0x10000,63)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_ATMEL,
+		.dev_id		= AT49BV32XT,
+		.name		= "Atmel AT49BV32XT",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x0AAA,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x0AAA   /* x16 */
+		},
+		.DevSize	= SIZE_4MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x10000,63),
+			ERASEINFO(0x02000,8)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_FUJITSU,
+		.dev_id		= MBM29LV650UE,
+		.name		= "Fujitsu MBM29LV650UE",
+		.uaddr		= {
+			[0] = MTD_UADDR_DONT_CARE     /* x16 */
+		},
+		.DevSize	= SIZE_8MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000,128)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_FUJITSU,
+		.dev_id		= MBM29LV320TE,
+		.name		= "Fujitsu MBM29LV320TE",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+		},
+		.DevSize	= SIZE_4MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x10000,63),
+			ERASEINFO(0x02000,8)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_FUJITSU,
+		.dev_id		= MBM29LV320BE,
+		.name		= "Fujitsu MBM29LV320BE",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+		},
+		.DevSize	= SIZE_4MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x02000,8),
+			ERASEINFO(0x10000,63)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_FUJITSU,
+		.dev_id		= MBM29LV160TE,
+		.name		= "Fujitsu MBM29LV160TE",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x10000,31),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x04000,1)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_FUJITSU,
+		.dev_id		= MBM29LV160BE,
+		.name		= "Fujitsu MBM29LV160BE",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x04000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x10000,31)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_FUJITSU,
+		.dev_id		= MBM29LV800BA,
+		.name		= "Fujitsu MBM29LV800BA",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x04000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x10000,15)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_FUJITSU,
+		.dev_id		= MBM29LV800TA,
+		.name		= "Fujitsu MBM29LV800TA",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x10000,15),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x04000,1)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F004B3B,
+		.name		= "Intel 28F004B3B",
+		.uaddr		= {
+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 7),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F004B3T,
+		.name		= "Intel 28F004B3T",
+		.uaddr		= {
+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x10000, 7),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F400B3B,
+		.name		= "Intel 28F400B3B",
+		.uaddr		= {
+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
+			[1] = MTD_UADDR_UNNECESSARY,    /* x16 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 7),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F400B3T,
+		.name		= "Intel 28F400B3T",
+		.uaddr		= {
+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
+			[1] = MTD_UADDR_UNNECESSARY,    /* x16 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x10000, 7),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F008B3B,
+		.name		= "Intel 28F008B3B",
+		.uaddr		= {
+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 15),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F008B3T,
+		.name		= "Intel 28F008B3T",
+		.uaddr		= {
+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x10000, 15),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F008S5,
+		.name		= "Intel 28F008S5",
+		.uaddr		= {
+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_INTEL_EXT,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000,16),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F016S5,
+		.name		= "Intel 28F016S5",
+		.uaddr		= {
+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_INTEL_EXT,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000,32),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F008SA,
+		.name		= "Intel 28F008SA",
+		.uaddr		= {
+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000, 16),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F800B3B,
+		.name		= "Intel 28F800B3B",
+		.uaddr		= {
+			[1] = MTD_UADDR_UNNECESSARY,    /* x16 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 15),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F800B3T,
+		.name		= "Intel 28F800B3T",
+		.uaddr		= {
+			[1] = MTD_UADDR_UNNECESSARY,    /* x16 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x10000, 15),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F016B3B,
+		.name		= "Intel 28F016B3B",
+		.uaddr		= {
+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 31),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F016S3,
+		.name		= "Intel I28F016S3",
+		.uaddr		= {
+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000, 32),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F016B3T,
+		.name		= "Intel 28F016B3T",
+		.uaddr		= {
+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x10000, 31),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F160B3B,
+		.name		= "Intel 28F160B3B",
+		.uaddr		= {
+			[1] = MTD_UADDR_UNNECESSARY,    /* x16 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 31),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F160B3T,
+		.name		= "Intel 28F160B3T",
+		.uaddr		= {
+			[1] = MTD_UADDR_UNNECESSARY,    /* x16 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x10000, 31),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F320B3B,
+		.name		= "Intel 28F320B3B",
+		.uaddr		= {
+			[1] = MTD_UADDR_UNNECESSARY,    /* x16 */
+		},
+		.DevSize	= SIZE_4MiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 63),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F320B3T,
+		.name		= "Intel 28F320B3T",
+		.uaddr		= {
+			[1] = MTD_UADDR_UNNECESSARY,    /* x16 */
+		},
+		.DevSize	= SIZE_4MiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x10000, 63),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F640B3B,
+		.name		= "Intel 28F640B3B",
+		.uaddr		= {
+			[1] = MTD_UADDR_UNNECESSARY,    /* x16 */
+		},
+		.DevSize	= SIZE_8MiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x02000, 8),
+			ERASEINFO(0x10000, 127),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I28F640B3T,
+		.name		= "Intel 28F640B3T",
+		.uaddr		= {
+			[1] = MTD_UADDR_UNNECESSARY,    /* x16 */
+		},
+		.DevSize	= SIZE_8MiB,
+		.CmdSet		= P_ID_INTEL_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x10000, 127),
+			ERASEINFO(0x02000, 8),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I82802AB,
+		.name		= "Intel 82802AB",
+		.uaddr		= {
+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_INTEL_EXT,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000,8),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_INTEL,
+		.dev_id		= I82802AC,
+		.name		= "Intel 82802AC",
+		.uaddr		= {
+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_INTEL_EXT,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000,16),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_MACRONIX,
+		.dev_id		= MX29LV160T,
+		.name		= "MXIC MX29LV160T",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x10000,31),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x04000,1)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_MACRONIX,
+		.dev_id		= MX29LV160B,
+		.name		= "MXIC MX29LV160B",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x04000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x10000,31)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_MACRONIX,
+		.dev_id		= MX29F016,
+		.name		= "Macronix MX29F016",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000,32),
+		}
+        }, {
+		.mfr_id		= MANUFACTURER_MACRONIX,
+		.dev_id		= MX29F004T,
+		.name		= "Macronix MX29F004T",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x10000,7),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x04000,1),
+		}
+        }, {
+		.mfr_id		= MANUFACTURER_MACRONIX,
+		.dev_id		= MX29F004B,
+		.name		= "Macronix MX29F004B",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x04000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x10000,7),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_PMC,
+		.dev_id		= PM49FL002,
+		.name		= "PMC Pm49FL002",
+ 		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_256KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO( 0x01000, 64 )
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_PMC,
+		.dev_id		= PM49FL004,
+		.name		= "PMC Pm49FL004",
+ 		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO( 0x01000, 128 )
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_PMC,
+		.dev_id		= PM49FL008,
+		.name		= "PMC Pm49FL008",
+ 		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO( 0x01000, 256 )
+		}
+        }, {
+		.mfr_id		= MANUFACTURER_SST,
+		.dev_id		= SST39LF512,
+		.name		= "SST 39LF512",
+ 		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_64KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x01000,16),
+		}
+        }, {
+		.mfr_id		= MANUFACTURER_SST,
+		.dev_id		= SST39LF010,
+		.name		= "SST 39LF010",
+ 		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_128KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x01000,32),
+		}
+        }, {
+		.mfr_id		= MANUFACTURER_SST,
+		.dev_id		= SST39LF020,
+		.name		= "SST 39LF020",
+ 		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_256KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x01000,64),
+		}
+        }, {
+		.mfr_id		= MANUFACTURER_SST,
+		.dev_id		= SST39LF040,
+		.name		= "SST 39LF040",
+ 		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x01000,128),
+		}
+        }, {
+		.mfr_id		= MANUFACTURER_SST,
+		.dev_id		= SST39SF010A,
+		.name		= "SST 39SF010A",
+ 		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_128KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x01000,32),
+		}
+        }, {
+		.mfr_id		= MANUFACTURER_SST,
+		.dev_id		= SST39SF020A,
+		.name		= "SST 39SF020A",
+ 		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_256KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x01000,64),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_SST,
+		.dev_id		= SST49LF030A,
+		.name		= "SST 49LF030A",
+ 		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x01000,96),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_SST,
+		.dev_id		= SST49LF040A,
+		.name		= "SST 49LF040A",
+ 		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x01000,128),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_SST,
+		.dev_id		= SST49LF080A,
+		.name		= "SST 49LF080A",
+ 		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x01000,256),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_ST,	/* FIXME - CFI device? */
+		.dev_id		= M29W800DT,
+		.name		= "ST M29W800DT",
+ 		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA,  /* x8 */
+			[1] = MTD_UADDR_0x5555_0x2AAA   /* x16 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x10000,15),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x04000,1)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_ST,	/* FIXME - CFI device? */
+		.dev_id		= M29W800DB,
+		.name		= "ST M29W800DB",
+ 		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA,  /* x8 */
+			[1] = MTD_UADDR_0x5555_0x2AAA   /* x16 */
+		},
+		.DevSize	= SIZE_1MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x04000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x10000,15)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_ST,	/* FIXME - CFI device? */
+		.dev_id		= M29W160DT,
+		.name		= "ST M29W160DT",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x02AA,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x10000,31),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x04000,1)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_ST,	/* FIXME - CFI device? */
+		.dev_id		= M29W160DB,
+		.name		= "ST M29W160DB",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x02AA,  /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x04000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x10000,31)
+		}
+        }, {
+		.mfr_id		= MANUFACTURER_ST,
+		.dev_id		= M29W040B,
+		.name		= "ST M29W040B",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+		},
+		.DevSize	= SIZE_512KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 1,
+		.regions	= {
+			ERASEINFO(0x10000,8),
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_TOSHIBA,
+		.dev_id		= TC58FVT160,
+		.name		= "Toshiba TC58FVT160",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA  /* x16 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x10000,31),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x04000,1)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_TOSHIBA,
+		.dev_id		= TC58FVB160,
+		.name		= "Toshiba TC58FVB160",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA  /* x16 */
+		},
+		.DevSize	= SIZE_2MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x04000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x10000,31)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_TOSHIBA,
+		.dev_id		= TC58FVB321,
+		.name		= "Toshiba TC58FVB321",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA  /* x16 */
+		},
+		.DevSize	= SIZE_4MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x02000,8),
+			ERASEINFO(0x10000,63)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_TOSHIBA,
+		.dev_id		= TC58FVT321,
+		.name		= "Toshiba TC58FVT321",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA  /* x16 */
+		},
+		.DevSize	= SIZE_4MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x10000,63),
+			ERASEINFO(0x02000,8)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_TOSHIBA,
+		.dev_id		= TC58FVB641,
+		.name		= "Toshiba TC58FVB641",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
+		},
+		.DevSize	= SIZE_8MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x02000,8),
+			ERASEINFO(0x10000,127)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_TOSHIBA,
+		.dev_id		= TC58FVT641,
+		.name		= "Toshiba TC58FVT641",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+			[1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
+		},
+		.DevSize	= SIZE_8MiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 2,
+		.regions	= {
+			ERASEINFO(0x10000,127),
+			ERASEINFO(0x02000,8)
+		}
+	}, {
+		.mfr_id		= MANUFACTURER_WINBOND,
+		.dev_id		= W49V002A,
+		.name		= "Winbond W49V002A",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+		},
+		.DevSize	= SIZE_256KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x10000, 3),
+			ERASEINFO(0x08000, 1),
+			ERASEINFO(0x02000, 2),
+			ERASEINFO(0x04000, 1),
+		}
 	} 
 };
 
@@ -258,12 +1352,70 @@
 			    struct flchip *chips, struct cfi_private *cfi);
 
 struct mtd_info *jedec_probe(struct map_info *map);
-#define jedec_read_mfr(map, base, osf) cfi_read(map, base)
-#define jedec_read_id(map, base, osf) cfi_read(map, (base)+(osf))
+
+static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, 
+	struct cfi_private *cfi)
+{
+	u32 result, mask;
+	mask = (1 << (cfi->device_type * 8)) -1;
+	result = cfi_read(map, base);
+	result &= mask;
+	return result;
+}
+
+static inline u32 jedec_read_id(struct map_info *map, __u32 base, 
+	struct cfi_private *cfi)
+{
+	int osf;
+	u32 result, mask;
+	osf = cfi->interleave *cfi->device_type;
+	mask = (1 << (cfi->device_type * 8)) -1;
+	result = cfi_read(map, base + osf);
+	result &= mask;
+	return result;
+}
+
+static inline void jedec_reset(u32 base, struct map_info *map, 
+	struct cfi_private *cfi)
+{
+	/* Reset */
+	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+	/* Some misdesigned intel chips do not respond for 0xF0 for a reset,
+	 * so ensure we're in read mode.  Send both the Intel and the AMD command
+	 * for this.  Intel uses 0xff for this, AMD uses 0xff for NOP, so
+	 * this should be safe.
+	 */ 
+	cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
+	/* FIXME - should have reset delay before continuing */
+}
+
+
+static inline __u8 finfo_uaddr(const struct amd_flash_info *finfo, int device_type)
+{
+	int uaddr_idx;
+	__u8 uaddr = MTD_UADDR_NOT_SUPPORTED;
+
+	switch ( device_type ) {
+	case CFI_DEVICETYPE_X8:  uaddr_idx = 0; break;
+	case CFI_DEVICETYPE_X16: uaddr_idx = 1; break;
+	case CFI_DEVICETYPE_X32: uaddr_idx = 2; break;
+	default:
+		printk(KERN_NOTICE "MTD: %s(): unknown device_type %d\n",
+		       __func__, device_type);
+		goto uaddr_done;
+	}
+
+	uaddr = finfo->uaddr[uaddr_idx];
+
+ uaddr_done:
+	return uaddr;
+}
+
 
 static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
 {
 	int i,num_erase_regions;
+	__u8 uaddr;
 
 	printk("Found: %s\n",jedec_table[index].name);
 
@@ -276,29 +1428,142 @@
 	}
 
 	memset(p_cfi->cfiq,0,sizeof(struct cfi_ident));	
-	
-	p_cfi->cfiq->P_ID = P_ID_AMD_STD;
+
+	p_cfi->cfiq->P_ID = jedec_table[index].CmdSet;
 	p_cfi->cfiq->NumEraseRegions = jedec_table[index].NumEraseRegions;
 	p_cfi->cfiq->DevSize = jedec_table[index].DevSize;
+	p_cfi->cfi_mode = CFI_MODE_JEDEC;
 
 	for (i=0; i<num_erase_regions; i++){
 		p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i];
-	}	
+	}
+	p_cfi->cmdset_priv = 0;
+
+	/* This may be redundant for some cases, but it doesn't hurt */
+	p_cfi->mfr = jedec_table[index].mfr_id;
+	p_cfi->id = jedec_table[index].dev_id;
+
+	uaddr = finfo_uaddr(&jedec_table[index], p_cfi->device_type);
+	if ( MTD_UADDR_NOT_SUPPORTED ) {
+		kfree( p_cfi->cfiq );
+		return 0;
+	}
+	p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1;
+	p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2;
+
 	return 1; 	/* ok */
 }
 
+
+/*
+ * There is a BIG problem properly ID'ing the JEDEC devic and guaranteeing
+ * the mapped address, unlock addresses, and proper chip ID.  This function
+ * attempts to minimize errors.  It is doubtfull that this probe will ever
+ * be perfect - consequently there should be some module parameters that
+ * could be manually specified to force the chip info.
+ */
+static inline int jedec_match( __u32 base,
+			       struct map_info *map,
+			       struct cfi_private *cfi,
+			       const struct amd_flash_info *finfo )
+{
+	int rc = 0;           /* failure until all tests pass */
+	u32 mfr, id;
+	__u8 uaddr;
+
+	/* The ID's must match */
+	if ( cfi->mfr != finfo->mfr_id || cfi->id != finfo->dev_id ) {
+		goto match_done;
+	}
+
+	/* the part size must fit in the memory window */
+	DEBUG( MTD_DEBUG_LEVEL3,
+	       "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n",
+	       __func__, base, 1 << finfo->DevSize, base + (1 << finfo->DevSize) );
+	if ( base + ( 1 << finfo->DevSize ) > map->size ) {
+		DEBUG( MTD_DEBUG_LEVEL3,
+		       "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n",
+		       __func__, finfo->mfr_id, finfo->dev_id,
+		       1 << finfo->DevSize );
+		goto match_done;
+	}
+
+	uaddr = finfo_uaddr(finfo, cfi->device_type);
+	if ( MTD_UADDR_NOT_SUPPORTED ) {
+		goto match_done;
+	}
+
+	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n",
+	       __func__, cfi->addr_unlock1, cfi->addr_unlock2 );
+	if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr
+	     && ( unlock_addrs[uaddr].addr1 != cfi->addr_unlock1
+		  || unlock_addrs[uaddr].addr2 != cfi->addr_unlock2 ) ) {
+		DEBUG( MTD_DEBUG_LEVEL3,
+		       "MTD %s(): 0x%.4x 0x%.4x did not match\n",
+		       __func__,
+		       unlock_addrs[uaddr].addr1,
+		       unlock_addrs[uaddr].addr2 );
+		goto match_done;
+	}
+
+	/*
+	 * Make sure the ID's dissappear when the device is taken out of
+	 * ID mode.  The only time this should fail when it should succeed
+	 * is when the ID's are written as data to the same
+	 * addresses.  For this rare and unfortunate case the chip
+	 * cannot be probed correctly.
+	 * FIXME - write a driver that takes all of the chip info as
+	 * module parameters, doesn't probe but forces a load.
+	 */
+	DEBUG( MTD_DEBUG_LEVEL3,
+	       "MTD %s(): check ID's disappear when not in ID mode\n",
+	       __func__ );
+	jedec_reset( base, map, cfi );
+	mfr = jedec_read_mfr( map, base, cfi );
+	id = jedec_read_id( map, base, cfi );
+	if ( mfr == cfi->mfr && id == cfi->id ) {
+		DEBUG( MTD_DEBUG_LEVEL3,
+		       "MTD %s(): ID 0x%.2x:0x%.2x did not change after reset:\n"
+		       "You might need to manually specify JEDEC parameters.\n",
+			__func__, cfi->mfr, cfi->id );
+		goto match_done;
+	}
+
+	/* all tests passed - mark  as success */
+	rc = 1;
+
+	/*
+	 * Put the device back in ID mode - only need to do this if we
+	 * were truly frobbing a real device.
+	 */
+	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ );
+	if(cfi->addr_unlock1) {
+		cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+		cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	}
+	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	/* FIXME - should have a delay before continuing */
+
+ match_done:	
+	return rc;
+}
+
+
 static int jedec_probe_chip(struct map_info *map, __u32 base,
 			      struct flchip *chips, struct cfi_private *cfi)
 {
 	int i;
-	int osf = cfi->interleave * cfi->device_type;
-	int retried = 0;
+	int unlockpass = 0;
 
+	/*
+	 * FIXME - eventually replace these unlock address seeds with
+	 * information from unlock_addrs[].
+	 */
 	if (!cfi->numchips) {
 		switch (cfi->device_type) {
 		case CFI_DEVICETYPE_X8:
-			cfi->addr_unlock1 = 0x555; 
-			cfi->addr_unlock2 = 0x2aa; 
+			cfi->addr_unlock1 = 0x555;
+			cfi->addr_unlock2 = 0x2aa;
 			break;
 		case CFI_DEVICETYPE_X16:
 			cfi->addr_unlock1 = 0xaaa;
@@ -320,48 +1585,98 @@
 	}
 
  retry:
+	/* Make certain we aren't probing past the end of map */
+	if (base >= map->size) {
+		printk(KERN_NOTICE
+			"Probe at base(0x%08x) past the end of the map(0x%08lx)\n",
+			base, map->size -1);
+		return 0;
+		
+	}
+	if ((base + cfi->addr_unlock1) >= map->size) {
+		printk(KERN_NOTICE
+			"Probe at addr_unlock1(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n",
+			base, cfi->addr_unlock1, map->size -1);
+
+		return 0;
+	}
+	if ((base + cfi->addr_unlock2) >= map->size) {
+		printk(KERN_NOTICE
+			"Probe at addr_unlock2(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n",
+			base, cfi->addr_unlock2, map->size -1);
+		return 0;
+		
+	}
+
 	/* Reset */
-	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+	jedec_reset(base, map, cfi);
 
 	/* Autoselect Mode */
-	cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
-	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	if(cfi->addr_unlock1) {
+		cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+		cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	}
 	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+	/* FIXME - should have a delay before continuing */
 
 	if (!cfi->numchips) {
 		/* This is the first time we're called. Set up the CFI 
 		   stuff accordingly and return */
 		
-		cfi->mfr = jedec_read_mfr(map, base, osf);
-		cfi->id = jedec_read_id(map, base, osf);
-		
+		cfi->mfr = jedec_read_mfr(map, base, cfi);
+		cfi->id = jedec_read_id(map, base, cfi);
+		printk(KERN_INFO "Search for id:(%02x %02x) interleave(%d) type(%d)\n", 
+			cfi->mfr, cfi->id, cfi->interleave, cfi->device_type);
 		for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) {
-			if (cfi->mfr == jedec_table[i].mfr_id &&
-			    cfi->id == jedec_table[i].dev_id)
-				return cfi_jedec_setup(cfi, i);
-		}
-		if (!retried++) {
-			/* Deal with whichever strange chips these were */
-			cfi->addr_unlock1 |= cfi->addr_unlock1 << 8;
-			cfi->addr_unlock2 |= cfi->addr_unlock2 << 8;
+			if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) {
+				DEBUG( MTD_DEBUG_LEVEL3,
+				       "MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n",
+				       __func__, cfi->mfr, cfi->id,
+				       cfi->addr_unlock1, cfi->addr_unlock2 );
+				if (!cfi_jedec_setup(cfi, i))
+					return 0;
+				goto ok_out;
+			}
+		}
+		switch(unlockpass++) {
+		case 0:
+			cfi->addr_unlock1 |= cfi->addr_unlock1 << 4;
+			cfi->addr_unlock2 |= cfi->addr_unlock2 << 4;
+			goto retry;
+		case 1:
+			cfi->addr_unlock1 = cfi->addr_unlock2 = 0;
 			goto retry;
 		}
 		return 0;
+	} else {
+		__u16 mfr;
+		__u16 id;
+
+		/* Make sure it is a chip of the same manufacturer and id */
+		mfr = jedec_read_mfr(map, base, cfi);
+		id = jedec_read_id(map, base, cfi);
+
+		if ((mfr != cfi->mfr) || (id != cfi->id)) {
+			printk(KERN_DEBUG "%s: Found different chip or no chip at all (mfr 0x%x, id 0x%x) at 0x%x\n",
+			       map->name, mfr, id, base);
+			jedec_reset(base, map, cfi);
+			return 0;
+		}
 	}
 	
 	/* Check each previous chip to see if it's an alias */
 	for (i=0; i<cfi->numchips; i++) {
 		/* This chip should be in read mode if it's one
 		   we've already touched. */
-		if (jedec_read_mfr(map, base, osf) == cfi->mfr &&
-		    jedec_read_id(map, base, osf) == cfi->id) {
+		if (jedec_read_mfr(map, chips[i].start, cfi) == cfi->mfr &&
+		    jedec_read_id(map, chips[i].start, cfi) == cfi->id) {
 			/* Eep. This chip also looks like it's in autoselect mode.
 			   Is it an alias for the new one? */
-			
-			cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL);
+			jedec_reset(chips[i].start, map, cfi);
+
 			/* If the device IDs go away, it's an alias */
-			if (jedec_read_mfr(map, base, osf) != cfi->mfr ||
-			    jedec_read_id(map, base, osf) != cfi->id) {
+			if (jedec_read_mfr(map, base, cfi) != cfi->mfr ||
+			    jedec_read_id(map, base, cfi) != cfi->id) {
 				printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
 				       map->name, base, chips[i].start);
 				return 0;
@@ -371,9 +1686,9 @@
 			 * unfortunate. Stick the new chip in read mode
 			 * too and if it's the same, assume it's an alias. */
 			/* FIXME: Use other modes to do a proper check */
-			cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
-			if (jedec_read_mfr(map, base, osf) == cfi->mfr &&
-			    jedec_read_id(map, base, osf) == cfi->id) {
+			jedec_reset(base, map, cfi);
+			if (jedec_read_mfr(map, base, cfi) == cfi->mfr &&
+			    jedec_read_id(map, base, cfi) == cfi->id) {
 				printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
 				       map->name, base, chips[i].start);
 				return 0;
@@ -392,8 +1707,9 @@
 	chips[cfi->numchips].state = FL_READY;
 	cfi->numchips++;
 		
+ok_out:
 	/* Put it back into Read Mode */
-	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+	jedec_reset(base, map, cfi);
 
 	printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
 	       map->name, cfi->interleave, cfi->device_type*8, base, 
diff -Nru a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c
--- a/drivers/mtd/chips/map_absent.c	Wed Feb 26 05:27:27 2003
+++ b/drivers/mtd/chips/map_absent.c	Wed May 28 08:01:02 2003
@@ -1,7 +1,7 @@
 /*
  * Common code to handle absent "placeholder" devices
  * Copyright 2001 Resilience Corporation <ebrower@resilience.com>
- * $Id: map_absent.c,v 1.2 2001/10/02 15:05:12 dwmw2 Exp $
+ * $Id: map_absent.c,v 1.4 2003/05/28 12:51:49 dwmw2 Exp $
  *
  * This map driver is used to allocate "placeholder" MTD
  * devices on systems that have socketed/removable media. 
@@ -23,9 +23,10 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
-
+#include <linux/mtd/compatmac.h>
 
 static int map_absent_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int map_absent_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -36,10 +37,10 @@
 
 
 static struct mtd_chip_driver map_absent_chipdrv = {
-	.probe 		= map_absent_probe,
+	.probe		= map_absent_probe,
 	.destroy	= map_absent_destroy,
-	.name 		= "map_absent",
-	.module 	= THIS_MODULE
+	.name		= "map_absent",
+	.module		= THIS_MODULE
 };
 
 static struct mtd_info *map_absent_probe(struct map_info *map)
@@ -65,7 +66,7 @@
 	mtd->flags 	= 0;
 	mtd->erasesize = PAGE_SIZE;
 
-	MOD_INC_USE_COUNT;
+	__module_get(THIS_MODULE);
 	return mtd;
 }
 
diff -Nru a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c
--- a/drivers/mtd/chips/map_ram.c	Wed Feb 26 05:27:41 2003
+++ b/drivers/mtd/chips/map_ram.c	Wed May 28 08:01:02 2003
@@ -1,7 +1,7 @@
 /*
  * Common code to handle map devices which are simple RAM
  * (C) 2000 Red Hat. GPL'd.
- * $Id: map_ram.c,v 1.14 2001/10/02 15:05:12 dwmw2 Exp $
+ * $Id: map_ram.c,v 1.17 2003/05/28 12:51:49 dwmw2 Exp $
  */
 
 #include <linux/module.h>
@@ -11,8 +11,10 @@
 #include <asm/byteorder.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
+#include <linux/mtd/compatmac.h>
 
 
 static int mapram_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
@@ -34,21 +36,21 @@
 
 	/* Check the first byte is RAM */
 #if 0
-	map->write8(map, 0x55, 0);
-	if (map->read8(map, 0) != 0x55)
+	map_write8(map, 0x55, 0);
+	if (map_read8(map, 0) != 0x55)
 		return NULL;
 
-	map->write8(map, 0xAA, 0);
-	if (map->read8(map, 0) != 0xAA)
+	map_write8(map, 0xAA, 0);
+	if (map_read8(map, 0) != 0xAA)
 		return NULL;
 
 	/* Check the last byte is RAM */
-	map->write8(map, 0x55, map->size-1);
-	if (map->read8(map, map->size-1) != 0x55)
+	map_write8(map, 0x55, map->size-1);
+	if (map_read8(map, map->size-1) != 0x55)
 		return NULL;
 
-	map->write8(map, 0xAA, map->size-1);
-	if (map->read8(map, map->size-1) != 0xAA)
+	map_write8(map, 0xAA, map->size-1);
+	if (map_read8(map, map->size-1) != 0xAA)
 		return NULL;
 #endif
 	/* OK. It seems to be RAM. */
@@ -74,7 +76,7 @@
  	while(mtd->size & (mtd->erasesize - 1))
 		mtd->erasesize >>= 1;
 
-	MOD_INC_USE_COUNT;
+	__module_get(THIS_MODULE);
 	return mtd;
 }
 
@@ -83,7 +85,7 @@
 {
 	struct map_info *map = (struct map_info *)mtd->priv;
 
-	map->copy_from(map, buf, from, len);
+	map_copy_from(map, buf, from, len);
 	*retlen = len;
 	return 0;
 }
@@ -92,7 +94,7 @@
 {
 	struct map_info *map = (struct map_info *)mtd->priv;
 
-	map->copy_to(map, to, buf, len);
+	map_copy_to(map, to, buf, len);
 	*retlen = len;
 	return 0;
 }
@@ -105,7 +107,7 @@
 	unsigned long i;
 
 	for (i=0; i<instr->len; i++)
-		map->write8(map, 0xFF, instr->addr + i);
+		map_write8(map, 0xFF, instr->addr + i);
 
 	if (instr->callback)
 		instr->callback(instr);
diff -Nru a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c
--- a/drivers/mtd/chips/map_rom.c	Wed Feb 26 05:27:53 2003
+++ b/drivers/mtd/chips/map_rom.c	Wed May 28 08:01:02 2003
@@ -1,7 +1,7 @@
 /*
  * Common code to handle map devices which are simple ROM
  * (C) 2000 Red Hat. GPL'd.
- * $Id: map_rom.c,v 1.17 2001/10/02 15:05:12 dwmw2 Exp $
+ * $Id: map_rom.c,v 1.20 2003/05/28 12:51:49 dwmw2 Exp $
  */
 
 #include <linux/version.h>
@@ -12,8 +12,10 @@
 #include <asm/byteorder.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
+#include <linux/mtd/compatmac.h>
 
 static int maprom_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int maprom_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -49,7 +51,7 @@
  	while(mtd->size & (mtd->erasesize - 1))
 		mtd->erasesize >>= 1;
 
-	MOD_INC_USE_COUNT;
+	__module_get(THIS_MODULE);
 	return mtd;
 }
 
@@ -58,7 +60,7 @@
 {
 	struct map_info *map = (struct map_info *)mtd->priv;
 
-	map->copy_from(map, buf, from, len);
+	map_copy_from(map, buf, from, len);
 	*retlen = len;
 	return 0;
 }
diff -Nru a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
--- a/drivers/mtd/chips/sharp.c	Wed May 14 23:43:59 2003
+++ b/drivers/mtd/chips/sharp.c	Wed May 28 08:56:01 2003
@@ -4,7 +4,7 @@
  * Copyright 2000,2001 David A. Schleef <ds@schleef.org>
  *           2000,2001 Lineo, Inc.
  *
- * $Id: sharp.c,v 1.6 2001/10/02 15:05:12 dwmw2 Exp $
+ * $Id: sharp.c,v 1.12 2003/05/28 15:39:52 dwmw2 Exp $
  *
  * Devices supported:
  *   LH28F016SCT Symmetrical block flash memory, 2Mx8
@@ -28,6 +28,7 @@
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/map.h>
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/cfi.h>
 #include <linux/delay.h>
 
@@ -165,12 +166,12 @@
 	u32 read0, read4;
 	int width = 4;
 
-	tmp = map->read32(map, base+0);
+	tmp = map_read32(map, base+0);
 
-	map->write32(map, CMD_READ_ID, base+0);
+	map_write32(map, CMD_READ_ID, base+0);
 
-	read0=map->read32(map, base+0);
-	read4=map->read32(map, base+4);
+	read0=map_read32(map, base+0);
+	read4=map_read32(map, base+4);
 	if(read0 == 0x89898989){
 		printk("Looks like sharp flash\n");
 		switch(read4){
@@ -198,10 +199,10 @@
 			printk("Sort-of looks like sharp flash, 0x%08x 0x%08x\n",
 				read0,read4);
 		}
-	}else if((map->read32(map, base+0) == CMD_READ_ID)){
+	}else if((map_read32(map, base+0) == CMD_READ_ID)){
 		/* RAM, probably */
 		printk("Looks like RAM\n");
-		map->write32(map, tmp, base+0);
+		map_write32(map, tmp, base+0);
 	}else{
 		printk("Doesn't look like sharp flash, 0x%08x 0x%08x\n",
 			read0,read4);
@@ -223,10 +224,10 @@
 
 	switch(chip->state){
 	case FL_READY:
-		map->write32(map,CMD_READ_STATUS,adr);
+		map_write32(map,CMD_READ_STATUS,adr);
 		chip->state = FL_STATUS;
 	case FL_STATUS:
-		status = map->read32(map,adr);
+		status = map_read32(map,adr);
 //printk("status=%08x\n",status);
 
 		udelay(100);
@@ -254,7 +255,7 @@
 		goto retry;
 	}
 
-	map->write32(map,CMD_RESET, adr);
+	map_write32(map,CMD_RESET, adr);
 
 	chip->state = FL_READY;
 
@@ -295,7 +296,7 @@
 		if(ret<0)
 			break;
 
-		map->copy_from(map,buf,ofs,thislen);
+		map_copy_from(map,buf,ofs,thislen);
 
 		sharp_release(&sharp->chips[chipnum]);
 
@@ -356,17 +357,17 @@
 	ret = sharp_wait(map,chip);
 
 	for(try=0;try<10;try++){
-		map->write32(map,CMD_BYTE_WRITE,adr);
+		map_write32(map,CMD_BYTE_WRITE,adr);
 		/* cpu_to_le32 -> hack to fix the writel be->le conversion */
-		map->write32(map,cpu_to_le32(datum),adr);
+		map_write32(map,cpu_to_le32(datum),adr);
 
 		chip->state = FL_WRITING;
 
 		timeo = jiffies + (HZ/2);
 
-		map->write32(map,CMD_READ_STATUS,adr);
+		map_write32(map,CMD_READ_STATUS,adr);
 		for(i=0;i<100;i++){
-			status = map->read32(map,adr);
+			status = map_read32(map,adr);
 			if((status & SR_READY)==SR_READY)
 				break;
 		}
@@ -379,9 +380,9 @@
 
 		printk("sharp: error writing byte at addr=%08lx status=%08x\n",adr,status);
 
-		map->write32(map,CMD_CLEAR_STATUS,adr);
+		map_write32(map,CMD_CLEAR_STATUS,adr);
 	}
-	map->write32(map,CMD_RESET,adr);
+	map_write32(map,CMD_RESET,adr);
 	chip->state = FL_READY;
 
 	wake_up(&chip->wq);
@@ -423,6 +424,7 @@
 		}
 	}
 
+	instr->state = MTD_ERASE_DONE;
 	if(instr->callback)
 		instr->callback(instr);
 
@@ -433,18 +435,18 @@
 	unsigned long adr)
 {
 	int ret;
-	unsigned long timeo;
+	int timeo;
 	int status;
 	DECLARE_WAITQUEUE(wait, current);
 
-	map->write32(map,CMD_READ_STATUS,adr);
-	status = map->read32(map,adr);
+	map_write32(map,CMD_READ_STATUS,adr);
+	status = map_read32(map,adr);
 
 	timeo = jiffies + HZ;
 
 	while(time_before(jiffies, timeo)){
-		map->write32(map,CMD_READ_STATUS,adr);
-		status = map->read32(map,adr);
+		map_write32(map,CMD_READ_STATUS,adr);
+		status = map_read32(map,adr);
 		if((status & SR_READY)==SR_READY){
 			ret = 0;
 			goto out;
@@ -486,26 +488,26 @@
 	sharp_unlock_oneblock(map,chip,adr);
 #endif
 
-	map->write32(map,CMD_BLOCK_ERASE_1,adr);
-	map->write32(map,CMD_BLOCK_ERASE_2,adr);
+	map_write32(map,CMD_BLOCK_ERASE_1,adr);
+	map_write32(map,CMD_BLOCK_ERASE_2,adr);
 
 	chip->state = FL_ERASING;
 
 	ret = sharp_do_wait_for_ready(map,chip,adr);
 	if(ret<0)return ret;
 
-	map->write32(map,CMD_READ_STATUS,adr);
-	status = map->read32(map,adr);
+	map_write32(map,CMD_READ_STATUS,adr);
+	status = map_read32(map,adr);
 
 	if(!(status&SR_ERRORS)){
-		map->write32(map,CMD_RESET,adr);
+		map_write32(map,CMD_RESET,adr);
 		chip->state = FL_READY;
 		//spin_unlock_bh(chip->mutex);
 		return 0;
 	}
 
 	printk("sharp: error erasing block at addr=%08lx status=%08x\n",adr,status);
-	map->write32(map,CMD_CLEAR_STATUS,adr);
+	map_write32(map,CMD_CLEAR_STATUS,adr);
 
 	//spin_unlock_bh(chip->mutex);
 
@@ -519,17 +521,17 @@
 	int i;
 	int status;
 
-	map->write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr);
-	map->write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr);
+	map_write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr);
+	map_write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr);
 
 	udelay(100);
 
-	status = map->read32(map,adr);
+	status = map_read32(map,adr);
 	printk("status=%08x\n",status);
 
 	for(i=0;i<1000;i++){
-		//map->write32(map,CMD_READ_STATUS,adr);
-		status = map->read32(map,adr);
+		//map_write32(map,CMD_READ_STATUS,adr);
+		status = map_read32(map,adr);
 		if((status & SR_READY)==SR_READY)
 			break;
 		udelay(100);
@@ -539,13 +541,13 @@
 	}
 
 	if(!(status&SR_ERRORS)){
-		map->write32(map,CMD_RESET,adr);
+		map_write32(map,CMD_RESET,adr);
 		chip->state = FL_READY;
 		return;
 	}
 
 	printk("sharp: error unlocking block at addr=%08lx status=%08x\n",adr,status);
-	map->write32(map,CMD_CLEAR_STATUS,adr);
+	map_write32(map,CMD_CLEAR_STATUS,adr);
 }
 #endif
 
diff -Nru a/drivers/mtd/cmdline.c b/drivers/mtd/cmdline.c
--- a/drivers/mtd/cmdline.c	Sun May 25 17:00:00 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,362 +0,0 @@
-/*
- * $Id: cmdline.c,v 1.5 2002/11/06 22:40:04 rmk Exp $
- *
- * Read flash partition table from command line
- *
- * Copyright 2002 SYSGO Real-Time Solutions GmbH
- *
- * The format for the command line is as follows:
- * 
- * mtdparts=<mtddef>[;<mtddef]
- * <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
- * <partdef> := <size>[@offset][<name>][ro]
- * <mtd-id>  := unique id used in mapping driver/device
- * <size>    := standard linux memsize OR "-" to denote all remaining space
- * <name>    := '(' NAME ')'
- * 
- * Examples:
- * 
- * 1 NOR Flash, with 1 single writable partition:
- * edb7312-nor:-
- * 
- * 1 NOR Flash with 2 partitions, 1 NAND with one
- * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <asm/setup.h>
-#include <linux/bootmem.h>
-
-/* error message prefix */
-#define ERRP "mtd: "
-
-/* debug macro */
-#if 0
-#define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0)
-#else
-#define dbg(x)
-#endif
-
-
-/* special size referring to all the remaining space in a partition */
-#define SIZE_REMAINING 0xffffffff
-
-struct cmdline_mtd_partition {
-	struct cmdline_mtd_partition *next;
-	char *mtd_id;
-	int num_parts;
-	struct mtd_partition *parts;
-};
-
-/* mtdpart_setup() parses into here */
-static struct cmdline_mtd_partition *partitions;
-
-/* the command line passed to mtdpart_setupd() */
-static char *cmdline;
-static int cmdline_parsed = 0;
-
-/*
- * Parse one partition definition for an MTD. Since there can be many
- * comma separated partition definitions, this function calls itself 
- * recursively until no more partition definitions are found. Nice side
- * effect: the memory to keep the mtd_partition structs and the names
- * is allocated upon the last definition being found. At that point the
- * syntax has been verified ok.
- */
-static struct mtd_partition * newpart(char *s, 
-                                      char **retptr,
-                                      int *num_parts,
-                                      int this_part, 
-                                      unsigned char **extra_mem_ptr, 
-                                      int extra_mem_size)
-{
-	struct mtd_partition *parts;
-	unsigned long size;
-	unsigned long offset = 0;
-	char *name;
-	int name_len;
-	unsigned char *extra_mem;
-	char delim;
-	unsigned int mask_flags;
-
-	/* fetch the partition size */
-	if (*s == '-')
-	{	/* assign all remaining space to this partition */
-		size = SIZE_REMAINING;
-		s++;
-	}
-	else
-	{
-		size = memparse(s, &s);
-		if (!size)
-		{
-			printk(KERN_ERR ERRP "couldn't parse number from input string\n");
-			return 0;
-		}
-		if (size < PAGE_SIZE)
-		{
-			printk(KERN_ERR ERRP "partition size too small (%lx)\n", size);
-			return 0;
-		}
-	}
-
-	/* fetch partition name and flags */
-	mask_flags = 0; /* this is going to be a regular partition */
-	delim = 0;
-        /* check for offset */
-        if (*s == '@') 
-	{
-                s++;
-                offset = memparse(s, &s);
-		if (!offset)
-		{
-			printk(KERN_ERR ERRP "couldn't parse number from input string\n");
-			return 0;
-		}
-        }
-        /* now look for name */
-	if (*s == '(')
-	{
-		delim = ')';
-	}
-	if (delim)
-	{
-		char *p;
-
-	    	name = ++s;
-		if ((p = strchr(name, delim)) == 0)
-		{
-			printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
-			return 0;
-		}
-		name_len = p - name;
-		s = p + 1;
-	}
-	else
-	{
-	    	name = NULL;
-		name_len = 13; /* Partition_000 */
-	}
-   
-	/* record name length for memory allocation later */
-	extra_mem_size += name_len + 1;
-
-        /* test for options */
-        if (strncmp(s, "ro", 2) == 0) 
-	{
-		mask_flags |= MTD_WRITEABLE;
-		s += 2;
-        }
-
-	/* test if more partitions are following */
-	if (*s == ',')
-	{
-		if (size == SIZE_REMAINING)
-		{
-			printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n");
-			return 0;
-		}
-		/* more partitions follow, parse them */
-		if ((parts = newpart(s + 1, &s, num_parts, 
-		                     this_part + 1, &extra_mem, extra_mem_size)) == 0)
-		  return 0;
-	}
-	else
-	{	/* this is the last partition: allocate space for all */
-		int alloc_size;
-
-		*num_parts = this_part + 1;
-		alloc_size = *num_parts * sizeof(struct mtd_partition) +
-			     extra_mem_size;
-		parts = kmalloc(alloc_size, GFP_KERNEL);
-		if (!parts)
-		{
-			printk(KERN_ERR ERRP "out of memory\n");
-			return 0;
-		}
-		memset(parts, 0, alloc_size);
-		extra_mem = (unsigned char *)(parts + *num_parts);
-	}
-	/* enter this partition (offset will be calculated later if it is zero at this point) */
-	parts[this_part].size = size;
-	parts[this_part].offset = offset;
-	parts[this_part].mask_flags = mask_flags;
-	if (name)
-	{
-		strlcpy(extra_mem, name, name_len + 1);
-	}
-	else
-	{
-		sprintf(extra_mem, "Partition_%03d", this_part);
-	}
-	parts[this_part].name = extra_mem;
-	extra_mem += name_len + 1;
-
-	dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n",
-	     this_part, 
-	     parts[this_part].name,
-	     parts[this_part].offset,
-	     parts[this_part].size,
-	     parts[this_part].mask_flags));
-
-	/* return (updated) pointer to extra_mem memory */
-	if (extra_mem_ptr)
-	  *extra_mem_ptr = extra_mem;
-
-	/* return (updated) pointer command line string */
-	*retptr = s;
-
-	/* return partition table */
-	return parts;
-}
-
-/* 
- * Parse the command line. 
- */
-static int mtdpart_setup_real(char *s)
-{
-	cmdline_parsed = 1;
-
-	for( ; s != NULL; )
-	{
-		struct cmdline_mtd_partition *this_mtd;
-		struct mtd_partition *parts;
-	    	int mtd_id_len;
-		int num_parts;
-		char *p, *mtd_id;
-
-	    	mtd_id = s;
-		/* fetch <mtd-id> */
-		if (!(p = strchr(s, ':')))
-		{
-			printk(KERN_ERR ERRP "no mtd-id\n");
-			return 0;
-		}
-		mtd_id_len = p - mtd_id;
-
-		dbg(("parsing <%s>\n", p+1));
-
-		/* 
-		 * parse one mtd. have it reserve memory for the
-		 * struct cmdline_mtd_partition and the mtd-id string.
-		 */
-		parts = newpart(p + 1,		/* cmdline */
-				&s,		/* out: updated cmdline ptr */
-				&num_parts,	/* out: number of parts */
-				0,		/* first partition */
-				(unsigned char**)&this_mtd, /* out: extra mem */
-				mtd_id_len + 1 + sizeof(*this_mtd));
-		if(!parts)
-		{
-			/*
-			 * An error occurred. We're either:
-			 * a) out of memory, or
-			 * b) in the middle of the partition spec
-			 * Either way, this mtd is hosed and we're
-			 * unlikely to succeed in parsing any more
-			 */
-			 return 0;
-		 }
-
-		/* enter results */	    
-		this_mtd->parts = parts;
-		this_mtd->num_parts = num_parts;
-		this_mtd->mtd_id = (char*)(this_mtd + 1);
-		strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1);
-
-		/* link into chain */
-		this_mtd->next = partitions;	    	
-		partitions = this_mtd;
-
-		dbg(("mtdid=<%s> num_parts=<%d>\n", 
-		     this_mtd->mtd_id, this_mtd->num_parts));
-		
-
-		/* EOS - we're done */
-		if (*s == 0)
-			break;
-
-		/* does another spec follow? */
-		if (*s != ';')
-		{
-			printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s);
-			return 0;
-		}
-		s++;
-	}
-	return 1;
-}
-
-/*
- * Main function to be called from the MTD mapping driver/device to
- * obtain the partitioning information. At this point the command line
- * arguments will actually be parsed and turned to struct mtd_partition
- * information.
- */
-int parse_cmdline_partitions(struct mtd_info *master, 
-                             struct mtd_partition **pparts,
-                             const char *mtd_id)
-{
-	unsigned long offset;
-	int i;
-	struct cmdline_mtd_partition *part;
-
-	if (!cmdline)
-		return -EINVAL;
-
-	/* parse command line */
-	if (!cmdline_parsed)
-		mtdpart_setup_real(cmdline);
-
-	for(part = partitions; part; part = part->next)
-	{
-		if (!strcmp(part->mtd_id, mtd_id))
-		{
-			for(i = 0, offset = 0; i < part->num_parts; i++)
-			{
-				if (!part->parts[i].offset)
-				  part->parts[i].offset = offset;
-				else
-				  offset = part->parts[i].offset;
-				if (part->parts[i].size == SIZE_REMAINING)
-				  part->parts[i].size = master->size - offset;
-				if (offset + part->parts[i].size > master->size)
-				{
-					printk(KERN_WARNING ERRP 
-					       "%s: partitioning exceeds flash size, truncating\n",
-					       mtd_id);
-					part->parts[i].size = master->size - offset;
-					part->num_parts = i;
-				}
-				offset += part->parts[i].size;
-			}
-			*pparts = part->parts;
-			return part->num_parts;
-		}
-	}
-	return -EINVAL;
-}
-
-
-/* 
- * This is the handler for our kernel parameter, called from 
- * main.c::checksetup(). Note that we can not yet kmalloc() anything,
- * so we only save the commandline for later processing.
- */
-static int __init mtdpart_setup(char *s)
-{
-	cmdline = s;
-	return 1;
-}
-
-__setup("mtdparts=", mtdpart_setup);
-
-EXPORT_SYMBOL(parse_cmdline_partitions);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
-MODULE_DESCRIPTION("Command line configuration of MTD partitions");
diff -Nru a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/cmdlinepart.c	Wed May 28 08:01:08 2003
@@ -0,0 +1,373 @@
+/*
+ * $Id: cmdlinepart.c,v 1.9 2003/05/16 17:08:24 dwmw2 Exp $
+ *
+ * Read flash partition table from command line
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ *
+ * The format for the command line is as follows:
+ * 
+ * mtdparts=<mtddef>[;<mtddef]
+ * <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
+ * <partdef> := <size>[@offset][<name>][ro]
+ * <mtd-id>  := unique id used in mapping driver/device
+ * <size>    := standard linux memsize OR "-" to denote all remaining space
+ * <name>    := '(' NAME ')'
+ * 
+ * Examples:
+ * 
+ * 1 NOR Flash, with 1 single writable partition:
+ * edb7312-nor:-
+ * 
+ * 1 NOR Flash with 2 partitions, 1 NAND with one
+ * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <asm/setup.h>
+#include <linux/bootmem.h>
+
+/* error message prefix */
+#define ERRP "mtd: "
+
+/* debug macro */
+#if 0
+#define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0)
+#else
+#define dbg(x)
+#endif
+
+
+/* special size referring to all the remaining space in a partition */
+#define SIZE_REMAINING 0xffffffff
+
+struct cmdline_mtd_partition {
+	struct cmdline_mtd_partition *next;
+	char *mtd_id;
+	int num_parts;
+	struct mtd_partition *parts;
+};
+
+/* mtdpart_setup() parses into here */
+static struct cmdline_mtd_partition *partitions;
+
+/* the command line passed to mtdpart_setupd() */
+static char *cmdline;
+static int cmdline_parsed = 0;
+
+/*
+ * Parse one partition definition for an MTD. Since there can be many
+ * comma separated partition definitions, this function calls itself 
+ * recursively until no more partition definitions are found. Nice side
+ * effect: the memory to keep the mtd_partition structs and the names
+ * is allocated upon the last definition being found. At that point the
+ * syntax has been verified ok.
+ */
+static struct mtd_partition * newpart(char *s, 
+                                      char **retptr,
+                                      int *num_parts,
+                                      int this_part, 
+                                      unsigned char **extra_mem_ptr, 
+                                      int extra_mem_size)
+{
+	struct mtd_partition *parts;
+	unsigned long size;
+	unsigned long offset = 0;
+	char *name;
+	int name_len;
+	unsigned char *extra_mem;
+	char delim;
+	unsigned int mask_flags;
+
+	/* fetch the partition size */
+	if (*s == '-')
+	{	/* assign all remaining space to this partition */
+		size = SIZE_REMAINING;
+		s++;
+	}
+	else
+	{
+		size = memparse(s, &s);
+		if (size < PAGE_SIZE)
+		{
+			printk(KERN_ERR ERRP "partition size too small (%lx)\n", size);
+			return 0;
+		}
+	}
+
+	/* fetch partition name and flags */
+	mask_flags = 0; /* this is going to be a regular partition */
+	delim = 0;
+        /* check for offset */
+        if (*s == '@') 
+	{
+                s++;
+                offset = memparse(s, &s);
+        }
+        /* now look for name */
+	if (*s == '(')
+	{
+		delim = ')';
+	}
+		
+	if (delim)
+	{
+		char *p;
+
+	    	name = ++s;
+		if ((p = strchr(name, delim)) == 0)
+		{
+			printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
+			return 0;
+		}
+		name_len = p - name;
+		s = p + 1;
+	}
+	else
+	{
+	    	name = NULL;
+		name_len = 13; /* Partition_000 */
+	}
+   
+	/* record name length for memory allocation later */
+	extra_mem_size += name_len + 1;
+
+        /* test for options */
+        if (strncmp(s, "ro", 2) == 0) 
+	{
+		mask_flags |= MTD_WRITEABLE;
+		s += 2;
+        }
+
+	/* test if more partitions are following */
+	if (*s == ',')
+	{
+		if (size == SIZE_REMAINING)
+		{
+			printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n");
+			return 0;
+		}
+		/* more partitions follow, parse them */
+		if ((parts = newpart(s + 1, &s, num_parts, 
+		                     this_part + 1, &extra_mem, extra_mem_size)) == 0)
+		  return 0;
+	}
+	else
+	{	/* this is the last partition: allocate space for all */
+		int alloc_size;
+
+		*num_parts = this_part + 1;
+		alloc_size = *num_parts * sizeof(struct mtd_partition) +
+			     extra_mem_size;
+		parts = kmalloc(alloc_size, GFP_KERNEL);
+		if (!parts)
+		{
+			printk(KERN_ERR ERRP "out of memory\n");
+			return 0;
+		}
+		memset(parts, 0, alloc_size);
+		extra_mem = (unsigned char *)(parts + *num_parts);
+	}
+	/* enter this partition (offset will be calculated later if it is zero at this point) */
+	parts[this_part].size = size;
+	parts[this_part].offset = offset;
+	parts[this_part].mask_flags = mask_flags;
+	if (name)
+	{
+		strlcpy(extra_mem, name, name_len + 1);
+	}
+	else
+	{
+		sprintf(extra_mem, "Partition_%03d", this_part);
+	}
+	parts[this_part].name = extra_mem;
+	extra_mem += name_len + 1;
+
+	dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n",
+	     this_part, 
+	     parts[this_part].name,
+	     parts[this_part].offset,
+	     parts[this_part].size,
+	     parts[this_part].mask_flags));
+
+	/* return (updated) pointer to extra_mem memory */
+	if (extra_mem_ptr)
+	  *extra_mem_ptr = extra_mem;
+
+	/* return (updated) pointer command line string */
+	*retptr = s;
+
+	/* return partition table */
+	return parts;
+}
+
+/* 
+ * Parse the command line. 
+ */
+static int mtdpart_setup_real(char *s)
+{
+	cmdline_parsed = 1;
+
+	for( ; s != NULL; )
+	{
+		struct cmdline_mtd_partition *this_mtd;
+		struct mtd_partition *parts;
+	    	int mtd_id_len;
+		int num_parts;
+		char *p, *mtd_id;
+
+	    	mtd_id = s;
+		/* fetch <mtd-id> */
+		if (!(p = strchr(s, ':')))
+		{
+			printk(KERN_ERR ERRP "no mtd-id\n");
+			return 0;
+		}
+		mtd_id_len = p - mtd_id;
+
+		dbg(("parsing <%s>\n", p+1));
+
+		/* 
+		 * parse one mtd. have it reserve memory for the
+		 * struct cmdline_mtd_partition and the mtd-id string.
+		 */
+		parts = newpart(p + 1,		/* cmdline */
+				&s,		/* out: updated cmdline ptr */
+				&num_parts,	/* out: number of parts */
+				0,		/* first partition */
+				(unsigned char**)&this_mtd, /* out: extra mem */
+				mtd_id_len + 1 + sizeof(*this_mtd));
+		if(!parts)
+		{
+			/*
+			 * An error occurred. We're either:
+			 * a) out of memory, or
+			 * b) in the middle of the partition spec
+			 * Either way, this mtd is hosed and we're
+			 * unlikely to succeed in parsing any more
+			 */
+			 return 0;
+		 }
+
+		/* enter results */	    
+		this_mtd->parts = parts;
+		this_mtd->num_parts = num_parts;
+		this_mtd->mtd_id = (char*)(this_mtd + 1);
+		strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1);
+
+		/* link into chain */
+		this_mtd->next = partitions;	    	
+		partitions = this_mtd;
+
+		dbg(("mtdid=<%s> num_parts=<%d>\n", 
+		     this_mtd->mtd_id, this_mtd->num_parts));
+		
+
+		/* EOS - we're done */
+		if (*s == 0)
+			break;
+
+		/* does another spec follow? */
+		if (*s != ';')
+		{
+			printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s);
+			return 0;
+		}
+		s++;
+	}
+	return 1;
+}
+
+/*
+ * Main function to be called from the MTD mapping driver/device to
+ * obtain the partitioning information. At this point the command line
+ * arguments will actually be parsed and turned to struct mtd_partition
+ * information. It returns partitions for the requested mtd device, or
+ * the first one in the chain if a NULL mtd_id is passed in.
+ */
+static int parse_cmdline_partitions(struct mtd_info *master, 
+                             struct mtd_partition **pparts,
+                             unsigned long origin)
+{
+	unsigned long offset;
+	int i;
+	struct cmdline_mtd_partition *part;
+	char *mtd_id = master->name;
+
+	if(!cmdline)
+		return -EINVAL;
+
+	/* parse command line */
+	if (!cmdline_parsed)
+		mtdpart_setup_real(cmdline);
+
+	for(part = partitions; part; part = part->next)
+	{
+		if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id)))
+		{
+			for(i = 0, offset = 0; i < part->num_parts; i++)
+			{
+				if (!part->parts[i].offset)
+				  part->parts[i].offset = offset;
+				else
+				  offset = part->parts[i].offset;
+				if (part->parts[i].size == SIZE_REMAINING)
+				  part->parts[i].size = master->size - offset;
+				if (offset + part->parts[i].size > master->size)
+				{
+					printk(KERN_WARNING ERRP 
+					       "%s: partitioning exceeds flash size, truncating\n",
+					       part->mtd_id);
+					part->parts[i].size = master->size - offset;
+					part->num_parts = i;
+				}
+				offset += part->parts[i].size;
+			}
+			*pparts = part->parts;
+			return part->num_parts;
+		}
+	}
+	return -EINVAL;
+}
+
+
+/* 
+ * This is the handler for our kernel parameter, called from 
+ * main.c::checksetup(). Note that we can not yet kmalloc() anything,
+ * so we only save the commandline for later processing.
+ */
+static int __init mtdpart_setup(char *s)
+{
+	cmdline = s;
+	return 1;
+}
+
+__setup("mtdparts=", mtdpart_setup);
+
+static struct mtd_part_parser cmdline_parser = {
+	.owner = THIS_MODULE,
+	.parse_fn = parse_cmdline_partitions,
+	.name = "cmdlinepart",
+};
+
+static int __init cmdline_parser_init(void)
+{
+	return register_mtd_parser(&cmdline_parser);
+}
+
+static void __exit cmdline_parser_exit(void)
+{
+	deregister_mtd_parser(&cmdline_parser);
+}
+
+module_init(cmdline_parser_init);
+module_exit(cmdline_parser_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
+MODULE_DESCRIPTION("Command line configuration of MTD partitions");
diff -Nru a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
--- a/drivers/mtd/devices/Kconfig	Tue Oct 29 17:16:55 2002
+++ b/drivers/mtd/devices/Kconfig	Wed May 28 08:56:01 2003
@@ -1,5 +1,5 @@
-# drivers/mtd/maps/Config.in
-# $Id: Config.in,v 1.5 2001/09/23 15:33:10 dwmw2 Exp $
+# drivers/mtd/maps/Kconfig
+# $Id: Kconfig,v 1.4 2003/05/28 15:18:54 dwmw2 Exp $
 
 menu "Self-contained MTD device drivers"
 	depends on MTD!=n
@@ -38,6 +38,12 @@
 	  is only really useful if you are developing on this driver or
 	  suspect a possible hardware or driver bug.  If unsure say N.
 
+config MTD_MS02NV
+	tristate "DEC MS02-NV NVRAM module support"
+	depends on CONFIG_DECSTATION
+	help
+	  Support for NVRAM module on DECstation.
+
 config MTD_SLRAM
 	tristate "Uncached system RAM"
 	depends on MTD
@@ -108,13 +114,6 @@
 
 comment "Disk-On-Chip Device Drivers"
 
-config MTD_DOC1000
-	tristate "M-Systems Disk-On-Chip 1000"
-	depends on MTD
-	help
-	  This provides an MTD device driver for the M-Systems DiskOnChip
-	  1000 devices, which are obsolete so you probably want to say 'N'.
-
 config MTD_DOC2000
 	tristate "M-Systems Disk-On-Chip 2000 and Millennium"
 	depends on MTD
@@ -148,10 +147,22 @@
 	  emulate a block device by using a kind of file system on the flash
 	  chips.
 
+config MTD_DOC2001PLUS
+	tristate "M-Systems Disk-On-Chip Millennium Plus"
+	depends on MTD
+	---help---
+	  This provides an MTD device driver for the M-Systems DiskOnChip
+	  Millennium Plus devices.
+
+	  If you use this device, you probably also want to enable the INFTL
+	  'Inverse NAND Flash Translation Layer' option below, which is used
+	  to emulate a block device by using a kind of file system on the 
+	  flash chips.
+
 config MTD_DOCPROBE
 	tristate
-	default m if MTD_DOC2001!=y && MTD_DOC2000!=y && (MTD_DOC2001=m || MTD_DOC2000=m)
-	default y if MTD_DOC2001=y || MTD_DOC2000=y
+	default m if MTD_DOC2001!=y && MTD_DOC2000!=y && MTD_DOC2001PLUS!=y && (MTD_DOC2001=m || MTD_DOC2000=m || MOD_DOC2001PLUS=m)
+	default y if MTD_DOC2001=y || MTD_DOC2000=y || MTD_DOC2001PLUS=y
 	help
 	  This isn't a real config option, it's derived.
 
@@ -200,7 +211,7 @@
 	  continue with probing if it is absent.  The signature will always be
 	  present for a DiskOnChip 2000 or a normal DiskOnChip Millennium.
 	  Only if you have overwritten the first block of a DiskOnChip
-	  Millennium will it be  absent.  Enable this option if you are using
+	  Millennium will it be absent.  Enable this option if you are using
 	  LinuxBIOS or if you need to recover a DiskOnChip Millennium on which
 	  you have managed to wipe the first block.
 
diff -Nru a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
--- a/drivers/mtd/devices/Makefile	Sat Dec 14 04:38:56 2002
+++ b/drivers/mtd/devices/Makefile	Wed May 28 08:01:02 2003
@@ -1,7 +1,7 @@
 #
 # linux/drivers/devices/Makefile
 #
-# $Id: Makefile,v 1.4 2001/06/26 21:10:05 spse Exp $
+# $Id: Makefile.common,v 1.3 2003/05/28 10:54:23 dwmw2 Exp $
 
 #                       *** BIG UGLY NOTE ***
 #
@@ -10,12 +10,13 @@
 # here where previously there was none.  We now have to ensure that
 # doc200[01].o are linked before docprobe.o
 
-obj-$(CONFIG_MTD_DOC1000)	+= doc1000.o
 obj-$(CONFIG_MTD_DOC2000)	+= doc2000.o
 obj-$(CONFIG_MTD_DOC2001)	+= doc2001.o
+obj-$(CONFIG_MTD_DOC2001PLUS)	+= doc2001plus.o
 obj-$(CONFIG_MTD_DOCPROBE)	+= docprobe.o docecc.o
 obj-$(CONFIG_MTD_SLRAM)		+= slram.o
 obj-$(CONFIG_MTD_PMC551)	+= pmc551.o
+obj-$(CONFIG_MTD_MS02NV)	+= ms02-nv.o
 obj-$(CONFIG_MTD_MTDRAM)	+= mtdram.o
 obj-$(CONFIG_MTD_LART)		+= lart.o
 obj-$(CONFIG_MTD_BLKMTD)	+= blkmtd.o
diff -Nru a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c
--- a/drivers/mtd/devices/doc2000.c	Tue Feb  5 07:26:32 2002
+++ b/drivers/mtd/devices/doc2000.c	Wed May 28 08:01:02 2003
@@ -4,7 +4,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2000.c,v 1.46 2001/10/02 15:05:13 dwmw2 Exp $
+ * $Id: doc2000.c,v 1.52 2003/05/20 21:03:07 dwmw2 Exp $
  */
 
 #include <linux/kernel.h>
@@ -22,7 +22,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ids.h>
 #include <linux/mtd/doc2000.h>
 
 #define DOC_SUPPORT_2000
@@ -54,9 +53,9 @@
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
 		     size_t *retlen, const u_char *buf);
 static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf, u_char *eccbuf);
+			size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-			 size_t *retlen, const u_char *buf, u_char *eccbuf);
+			 size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
 			size_t *retlen, u_char *buf);
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
@@ -97,12 +96,8 @@
 			DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
 			return -EIO;
 		}
-		if (need_resched()) {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(1);
-		}
-		else
-			udelay(1);
+		udelay(1);
+		cond_resched();
 	}
 
 	return 0;
@@ -320,7 +315,7 @@
 
 static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
 {
-	int mfr, id, i;
+	int mfr, id, i, j;
 	volatile char dummy;
 
 	/* Page in the required floor/chip */
@@ -378,12 +373,16 @@
 
 	/* Print and store the manufacturer and ID codes. */
 	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-		if (mfr == nand_flash_ids[i].manufacture_id &&
-		    id == nand_flash_ids[i].model_id) {
+		if (id == nand_flash_ids[i].id) {
+			/* Try to identify manufacturer */
+			for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
+				if (nand_manuf_ids[j].id == mfr)
+					break;
+			}	
 			printk(KERN_INFO
 			       "Flash chip found: Manufacturer ID: %2.2X, "
-			       "Chip ID: %2.2X (%s)\n", mfr, id,
-			       nand_flash_ids[i].name);
+			       "Chip ID: %2.2X (%s:%s)\n", mfr, id,
+			       nand_manuf_ids[j].name, nand_flash_ids[i].name);
 			if (!doc->mfr) {
 				doc->mfr = mfr;
 				doc->id = id;
@@ -391,7 +390,7 @@
 				    nand_flash_ids[i].chipshift;
 				doc->page256 = nand_flash_ids[i].page256;
 				doc->pageadrlen =
-				    nand_flash_ids[i].pageadrlen;
+				    nand_flash_ids[i].chipshift > 25 ? 3 : 2;
 				doc->erasesize =
 				    nand_flash_ids[i].erasesize;
 				return 1;
@@ -558,7 +557,7 @@
 	mtd->erasesize = 0;
 	mtd->oobblock = 512;
 	mtd->oobsize = 16;
-	mtd->module = THIS_MODULE;
+	mtd->owner = THIS_MODULE;
 	mtd->erase = doc_erase;
 	mtd->point = NULL;
 	mtd->unpoint = NULL;
@@ -597,11 +596,11 @@
 		    size_t * retlen, u_char * buf)
 {
 	/* Just a special case of doc_read_ecc */
-	return doc_read_ecc(mtd, from, len, retlen, buf, NULL);
+	return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
 }
 
 static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-			size_t * retlen, u_char * buf, u_char * eccbuf)
+			size_t * retlen, u_char * buf, u_char * eccbuf, int oobsel)
 {
 	struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
 	unsigned long docptr;
@@ -745,12 +744,12 @@
 		     size_t * retlen, const u_char * buf)
 {
 	char eccbuf[6];
-	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf);
+	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
 }
 
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
 			 size_t * retlen, const u_char * buf,
-			 u_char * eccbuf)
+			 u_char * eccbuf, int oobsel)
 {
 	struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
 	int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
diff -Nru a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c
--- a/drivers/mtd/devices/doc2001.c	Mon Feb  4 23:49:33 2002
+++ b/drivers/mtd/devices/doc2001.c	Wed May 28 08:01:02 2003
@@ -4,7 +4,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2001.c,v 1.35 2001/10/02 15:05:13 dwmw2 Exp $
+ * $Id: doc2001.c,v 1.40 2003/05/20 21:03:07 dwmw2 Exp $
  */
 
 #include <linux/kernel.h>
@@ -22,7 +22,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ids.h>
 #include <linux/mtd/doc2000.h>
 
 /* #define ECC_DEBUG */
@@ -38,9 +37,9 @@
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
 		     size_t *retlen, const u_char *buf);
 static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf, u_char *eccbuf);
+			size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-			 size_t *retlen, const u_char *buf, u_char *eccbuf);
+			 size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
 			size_t *retlen, u_char *buf);
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
@@ -182,7 +181,7 @@
 /* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */
 static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
 {
-	int mfr, id, i;
+	int mfr, id, i, j;
 	volatile char dummy;
 
 	/* Page in the required floor/chip
@@ -216,11 +215,15 @@
 
 	/* FIXME: to deal with multi-flash on multi-Millennium case more carefully */
 	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-		if (mfr == nand_flash_ids[i].manufacture_id &&
-		    id == nand_flash_ids[i].model_id) {
+		if ( id == nand_flash_ids[i].id) {
+			/* Try to identify manufacturer */
+			for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
+				if (nand_manuf_ids[j].id == mfr)
+					break;
+			}	
 			printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, "
-			       "Chip ID: %2.2X (%s)\n",
-			       mfr, id, nand_flash_ids[i].name);
+			       "Chip ID: %2.2X (%s:%s)\n",
+			       mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name);
 			doc->mfr = mfr;
 			doc->id = id;
 			doc->chipshift = nand_flash_ids[i].chipshift;
@@ -363,7 +366,7 @@
 
 	mtd->oobblock = 512;
 	mtd->oobsize = 16;
-	mtd->module = THIS_MODULE;
+	mtd->owner = THIS_MODULE;
 	mtd->erase = doc_erase;
 	mtd->point = NULL;
 	mtd->unpoint = NULL;
@@ -399,11 +402,11 @@
 		     size_t *retlen, u_char *buf)
 {
 	/* Just a special case of doc_read_ecc */
-	return doc_read_ecc(mtd, from, len, retlen, buf, NULL);
+	return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
 }
 
 static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-			 size_t *retlen, u_char *buf, u_char *eccbuf)
+			 size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel)
 {
 	int i, ret;
 	volatile char dummy;
@@ -525,11 +528,11 @@
 		      size_t *retlen, const u_char *buf)
 {
 	char eccbuf[6];
-	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf);
+	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
 }
 
 static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-			  size_t *retlen, const u_char *buf, u_char *eccbuf)
+			  size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel)
 {
 	int i,ret = 0;
 	volatile char dummy;
diff -Nru a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/devices/doc2001plus.c	Wed May 28 08:01:09 2003
@@ -0,0 +1,1120 @@
+/*
+ * Linux driver for Disk-On-Chip Millennium Plus
+ *
+ * (c) 2002-2003 Greg Ungerer <gerg@snapgear.com>
+ * (c) 2002-2003 SnapGear Inc
+ * (c) 1999 Machine Vision Holdings, Inc.
+ * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
+ *
+ * $Id: doc2001plus.c,v 1.4 2003/05/23 11:28:46 dwmw2 Exp $
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/doc2000.h>
+
+/* #define ECC_DEBUG */
+
+/* I have no idea why some DoC chips can not use memcop_form|to_io().
+ * This may be due to the different revisions of the ASIC controller built-in or
+ * simplily a QA/Bug issue. Who knows ?? If you have trouble, please uncomment
+ * this:*/
+#undef USE_MEMCPY
+
+static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
+		size_t *retlen, u_char *buf);
+static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
+		size_t *retlen, const u_char *buf);
+static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
+		size_t *retlen, u_char *buf, u_char *eccbuf,
+		struct nand_oobinfo *oobsel);
+static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
+		size_t *retlen, const u_char *buf, u_char *eccbuf,
+		struct nand_oobinfo *oobsel);
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
+		size_t *retlen, u_char *buf);
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
+		size_t *retlen, const u_char *buf);
+static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
+
+static struct mtd_info *docmilpluslist = NULL;
+
+
+/* Perform the required delay cycles by writing to the NOP register */
+static void DoC_Delay(unsigned long docptr, int cycles)
+{
+	int i;
+
+	for (i = 0; (i < cycles); i++)
+		WriteDOC(0, docptr, Mplus_NOP);
+}
+
+#define	CDSN_CTRL_FR_B_MASK	(CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
+
+/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
+static int _DoC_WaitReady(unsigned long docptr)
+{
+	unsigned int c = 0xffff;
+
+	DEBUG(MTD_DEBUG_LEVEL3,
+	      "_DoC_WaitReady called for out-of-line wait\n");
+
+	/* Out-of-line routine to wait for chip response */
+	while (((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) && --c)
+		;
+
+	if (c == 0)
+		DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
+
+	return (c == 0);
+}
+
+static inline int DoC_WaitReady(unsigned long docptr)
+{
+	/* This is inline, to optimise the common case, where it's ready instantly */
+	int ret = 0;
+
+	/* read form NOP register should be issued prior to the read from CDSNControl
+	   see Software Requirement 11.4 item 2. */
+	DoC_Delay(docptr, 4);
+
+	if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK)
+		/* Call the out-of-line routine to wait */
+		ret = _DoC_WaitReady(docptr);
+
+	return ret;
+}
+
+/* For some reason the Millennium Plus seems to occassionally put itself
+ * into reset mode. For me this happens randomly, with no pattern that I
+ * can detect. M-systems suggest always check this on any block level
+ * operation and setting to normal mode if in reset mode.
+ */
+static inline void DoC_CheckASIC(unsigned long docptr)
+{
+	/* Make sure the DoC is in normal mode */
+	if ((ReadDOC(docptr, Mplus_DOCControl) & DOC_MODE_NORMAL) == 0) {
+		WriteDOC((DOC_MODE_NORMAL | DOC_MODE_MDWREN), docptr, Mplus_DOCControl);
+		WriteDOC(~(DOC_MODE_NORMAL | DOC_MODE_MDWREN), docptr, Mplus_CtrlConfirm);
+	}
+}
+
+/* DoC_Command: Send a flash command to the flash chip through the Flash
+ * command register. Need 2 Write Pipeline Terminates to complete send.
+ */
+static inline void DoC_Command(unsigned long docptr, unsigned char command,
+			       unsigned char xtraflags)
+{
+	WriteDOC(command, docptr, Mplus_FlashCmd);
+	WriteDOC(command, docptr, Mplus_WritePipeTerm);
+	WriteDOC(command, docptr, Mplus_WritePipeTerm);
+}
+
+/* DoC_Address: Set the current address for the flash chip through the Flash
+ * Address register. Need 2 Write Pipeline Terminates to complete send.
+ */
+static inline void DoC_Address(struct DiskOnChip *doc, int numbytes,
+			       unsigned long ofs, unsigned char xtraflags1,
+			       unsigned char xtraflags2)
+{
+	unsigned long docptr = doc->virtadr;
+
+	/* Allow for possible Mill Plus internal flash interleaving */
+	ofs >>= doc->interleave;
+
+	switch (numbytes) {
+	case 1:
+		/* Send single byte, bits 0-7. */
+		WriteDOC(ofs & 0xff, docptr, Mplus_FlashAddress);
+		break;
+	case 2:
+		/* Send bits 9-16 followed by 17-23 */
+		WriteDOC((ofs >> 9)  & 0xff, docptr, Mplus_FlashAddress);
+		WriteDOC((ofs >> 17) & 0xff, docptr, Mplus_FlashAddress);
+		break;
+	case 3:
+		/* Send 0-7, 9-16, then 17-23 */
+		WriteDOC(ofs & 0xff, docptr, Mplus_FlashAddress);
+		WriteDOC((ofs >> 9)  & 0xff, docptr, Mplus_FlashAddress);
+		WriteDOC((ofs >> 17) & 0xff, docptr, Mplus_FlashAddress);
+		break;
+	default:
+		return;
+	}
+
+	WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
+	WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
+}
+
+/* DoC_SelectChip: Select a given flash chip within the current floor */
+static int DoC_SelectChip(unsigned long docptr, int chip)
+{
+	/* No choice for flash chip on Millennium Plus */
+	return 0;
+}
+
+/* DoC_SelectFloor: Select a given floor (bank of flash chips) */
+static int DoC_SelectFloor(unsigned long docptr, int floor)
+{
+	WriteDOC((floor & 0x3), docptr, Mplus_DeviceSelect);
+	return 0;
+}
+
+/*
+ * Translate the given offset into the appropriate command and offset.
+ * This does the mapping using the 16bit interleave layout defined by
+ * M-Systems, and looks like this for a sector pair:
+ *  +-----------+-------+-------+-------+--------------+---------+-----------+
+ *  | 0 --- 511 |512-517|518-519|520-521| 522 --- 1033 |1034-1039|1040 - 1055|
+ *  +-----------+-------+-------+-------+--------------+---------+-----------+
+ *  | Data 0    | ECC 0 |Flags0 |Flags1 | Data 1       |ECC 1    | OOB 1 + 2 |
+ *  +-----------+-------+-------+-------+--------------+---------+-----------+
+ */
+static unsigned int DoC_GetDataOffset(struct mtd_info *mtd, loff_t *from)
+{
+	unsigned int ofs = *from & 0x3ff;
+	unsigned int cmd;
+
+	if (ofs < 512) {
+		cmd = NAND_CMD_READ0;
+		ofs &= 0x1ff;
+	} else if (ofs < 1014) {
+		cmd = NAND_CMD_READ1;
+		ofs = (ofs & 0x1ff) + 10;
+	} else {
+		cmd = NAND_CMD_READOOB;
+		ofs = ofs - 1014;
+	}
+
+	*from = (*from & ~0x3ff) | ofs;
+	return cmd;
+}
+
+static unsigned int DoC_GetECCOffset(struct mtd_info *mtd, loff_t *from)
+{
+	unsigned int ofs, cmd;
+
+	if (*from & 0x200) {
+		cmd = NAND_CMD_READOOB;
+		ofs = 10 + (*from & 0xf);
+	} else {
+		cmd = NAND_CMD_READ1;
+		ofs = (*from & 0xf);
+	}
+
+	*from = (*from & ~0x3ff) | ofs;
+	return cmd;
+}
+
+static unsigned int DoC_GetFlagsOffset(struct mtd_info *mtd, loff_t *from)
+{
+	unsigned int ofs, cmd;
+
+	cmd = NAND_CMD_READ1;
+	ofs = (*from & 0x200) ? 8 : 6;
+	*from = (*from & ~0x3ff) | ofs;
+	return cmd;
+}
+
+static unsigned int DoC_GetHdrOffset(struct mtd_info *mtd, loff_t *from)
+{
+	unsigned int ofs, cmd;
+
+	cmd = NAND_CMD_READOOB;
+	ofs = (*from & 0x200) ? 24 : 16;
+	*from = (*from & ~0x3ff) | ofs;
+	return cmd;
+}
+
+static inline void MemReadDOC(unsigned long docptr, unsigned char *buf, int len)
+{
+#ifndef USE_MEMCPY
+	int i;
+	for (i = 0; i < len; i++)
+		buf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
+#else
+	memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len);
+#endif
+}
+
+static inline void MemWriteDOC(unsigned long docptr, unsigned char *buf, int len)
+{
+#ifndef USE_MEMCPY
+	int i;
+	for (i = 0; i < len; i++)
+		WriteDOC(buf[i], docptr, Mil_CDSN_IO + i);
+#else
+	memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);
+#endif
+}
+
+/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */
+static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
+{
+	int mfr, id, i, j;
+	volatile char dummy;
+	unsigned long docptr = doc->virtadr;
+
+	/* Page in the required floor/chip */
+	DoC_SelectFloor(docptr, floor);
+	DoC_SelectChip(docptr, chip);
+
+	/* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
+	WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
+
+	/* Reset the chip, see Software Requirement 11.4 item 1. */
+	DoC_Command(docptr, NAND_CMD_RESET, 0);
+	DoC_WaitReady(docptr);
+
+	/* Read the NAND chip ID: 1. Send ReadID command */ 
+	DoC_Command(docptr, NAND_CMD_READID, 0);
+
+	/* Read the NAND chip ID: 2. Send address byte zero */ 
+	DoC_Address(doc, 1, 0x00, 0, 0x00);
+
+	WriteDOC(0, docptr, Mplus_FlashControl);
+	DoC_WaitReady(docptr);
+
+	/* Read the manufacturer and device id codes of the flash device through
+	   CDSN IO register see Software Requirement 11.4 item 5.*/
+	dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
+	dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
+
+	mfr = ReadDOC(docptr, Mil_CDSN_IO);
+	dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
+
+	id  = ReadDOC(docptr, Mil_CDSN_IO);
+	dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
+
+	dummy = ReadDOC(docptr, Mplus_LastDataRead);
+	dummy = ReadDOC(docptr, Mplus_LastDataRead);
+
+	/* Disable flash internally */
+	WriteDOC(0, docptr, Mplus_FlashSelect);
+
+	/* No response - return failure */
+	if (mfr == 0xff || mfr == 0)
+		return 0;
+
+	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
+		if (id == nand_flash_ids[i].id) {
+			/* Try to identify manufacturer */
+			for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
+				if (nand_manuf_ids[j].id == mfr)
+					break;
+			}
+			printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, "
+			       "Chip ID: %2.2X (%s:%s)\n", mfr, id,
+			       nand_manuf_ids[j].name, nand_flash_ids[i].name);
+			doc->mfr = mfr;
+			doc->id = id;
+			doc->interleave = 0;
+			if (doc->ChipID == DOC_ChipID_DocMilPlus32)
+				doc->interleave = 1;
+			doc->chipshift = nand_flash_ids[i].chipshift;
+			doc->erasesize = nand_flash_ids[i].erasesize << doc->interleave;
+			break;
+		}
+	}
+
+	if (nand_flash_ids[i].name == NULL)
+		return 0;
+	return 1;
+}
+
+/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
+static void DoC_ScanChips(struct DiskOnChip *this)
+{
+	int floor, chip;
+	int numchips[MAX_FLOORS_MPLUS];
+	int ret;
+
+	this->numchips = 0;
+	this->mfr = 0;
+	this->id = 0;
+
+	/* For each floor, find the number of valid chips it contains */
+	for (floor = 0,ret = 1; floor < MAX_FLOORS_MPLUS; floor++) {
+		numchips[floor] = 0;
+		for (chip = 0; chip < MAX_CHIPS_MPLUS && ret != 0; chip++) {
+			ret = DoC_IdentChip(this, floor, chip);
+			if (ret) {
+				numchips[floor]++;
+				this->numchips++;
+			}
+		}
+	}
+	/* If there are none at all that we recognise, bail */
+	if (!this->numchips) {
+		printk("No flash chips recognised.\n");
+		return;
+	}
+
+	/* Allocate an array to hold the information for each chip */
+	this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL);
+	if (!this->chips){
+		printk("MTD: No memory for allocating chip info structures\n");
+		return;
+	}
+
+	/* Fill out the chip array with {floor, chipno} for each 
+	 * detected chip in the device. */
+	for (floor = 0, ret = 0; floor < MAX_FLOORS_MPLUS; floor++) {
+		for (chip = 0 ; chip < numchips[floor] ; chip++) {
+			this->chips[ret].floor = floor;
+			this->chips[ret].chip = chip;
+			this->chips[ret].curadr = 0;
+			this->chips[ret].curmode = 0x50;
+			ret++;
+		}
+	}
+
+	/* Calculate and print the total size of the device */
+	this->totlen = this->numchips * (1 << this->chipshift);
+	printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld MiB\n",
+	       this->numchips ,this->totlen >> 20);
+}
+
+static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
+{
+	int tmp1, tmp2, retval;
+
+	if (doc1->physadr == doc2->physadr)
+		return 1;
+
+	/* Use the alias resolution register which was set aside for this
+	 * purpose. If it's value is the same on both chips, they might
+	 * be the same chip, and we write to one and check for a change in
+	 * the other. It's unclear if this register is usuable in the
+	 * DoC 2000 (it's in the Millennium docs), but it seems to work. */
+	tmp1 = ReadDOC(doc1->virtadr, Mplus_AliasResolution);
+	tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution);
+	if (tmp1 != tmp2)
+		return 0;
+	
+	WriteDOC((tmp1+1) % 0xff, doc1->virtadr, Mplus_AliasResolution);
+	tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution);
+	if (tmp2 == (tmp1+1) % 0xff)
+		retval = 1;
+	else
+		retval = 0;
+
+	/* Restore register contents.  May not be necessary, but do it just to
+	 * be safe. */
+	WriteDOC(tmp1, doc1->virtadr, Mplus_AliasResolution);
+
+	return retval;
+}
+
+static const char im_name[] = "DoCMilPlus_init";
+
+/* This routine is made available to other mtd code via
+ * inter_module_register.  It must only be accessed through
+ * inter_module_get which will bump the use count of this module.  The
+ * addresses passed back in mtd are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put.  Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
+static void DoCMilPlus_init(struct mtd_info *mtd)
+{
+	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+	struct DiskOnChip *old = NULL;
+
+	/* We must avoid being called twice for the same device. */
+	if (docmilpluslist)
+		old = (struct DiskOnChip *)docmilpluslist->priv;
+
+	while (old) {
+		if (DoCMilPlus_is_alias(this, old)) {
+			printk(KERN_NOTICE "Ignoring DiskOnChip Millennium "
+				"Plus at 0x%lX - already configured\n",
+				this->physadr);
+			iounmap((void *)this->virtadr);
+			kfree(mtd);
+			return;
+		}
+		if (old->nextdoc)
+			old = (struct DiskOnChip *)old->nextdoc->priv;
+		else
+			old = NULL;
+	}
+
+	mtd->name = "DiskOnChip Millennium Plus";
+	printk(KERN_NOTICE "DiskOnChip Millennium Plus found at "
+		"address 0x%lX\n", this->physadr);
+
+	mtd->type = MTD_NANDFLASH;
+	mtd->flags = MTD_CAP_NANDFLASH;
+	mtd->size = 0;
+
+	mtd->erasesize = 0;
+	mtd->oobblock = 512;
+	mtd->oobsize = 16;
+	mtd->owner = THIS_MODULE;
+	mtd->erase = doc_erase;
+	mtd->point = NULL;
+	mtd->unpoint = NULL;
+	mtd->read = doc_read;
+	mtd->write = doc_write;
+	mtd->read_ecc = doc_read_ecc;
+	mtd->write_ecc = doc_write_ecc;
+	mtd->read_oob = doc_read_oob;
+	mtd->write_oob = doc_write_oob;
+	mtd->sync = NULL;
+
+	this->totlen = 0;
+	this->numchips = 0;
+	this->curfloor = -1;
+	this->curchip = -1;
+
+	/* Ident all the chips present. */
+	DoC_ScanChips(this);
+
+	if (!this->totlen) {
+		kfree(mtd);
+		iounmap((void *)this->virtadr);
+	} else {
+		this->nextdoc = docmilpluslist;
+		docmilpluslist = mtd;
+		mtd->size  = this->totlen;
+		mtd->erasesize = this->erasesize;
+		add_mtd_device(mtd);
+		return;
+	}
+}
+
+#if 0
+static int doc_dumpblk(struct mtd_info *mtd, loff_t from)
+{
+	int i;
+	loff_t fofs;
+	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+	unsigned long docptr = this->virtadr;
+	struct Nand *mychip = &this->chips[from >> (this->chipshift)];
+	unsigned char *bp, buf[1056];
+	char c[32];
+
+	from &= ~0x3ff;
+
+	/* Don't allow read past end of device */
+	if (from >= this->totlen)
+		return -EINVAL;
+
+	DoC_CheckASIC(docptr);
+
+	/* Find the chip which is to be used and select it */
+	if (this->curfloor != mychip->floor) {
+		DoC_SelectFloor(docptr, mychip->floor);
+		DoC_SelectChip(docptr, mychip->chip);
+	} else if (this->curchip != mychip->chip) {
+		DoC_SelectChip(docptr, mychip->chip);
+	}
+	this->curfloor = mychip->floor;
+	this->curchip = mychip->chip;
+
+	/* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
+	WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
+
+	/* Reset the chip, see Software Requirement 11.4 item 1. */
+	DoC_Command(docptr, NAND_CMD_RESET, 0);
+	DoC_WaitReady(docptr);
+
+	fofs = from;
+	DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0);
+	DoC_Address(this, 3, fofs, 0, 0x00);
+	WriteDOC(0, docptr, Mplus_FlashControl);
+	DoC_WaitReady(docptr);
+
+	/* disable the ECC engine */
+	WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
+
+	ReadDOC(docptr, Mplus_ReadPipeInit);
+	ReadDOC(docptr, Mplus_ReadPipeInit);
+
+	/* Read the data via the internal pipeline through CDSN IO
+	   register, see Pipelined Read Operations 11.3 */
+	MemReadDOC(docptr, buf, 1054);
+	buf[1054] = ReadDOC(docptr, Mplus_LastDataRead);
+	buf[1055] = ReadDOC(docptr, Mplus_LastDataRead);
+
+	memset(&c[0], 0, sizeof(c));
+	printk("DUMP OFFSET=%x:\n", (int)from);
+
+        for (i = 0, bp = &buf[0]; (i < 1056); i++) {
+                if ((i % 16) == 0)
+                        printk("%08x: ", i);
+                printk(" %02x", *bp);
+                c[(i & 0xf)] = ((*bp >= 0x20) && (*bp <= 0x7f)) ? *bp : '.';
+                bp++;
+                if (((i + 1) % 16) == 0)
+                        printk("    %s\n", c);
+        }
+	printk("\n");
+
+	/* Disable flash internally */
+	WriteDOC(0, docptr, Mplus_FlashSelect);
+
+	return 0;
+}
+#endif
+
+static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
+		    size_t *retlen, u_char *buf)
+{
+	/* Just a special case of doc_read_ecc */
+	return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
+}
+
+static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
+			size_t *retlen, u_char *buf, u_char *eccbuf,
+			struct nand_oobinfo *oobsel)
+{
+	int ret, i;
+	volatile char dummy;
+	loff_t fofs;
+	unsigned char syndrome[6];
+	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+	unsigned long docptr = this->virtadr;
+	struct Nand *mychip = &this->chips[from >> (this->chipshift)];
+
+	/* Don't allow read past end of device */
+	if (from >= this->totlen)
+		return -EINVAL;
+
+	/* Don't allow a single read to cross a 512-byte block boundary */
+	if (from + len > ((from | 0x1ff) + 1)) 
+		len = ((from | 0x1ff) + 1) - from;
+
+	DoC_CheckASIC(docptr);
+
+	/* Find the chip which is to be used and select it */
+	if (this->curfloor != mychip->floor) {
+		DoC_SelectFloor(docptr, mychip->floor);
+		DoC_SelectChip(docptr, mychip->chip);
+	} else if (this->curchip != mychip->chip) {
+		DoC_SelectChip(docptr, mychip->chip);
+	}
+	this->curfloor = mychip->floor;
+	this->curchip = mychip->chip;
+
+	/* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
+	WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
+
+	/* Reset the chip, see Software Requirement 11.4 item 1. */
+	DoC_Command(docptr, NAND_CMD_RESET, 0);
+	DoC_WaitReady(docptr);
+
+	fofs = from;
+	DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0);
+	DoC_Address(this, 3, fofs, 0, 0x00);
+	WriteDOC(0, docptr, Mplus_FlashControl);
+	DoC_WaitReady(docptr);
+
+	if (eccbuf) {
+		/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
+		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
+		WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
+	} else {
+		/* disable the ECC engine */
+		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
+	}
+
+	/* Let the caller know we completed it */
+	*retlen = len;
+        ret = 0;
+
+	ReadDOC(docptr, Mplus_ReadPipeInit);
+	ReadDOC(docptr, Mplus_ReadPipeInit);
+
+	if (eccbuf) {
+		/* Read the data via the internal pipeline through CDSN IO
+		   register, see Pipelined Read Operations 11.3 */
+		MemReadDOC(docptr, buf, len);
+
+		/* Read the ECC data following raw data */
+		MemReadDOC(docptr, eccbuf, 4);
+		eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead);
+		eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead);
+
+		/* Flush the pipeline */
+		dummy = ReadDOC(docptr, Mplus_ECCConf);
+		dummy = ReadDOC(docptr, Mplus_ECCConf);
+
+		/* Check the ECC Status */
+		if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) {
+                        int nb_errors;
+			/* There was an ECC error */
+#ifdef ECC_DEBUG
+			printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
+#endif
+			/* Read the ECC syndrom through the DiskOnChip ECC logic.
+			   These syndrome will be all ZERO when there is no error */
+			for (i = 0; i < 6; i++)
+				syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
+
+                        nb_errors = doc_decode_ecc(buf, syndrome);
+#ifdef ECC_DEBUG
+			printk("ECC Errors corrected: %x\n", nb_errors);
+#endif
+                        if (nb_errors < 0) {
+				/* We return error, but have actually done the read. Not that
+				   this can be told to user-space, via sys_read(), but at least
+				   MTD-aware stuff can know about it by checking *retlen */
+#ifdef ECC_DEBUG
+			printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n",
+				__FILE__, __LINE__, (int)from);
+			printk("        syndrome= %02x:%02x:%02x:%02x:%02x:"
+				"%02x\n",
+				syndrome[0], syndrome[1], syndrome[2],
+				syndrome[3], syndrome[4], syndrome[5]);
+			printk("          eccbuf= %02x:%02x:%02x:%02x:%02x:"
+				"%02x\n",
+				eccbuf[0], eccbuf[1], eccbuf[2],
+				eccbuf[3], eccbuf[4], eccbuf[5]);
+#endif
+				ret = -EIO;
+                        }
+		}
+
+#ifdef PSYCHO_DEBUG
+		printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+		       (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+		       eccbuf[4], eccbuf[5]);
+#endif
+
+		/* disable the ECC engine */
+		WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf);
+	} else {
+		/* Read the data via the internal pipeline through CDSN IO
+		   register, see Pipelined Read Operations 11.3 */
+		MemReadDOC(docptr, buf, len-2);
+		buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead);
+		buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead);
+	}
+
+	/* Disable flash internally */
+	WriteDOC(0, docptr, Mplus_FlashSelect);
+
+	return ret;
+}
+
+static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
+		     size_t *retlen, const u_char *buf)
+{
+	char eccbuf[6];
+	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
+}
+
+static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
+			 size_t *retlen, const u_char *buf, u_char *eccbuf,
+			 struct nand_oobinfo *oobsel)
+{
+	int i, before, ret = 0;
+	loff_t fto;
+	volatile char dummy;
+	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+	unsigned long docptr = this->virtadr;
+	struct Nand *mychip = &this->chips[to >> (this->chipshift)];
+
+	/* Don't allow write past end of device */
+	if (to >= this->totlen)
+		return -EINVAL;
+
+	/* Don't allow writes which aren't exactly one block (512 bytes) */
+	if ((to & 0x1ff) || (len != 0x200))
+		return -EINVAL;
+
+	/* Determine position of OOB flags, before or after data */
+	before = to & 0x200;
+
+	DoC_CheckASIC(docptr);
+
+	/* Find the chip which is to be used and select it */
+	if (this->curfloor != mychip->floor) {
+		DoC_SelectFloor(docptr, mychip->floor);
+		DoC_SelectChip(docptr, mychip->chip);
+	} else if (this->curchip != mychip->chip) {
+		DoC_SelectChip(docptr, mychip->chip);
+	}
+	this->curfloor = mychip->floor;
+	this->curchip = mychip->chip;
+
+	/* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
+	WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect);
+
+	/* Reset the chip, see Software Requirement 11.4 item 1. */
+	DoC_Command(docptr, NAND_CMD_RESET, 0);
+	DoC_WaitReady(docptr);
+
+	/* Set device to appropriate plane of flash */
+	fto = to;
+	WriteDOC(DoC_GetDataOffset(mtd, &fto), docptr, Mplus_FlashCmd);
+
+	/* On interleaved devices the flags for 2nd half 512 are before data */
+	if (eccbuf && before)
+		fto -= 2;
+
+	/* issue the Serial Data In command to initial the Page Program process */
+	DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
+	DoC_Address(this, 3, fto, 0x00, 0x00);
+
+	/* Disable the ECC engine */
+	WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
+
+	if (eccbuf) {
+		if (before) {
+			/* Write the block status BLOCK_USED (0x5555) */
+			WriteDOC(0x55, docptr, Mil_CDSN_IO);
+			WriteDOC(0x55, docptr, Mil_CDSN_IO);
+		}
+
+		/* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
+		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
+	}
+
+	MemWriteDOC(docptr, (unsigned char *) buf, len);
+
+	if (eccbuf) {
+		/* Write ECC data to flash, the ECC info is generated by
+		   the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */
+		DoC_Delay(docptr, 3);
+
+		/* Read the ECC data through the DiskOnChip ECC logic */
+		for (i = 0; i < 6; i++)
+			eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
+
+		/* disable the ECC engine */
+		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
+
+		/* Write the ECC data to flash */
+		MemWriteDOC(docptr, eccbuf, 6);
+
+		if (!before) {
+			/* Write the block status BLOCK_USED (0x5555) */
+			WriteDOC(0x55, docptr, Mil_CDSN_IO+6);
+			WriteDOC(0x55, docptr, Mil_CDSN_IO+7);
+		}
+
+#ifdef PSYCHO_DEBUG
+		printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+		       (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+		       eccbuf[4], eccbuf[5]);
+#endif
+	}
+
+	WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
+	WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
+
+	/* Commit the Page Program command and wait for ready
+	   see Software Requirement 11.4 item 1.*/
+	DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00);
+	DoC_WaitReady(docptr);
+
+	/* Read the status of the flash device through CDSN IO register
+	   see Software Requirement 11.4 item 5.*/
+	DoC_Command(docptr, NAND_CMD_STATUS, 0);
+	dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
+	dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
+	DoC_Delay(docptr, 2);
+	if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) {
+		printk("MTD: Error 0x%x programming at 0x%x\n", dummy, (int)to);
+		/* Error in programming
+		   FIXME: implement Bad Block Replacement (in nftl.c ??) */
+		*retlen = 0;
+		ret = -EIO;
+	}
+	dummy = ReadDOC(docptr, Mplus_LastDataRead);
+
+	/* Disable flash internally */
+	WriteDOC(0, docptr, Mplus_FlashSelect);
+
+	/* Let the caller know we completed it */
+	*retlen = len;
+
+	return ret;
+}
+
+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
+			size_t *retlen, u_char *buf)
+{
+	loff_t fofs, base;
+	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+	unsigned long docptr = this->virtadr;
+	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
+	size_t i, size, got, want;
+
+	DoC_CheckASIC(docptr);
+
+	/* Find the chip which is to be used and select it */
+	if (this->curfloor != mychip->floor) {
+		DoC_SelectFloor(docptr, mychip->floor);
+		DoC_SelectChip(docptr, mychip->chip);
+	} else if (this->curchip != mychip->chip) {
+		DoC_SelectChip(docptr, mychip->chip);
+	}
+	this->curfloor = mychip->floor;
+	this->curchip = mychip->chip;
+
+	/* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
+	WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
+
+	/* disable the ECC engine */
+	WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
+	DoC_WaitReady(docptr);
+
+	/* Maximum of 16 bytes in the OOB region, so limit read to that */
+	if (len > 16)
+		len = 16;
+	got = 0;
+	want = len;
+
+	for (i = 0; ((i < 3) && (want > 0)); i++) {
+		/* Figure out which region we are accessing... */
+		fofs = ofs;
+		base = ofs & 0xf;
+		if (base < 6) {
+			DoC_Command(docptr, DoC_GetECCOffset(mtd, &fofs), 0);
+			size = 6 - base;
+		} else if (base < 8) {
+			DoC_Command(docptr, DoC_GetFlagsOffset(mtd, &fofs), 0);
+			size = 8 - base;
+		} else {
+			DoC_Command(docptr, DoC_GetHdrOffset(mtd, &fofs), 0);
+			size = 16 - base;
+		}
+		if (size > want)
+			size = want;
+
+		/* Issue read command */
+		DoC_Address(this, 3, fofs, 0, 0x00);
+		WriteDOC(0, docptr, Mplus_FlashControl);
+		DoC_WaitReady(docptr);
+
+		ReadDOC(docptr, Mplus_ReadPipeInit);
+		ReadDOC(docptr, Mplus_ReadPipeInit);
+		MemReadDOC(docptr, &buf[got], size - 2);
+		buf[got + size - 2] = ReadDOC(docptr, Mplus_LastDataRead);
+		buf[got + size - 1] = ReadDOC(docptr, Mplus_LastDataRead);
+
+		ofs += size;
+		got += size;
+		want -= size;
+	}
+
+	/* Disable flash internally */
+	WriteDOC(0, docptr, Mplus_FlashSelect);
+
+	*retlen = len;
+	return 0;
+}
+
+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
+			 size_t *retlen, const u_char *buf)
+{
+	volatile char dummy;
+	loff_t fofs, base;
+	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+	unsigned long docptr = this->virtadr;
+	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
+	size_t i, size, got, want;
+	int ret = 0;
+
+	DoC_CheckASIC(docptr);
+
+	/* Find the chip which is to be used and select it */
+	if (this->curfloor != mychip->floor) {
+		DoC_SelectFloor(docptr, mychip->floor);
+		DoC_SelectChip(docptr, mychip->chip);
+	} else if (this->curchip != mychip->chip) {
+		DoC_SelectChip(docptr, mychip->chip);
+	}
+	this->curfloor = mychip->floor;
+	this->curchip = mychip->chip;
+
+	/* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
+	WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect);
+
+
+	/* Maximum of 16 bytes in the OOB region, so limit write to that */
+	if (len > 16)
+		len = 16;
+	got = 0;
+	want = len;
+
+	for (i = 0; ((i < 3) && (want > 0)); i++) {
+		/* Reset the chip, see Software Requirement 11.4 item 1. */
+		DoC_Command(docptr, NAND_CMD_RESET, 0);
+		DoC_WaitReady(docptr);
+
+		/* Figure out which region we are accessing... */
+		fofs = ofs;
+		base = ofs & 0x0f;
+		if (base < 6) {
+			WriteDOC(DoC_GetECCOffset(mtd, &fofs), docptr, Mplus_FlashCmd);
+			size = 6 - base;
+		} else if (base < 8) {
+			WriteDOC(DoC_GetFlagsOffset(mtd, &fofs), docptr, Mplus_FlashCmd);
+			size = 8 - base;
+		} else {
+			WriteDOC(DoC_GetHdrOffset(mtd, &fofs), docptr, Mplus_FlashCmd);
+			size = 16 - base;
+		}
+		if (size > want)
+			size = want;
+
+		/* Issue the Serial Data In command to initial the Page Program process */
+		DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
+		DoC_Address(this, 3, fofs, 0, 0x00);
+
+		/* Disable the ECC engine */
+		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
+
+		/* Write the data via the internal pipeline through CDSN IO
+		   register, see Pipelined Write Operations 11.2 */
+		MemWriteDOC(docptr, (unsigned char *) &buf[got], size);
+		WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
+		WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
+
+		/* Commit the Page Program command and wait for ready
+	 	   see Software Requirement 11.4 item 1.*/
+		DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00);
+		DoC_WaitReady(docptr);
+
+		/* Read the status of the flash device through CDSN IO register
+		   see Software Requirement 11.4 item 5.*/
+		DoC_Command(docptr, NAND_CMD_STATUS, 0x00);
+		dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
+		dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
+		DoC_Delay(docptr, 2);
+		if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) {
+			printk("MTD: Error 0x%x programming oob at 0x%x\n",
+				dummy, (int)ofs);
+			/* FIXME: implement Bad Block Replacement */
+			*retlen = 0;
+			ret = -EIO;
+		}
+		dummy = ReadDOC(docptr, Mplus_LastDataRead);
+
+		ofs += size;
+		got += size;
+		want -= size;
+	}
+
+	/* Disable flash internally */
+	WriteDOC(0, docptr, Mplus_FlashSelect);
+
+	*retlen = len;
+	return ret;
+}
+
+int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	volatile char dummy;
+	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
+	__u32 ofs = instr->addr;
+	__u32 len = instr->len;
+	unsigned long docptr = this->virtadr;
+	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
+
+	DoC_CheckASIC(docptr);
+
+	if (len != mtd->erasesize) 
+		printk(KERN_WARNING "MTD: Erase not right size (%x != %x)n",
+		       len, mtd->erasesize);
+
+	/* Find the chip which is to be used and select it */
+	if (this->curfloor != mychip->floor) {
+		DoC_SelectFloor(docptr, mychip->floor);
+		DoC_SelectChip(docptr, mychip->chip);
+	} else if (this->curchip != mychip->chip) {
+		DoC_SelectChip(docptr, mychip->chip);
+	}
+	this->curfloor = mychip->floor;
+	this->curchip = mychip->chip;
+
+	instr->state = MTD_ERASE_PENDING;
+
+	/* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
+	WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect);
+
+	DoC_Command(docptr, NAND_CMD_RESET, 0x00);
+	DoC_WaitReady(docptr);
+
+	DoC_Command(docptr, NAND_CMD_ERASE1, 0);
+	DoC_Address(this, 2, ofs, 0, 0x00);
+	DoC_Command(docptr, NAND_CMD_ERASE2, 0);
+	DoC_WaitReady(docptr);
+	instr->state = MTD_ERASING;
+
+	/* Read the status of the flash device through CDSN IO register
+	   see Software Requirement 11.4 item 5. */
+	DoC_Command(docptr, NAND_CMD_STATUS, 0);
+	dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
+	dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
+	if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) {
+		printk("MTD: Error 0x%x erasing at 0x%x\n", dummy, ofs);
+		/* FIXME: implement Bad Block Replacement (in nftl.c ??) */
+		instr->state = MTD_ERASE_FAILED;
+	} else {
+		instr->state = MTD_ERASE_DONE;
+	}
+	dummy = ReadDOC(docptr, Mplus_LastDataRead);
+
+	/* Disable flash internally */
+	WriteDOC(0, docptr, Mplus_FlashSelect);
+
+	if (instr->callback) 
+		instr->callback(instr);
+
+	return 0;
+}
+
+/****************************************************************************
+ *
+ * Module stuff
+ *
+ ****************************************************************************/
+
+int __init init_doc2001plus(void)
+{
+	inter_module_register(im_name, THIS_MODULE, &DoCMilPlus_init);
+	return 0;
+}
+
+static void __exit cleanup_doc2001plus(void)
+{
+	struct mtd_info *mtd;
+	struct DiskOnChip *this;
+
+	while ((mtd=docmilpluslist)) {
+		this = (struct DiskOnChip *)mtd->priv;
+		docmilpluslist = this->nextdoc;
+			
+		del_mtd_device(mtd);
+			
+		iounmap((void *)this->virtadr);
+		kfree(this->chips);
+		kfree(mtd);
+	}
+	inter_module_unregister(im_name);
+}
+
+module_exit(cleanup_doc2001plus);
+module_init(init_doc2001plus);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com> et al.");
+MODULE_DESCRIPTION("Driver for DiskOnChip Millennium Plus");
diff -Nru a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c
--- a/drivers/mtd/devices/docecc.c	Mon Feb  4 23:49:33 2002
+++ b/drivers/mtd/devices/docecc.c	Wed May 28 08:01:02 2003
@@ -7,7 +7,7 @@
  * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
  * Copyright (C) 2000 Netgem S.A.
  *
- * $Id: docecc.c,v 1.4 2001/10/02 15:05:13 dwmw2 Exp $
+ * $Id: docecc.c,v 1.5 2003/05/21 15:15:06 dwmw2 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
@@ -518,6 +518,8 @@
     kfree(Index_of);
     return nb_errors;
 }
+
+EXPORT_SYMBOL_GPL(doc_decode_ecc);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Fabrice Bellard <fabrice.bellard@netgem.com>");
diff -Nru a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c
--- a/drivers/mtd/devices/docprobe.c	Mon Feb  4 23:49:33 2002
+++ b/drivers/mtd/devices/docprobe.c	Wed May 28 08:01:02 2003
@@ -1,9 +1,10 @@
 
 /* Linux driver for Disk-On-Chip devices			*/
 /* Probe routines common to all DoC devices			*/
-/* (c) 1999 Machine Vision Holdings, Inc.			*/
-/* Author: David Woodhouse <dwmw2@infradead.org>		*/
-/* $Id: docprobe.c,v 1.30 2001/10/02 15:05:13 dwmw2 Exp $	*/
+/* (C) 1999 Machine Vision Holdings, Inc.			*/
+/* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>		*/
+
+/* $Id: docprobe.c,v 1.36 2003/05/23 11:29:34 dwmw2 Exp $	*/
 
 
 
@@ -30,14 +31,12 @@
 /* DOC_SINGLE_DRIVER:
    Millennium driver has been merged into DOC2000 driver.
 
-   The newly-merged driver doesn't appear to work for writing. It's the
-   same with the DiskOnChip 2000 and the Millennium. If you have a 
-   Millennium and you want write support to work, remove the definition
-   of DOC_SINGLE_DRIVER below to use the old doc2001-specific driver.
-
-   Otherwise, it's left on in the hope that it'll annoy someone with
-   a Millennium enough that they go through and work out what the 
-   difference is :)
+   The old Millennium-only driver has been retained just in case there
+   are problems with the new code. If the combined driver doesn't work
+   for you, you can try the old one by undefining DOC_SINGLE_DRIVER 
+   below and also enabling it in your configuration. If this fixes the
+   problems, please send a report to the MTD mailing list at 
+   <linux-mtd@lists.infradead.org>.
 */
 #define DOC_SINGLE_DRIVER
 
@@ -46,18 +45,15 @@
 #include <linux/module.h>
 #include <asm/errno.h>
 #include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/miscdevice.h>
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/types.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/doc2000.h>
+#include <linux/mtd/compatmac.h>
 
 /* Where to look for the devices? */
 #ifndef CONFIG_MTD_DOCPROBE_ADDRESS
@@ -67,7 +63,7 @@
 
 static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS;
 MODULE_PARM(doc_config_location, "l");
-
+MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
 
 static unsigned long __initdata doc_locations[] = {
 #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
@@ -84,21 +80,24 @@
 	0xe0000, 0xe2000, 0xe4000, 0xe6000, 
 	0xe8000, 0xea000, 0xec000, 0xee000,
 #endif /*  CONFIG_MTD_DOCPROBE_HIGH */
-#elif defined(__ppc__)
+#elif defined(__PPC__)
 	0xe4000000,
 #elif defined(CONFIG_MOMENCO_OCELOT)
 	0x2f000000,
-#else
+        0xff000000,
+#elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C)
+        0xff000000,
+##else
 #warning Unknown architecture for DiskOnChip. No default probe locations defined
 #endif
-	0 };
+	0xffffffff };
 
 /* doccheck: Probe a given memory window to see if there's a DiskOnChip present */
 
 static inline int __init doccheck(unsigned long potential, unsigned long physadr)
 {
 	unsigned long window=potential;
-	unsigned char tmp, ChipID;
+	unsigned char tmp, tmpb, tmpc, ChipID;
 #ifndef DOC_PASSIVE_PROBE
 	unsigned char tmp2;
 #endif
@@ -141,19 +140,65 @@
 	switch (ChipID) {
 	case DOC_ChipID_Doc2k:
 		/* Check the TOGGLE bit in the ECC register */
-		tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
-		if ((ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT) != tmp)
+		tmp  = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
+		tmpb = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
+		tmpc = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT;
+		if (tmp != tmpb && tmp == tmpc)
 				return ChipID;
 		break;
 		
 	case DOC_ChipID_DocMil:
 		/* Check the TOGGLE bit in the ECC register */
-		tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
-		if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp)
+		tmp  = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
+		tmpb = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
+		tmpc = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
+		if (tmp != tmpb && tmp == tmpc)
 				return ChipID;
 		break;
 		
+	case DOC_ChipID_DocMilPlus16:
+	case DOC_ChipID_DocMilPlus32:
+	case 0:
+		/* Possible Millennium+, need to do more checks */
+#ifndef DOC_PASSIVE_PROBE
+		/* Possibly release from power down mode */
+		for (tmp = 0; (tmp < 4); tmp++)
+			ReadDOC(window, Mplus_Power);
+
+		/* Reset the DiskOnChip ASIC */
+		tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
+			DOC_MODE_BDECT;
+		WriteDOC(tmp, window, Mplus_DOCControl);
+		WriteDOC(~tmp, window, Mplus_CtrlConfirm);
+	
+		mdelay(1);
+		/* Enable the DiskOnChip ASIC */
+		tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
+			DOC_MODE_BDECT;
+		WriteDOC(tmp, window, Mplus_DOCControl);
+		WriteDOC(~tmp, window, Mplus_CtrlConfirm);
+		mdelay(1);
+#endif /* !DOC_PASSIVE_PROBE */	
+
+		ChipID = ReadDOC(window, ChipID);
+
+		switch (ChipID) {
+		case DOC_ChipID_DocMilPlus16:
+		case DOC_ChipID_DocMilPlus32:
+			/* Check the TOGGLE bit in the toggle register */
+			tmp  = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
+			tmpb = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
+			tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
+			if (tmp != tmpb && tmp == tmpc)
+					return ChipID;
+			break;
+		default:
+			break;
+		}
+		/* FALL TRHU */
+
 	default:
+
 #ifndef CONFIG_MTD_DOCPROBE_55AA
 		printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
 		       ChipID, physadr);
@@ -233,6 +278,13 @@
 			im_modname = "doc2001";
 #endif /* DOC_SINGLE_DRIVER */
 			break;
+
+		case DOC_ChipID_DocMilPlus16:
+		case DOC_ChipID_DocMilPlus32:
+			name="MillenniumPlus";
+			im_funcname = "DoCMilPlus_init";
+			im_modname = "doc2001plus";
+			break;
 		}
 
 		if (im_funcname)
@@ -244,6 +296,7 @@
 			return;
 		}
 		printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr);
+		kfree(mtd);
 	}
 	iounmap((void *)docptr);
 }
@@ -263,7 +316,7 @@
 		printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
 		DoC_Probe(doc_config_location);
 	} else {
-		for (i=0; doc_locations[i]; i++) {
+		for (i=0; (doc_locations[i] != 0xffffffff); i++) {
 			DoC_Probe(doc_locations[i]);
 		}
 	}
@@ -271,11 +324,7 @@
 	   found, so the user knows we at least tried. */
 	if (!docfound)
 		printk(KERN_INFO "No recognised DiskOnChip devices found\n");
-	/* So it looks like we've been used and we get unloaded */
-	MOD_INC_USE_COUNT;
-	MOD_DEC_USE_COUNT;
-	return 0;
-	
+	return -EAGAIN;
 }
 
 module_init(init_doc);
diff -Nru a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c
--- a/drivers/mtd/devices/lart.c	Tue Feb  5 12:20:55 2002
+++ b/drivers/mtd/devices/lart.c	Wed May 28 08:01:02 2003
@@ -2,7 +2,7 @@
 /*
  * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART.
  *
- * $Id: lart.c,v 1.2 2001/10/02 15:05:13 dwmw2 Exp $
+ * $Id: lart.c,v 1.5 2003/05/20 21:03:07 dwmw2 Exp $
  *
  * Author: Abraham vd Merwe <abraham@2d3d.co.za>
  *
@@ -584,46 +584,41 @@
 
 static struct mtd_info mtd;
 
-static struct mtd_erase_region_info erase_regions[] =
-{
-   /* parameter blocks */
-   {
-	     offset: 0x00000000,
-	  erasesize: FLASH_BLOCKSIZE_PARAM,
-	  numblocks: FLASH_NUMBLOCKS_16m_PARAM
-   },
-   /* main blocks */
-   {
-	     offset: FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM,
-	  erasesize: FLASH_BLOCKSIZE_MAIN,
-	  numblocks: FLASH_NUMBLOCKS_16m_MAIN
-   }
+static struct mtd_erase_region_info erase_regions[] = {
+	/* parameter blocks */
+	{
+		.offset		= 0x00000000,
+		.erasesize	= FLASH_BLOCKSIZE_PARAM,
+		.numblocks	= FLASH_NUMBLOCKS_16m_PARAM,
+	},
+	/* main blocks */
+	{
+		.offset	 = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM,
+		.erasesize	= FLASH_BLOCKSIZE_MAIN,
+		.numblocks	= FLASH_NUMBLOCKS_16m_MAIN,
+	}
 };
 
 #ifdef HAVE_PARTITIONS
-static struct mtd_partition lart_partitions[] =
-{
-   /* blob */
-   {
-	       name: "blob",
-	     offset: BLOB_START,
-	       size: BLOB_LEN,
-	 mask_flags: 0
-   },
-   /* kernel */
-   {
-	       name: "kernel",
-	     offset: KERNEL_START,			/* MTDPART_OFS_APPEND */
-	       size: KERNEL_LEN,
-	 mask_flags: 0
-   },
-   /* initial ramdisk / file system */
-   {
-	       name: "file system",
-	     offset: INITRD_START,			/* MTDPART_OFS_APPEND */
-	       size: INITRD_LEN,			/* MTDPART_SIZ_FULL */
-	 mask_flags: 0
-   }
+static struct mtd_partition lart_partitions[] = {
+	/* blob */
+	{
+		.name	= "blob",
+		.offset	= BLOB_START,
+		.size	= BLOB_LEN,
+	},
+	/* kernel */
+	{
+		.name	= "kernel",
+		.offset	= KERNEL_START,		/* MTDPART_OFS_APPEND */
+		.size	= KERNEL_LEN,
+	},
+	/* initial ramdisk / file system */
+	{
+		.name	= "file system",
+		.offset	= INITRD_START,		/* MTDPART_OFS_APPEND */
+		.size	= INITRD_LEN,		/* MTDPART_SIZ_FULL */
+	}
 };
 #endif
 
@@ -646,10 +641,10 @@
    mtd.erasesize = FLASH_BLOCKSIZE_MAIN;
    mtd.numeraseregions = NB_OF (erase_regions);
    mtd.eraseregions = erase_regions;
-   mtd.module = THIS_MODULE;
    mtd.erase = flash_erase;
    mtd.read = flash_read;
    mtd.write = flash_write;
+   mtd.owner = THIS_MODULE;
 
 #ifdef LART_DEBUG
    printk (KERN_DEBUG
diff -Nru a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/devices/ms02-nv.c	Wed May 28 08:01:09 2003
@@ -0,0 +1,326 @@
+/*
+ *      Copyright (c) 2001 Maciej W. Rozycki
+ *
+ *      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.
+ *
+ *	$Id: ms02-nv.c,v 1.4 2003/05/20 21:03:07 dwmw2 Exp $
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+#include <asm/dec/ioasic_addrs.h>
+#include <asm/dec/kn02.h>
+#include <asm/dec/kn03.h>
+#include <asm/io.h>
+#include <asm/paccess.h>
+
+#include "ms02-nv.h"
+
+
+static char version[] __initdata =
+        "ms02-nv.c: v.1.0.0  13 Aug 2001  Maciej W. Rozycki.\n";
+
+MODULE_AUTHOR("Maciej W. Rozycki <macro@ds2.pg.gda.pl>");
+MODULE_DESCRIPTION("DEC MS02-NV NVRAM module driver");
+MODULE_LICENSE("GPL");
+
+
+/*
+ * Addresses we probe for an MS02-NV at.  Modules may be located
+ * at any 8MB boundary within a 0MB up to 112MB range or at any 32MB
+ * boundary within a 0MB up to 448MB range.  We don't support a module
+ * at 0MB, though.
+ */
+static ulong ms02nv_addrs[] __initdata = {
+	0x07000000, 0x06800000, 0x06000000, 0x05800000, 0x05000000,
+	0x04800000, 0x04000000, 0x03800000, 0x03000000, 0x02800000,
+	0x02000000, 0x01800000, 0x01000000, 0x00800000
+};
+
+static const char ms02nv_name[] = "DEC MS02-NV NVRAM";
+static const char ms02nv_res_diag_ram[] = "Diagnostic RAM";
+static const char ms02nv_res_user_ram[] = "General-purpose RAM";
+static const char ms02nv_res_csr[] = "Control and status register";
+
+static struct mtd_info *root_ms02nv_mtd;
+
+
+static int ms02nv_read(struct mtd_info *mtd, loff_t from,
+			size_t len, size_t *retlen, u_char *buf)
+{
+	struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv;
+
+	if (from + len > mtd->size)
+		return -EINVAL;
+
+	memcpy(buf, mp->uaddr + from, len);
+	*retlen = len;
+
+	return 0;
+}
+
+static int ms02nv_write(struct mtd_info *mtd, loff_t to,
+			size_t len, size_t *retlen, const u_char *buf)
+{
+	struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv;
+
+	if (to + len > mtd->size)
+		return -EINVAL;
+
+	memcpy(mp->uaddr + to, buf, len);
+	*retlen = len;
+
+	return 0;
+}
+
+
+static inline uint ms02nv_probe_one(ulong addr)
+{
+	ms02nv_uint *ms02nv_diagp;
+	ms02nv_uint *ms02nv_magicp;
+	uint ms02nv_diag;
+	uint ms02nv_magic;
+	size_t size;
+
+	int err;
+
+	/*
+	 * The firmware writes MS02NV_ID at MS02NV_MAGIC and also
+	 * a diagnostic status at MS02NV_DIAG.
+	 */
+	ms02nv_diagp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_DIAG));
+	ms02nv_magicp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_MAGIC));
+	err = get_dbe(ms02nv_magic, ms02nv_magicp);
+	if (err)
+		return 0;
+	if (ms02nv_magic != MS02NV_ID)
+		return 0;
+
+	ms02nv_diag = *ms02nv_diagp;
+	size = (ms02nv_diag & MS02NV_DIAG_SIZE_MASK) << MS02NV_DIAG_SIZE_SHIFT;
+	if (size > MS02NV_CSR)
+		size = MS02NV_CSR;
+
+	return size;
+}
+
+static int __init ms02nv_init_one(ulong addr)
+{
+	struct mtd_info *mtd;
+	struct ms02nv_private *mp;
+	struct resource *mod_res;
+	struct resource *diag_res;
+	struct resource *user_res;
+	struct resource *csr_res;
+	ulong fixaddr;
+	size_t size, fixsize;
+
+	static int version_printed;
+
+	int ret = -ENODEV;
+
+	/* The module decodes 8MB of address space. */
+	mod_res = kmalloc(sizeof(*mod_res), GFP_KERNEL);
+	if (!mod_res)
+		return -ENOMEM;
+
+	memset(mod_res, 0, sizeof(*mod_res));
+	mod_res->name = ms02nv_name;
+	mod_res->start = addr;
+	mod_res->end = addr + MS02NV_SLOT_SIZE - 1;
+	mod_res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+	if (request_resource(&iomem_resource, mod_res) < 0)
+		goto err_out_mod_res;
+
+	size = ms02nv_probe_one(addr);
+	if (!size)
+		goto err_out_mod_res_rel;
+
+	if (!version_printed) {
+		printk(KERN_INFO "%s", version);
+		version_printed = 1;
+	}
+
+	ret = -ENOMEM;
+	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
+	if (!mtd)
+		goto err_out_mod_res_rel;
+	memset(mtd, 0, sizeof(*mtd));
+	mp = kmalloc(sizeof(*mp), GFP_KERNEL);
+	if (!mp)
+		goto err_out_mtd;
+	memset(mp, 0, sizeof(*mp));
+
+	mtd->priv = mp;
+	mp->resource.module = mod_res;
+
+	/* Firmware's diagnostic NVRAM area. */
+	diag_res = kmalloc(sizeof(*diag_res), GFP_KERNEL);
+	if (!diag_res)
+		goto err_out_mp;
+
+	memset(diag_res, 0, sizeof(*diag_res));
+	diag_res->name = ms02nv_res_diag_ram;
+	diag_res->start = addr;
+	diag_res->end = addr + MS02NV_RAM - 1;
+	diag_res->flags = IORESOURCE_BUSY;
+	request_resource(mod_res, diag_res);
+
+	mp->resource.diag_ram = diag_res;
+
+	/* User-available general-purpose NVRAM area. */
+	user_res = kmalloc(sizeof(*user_res), GFP_KERNEL);
+	if (!user_res)
+		goto err_out_diag_res;
+
+	memset(user_res, 0, sizeof(*user_res));
+	user_res->name = ms02nv_res_user_ram;
+	user_res->start = addr + MS02NV_RAM;
+	user_res->end = addr + size - 1;
+	user_res->flags = IORESOURCE_BUSY;
+	request_resource(mod_res, user_res);
+
+	mp->resource.user_ram = user_res;
+
+	/* Control and status register. */
+	csr_res = kmalloc(sizeof(*csr_res), GFP_KERNEL);
+	if (!csr_res)
+		goto err_out_user_res;
+
+	memset(csr_res, 0, sizeof(*csr_res));
+	csr_res->name = ms02nv_res_csr;
+	csr_res->start = addr + MS02NV_CSR;
+	csr_res->end = addr + MS02NV_CSR + 3;
+	csr_res->flags = IORESOURCE_BUSY;
+	request_resource(mod_res, csr_res);
+
+	mp->resource.csr = csr_res;
+
+	mp->addr = phys_to_virt(addr);
+	mp->size = size;
+
+	/*
+	 * Hide the firmware's diagnostic area.  It may get destroyed
+	 * upon a reboot.  Take paging into account for mapping support.
+	 */
+	fixaddr = (addr + MS02NV_RAM + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+	fixsize = (size - (fixaddr - addr)) & ~(PAGE_SIZE - 1);
+	mp->uaddr = phys_to_virt(fixaddr);
+
+	mtd->type = MTD_RAM;
+	mtd->flags = MTD_CAP_RAM | MTD_XIP;
+	mtd->size = fixsize;
+	mtd->name = (char *)ms02nv_name;
+	mtd->owner = THIS_MODULE;
+	mtd->read = ms02nv_read;
+	mtd->write = ms02nv_write;
+
+	ret = -EIO;
+	if (add_mtd_device(mtd)) {
+		printk(KERN_ERR
+			"ms02-nv: Unable to register MTD device, aborting!\n");
+		goto err_out_csr_res;
+	}
+
+	printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMB.\n",
+		mtd->index, ms02nv_name, addr, size >> 20);
+
+	mp->next = root_ms02nv_mtd;
+	root_ms02nv_mtd = mtd;
+
+	return 0;
+
+
+err_out_csr_res:
+	release_resource(csr_res);
+	kfree(csr_res);
+err_out_user_res:
+	release_resource(user_res);
+	kfree(user_res);
+err_out_diag_res:
+	release_resource(diag_res);
+	kfree(diag_res);
+err_out_mp:
+	kfree(mp);
+err_out_mtd:
+	kfree(mtd);
+err_out_mod_res_rel:
+	release_resource(mod_res);
+err_out_mod_res:
+	kfree(mod_res);
+	return ret;
+}
+
+static void __exit ms02nv_remove_one(void)
+{
+	struct mtd_info *mtd = root_ms02nv_mtd;
+	struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv;
+
+	root_ms02nv_mtd = mp->next;
+
+	del_mtd_device(mtd);
+
+	release_resource(mp->resource.csr);
+	kfree(mp->resource.csr);
+	release_resource(mp->resource.user_ram);
+	kfree(mp->resource.user_ram);
+	release_resource(mp->resource.diag_ram);
+	kfree(mp->resource.diag_ram);
+	release_resource(mp->resource.module);
+	kfree(mp->resource.module);
+	kfree(mp);
+	kfree(mtd);
+}
+
+
+static int __init ms02nv_init(void)
+{
+	volatile u32 *csr;
+	uint stride = 0;
+	int count = 0;
+	int i;
+
+	switch (mips_machtype) {
+	case MACH_DS5000_200:
+		csr = (volatile u32 *)KN02_CSR_ADDR;
+		if (*csr & KN02_CSR_BNK32M)
+			stride = 2;
+		break;
+	case MACH_DS5000_2X0:
+	case MACH_DS5000:
+		csr = (volatile u32 *)KN03_MCR_BASE;
+		if (*csr & KN03_MCR_BNK32M)
+			stride = 2;
+		break;
+	default:
+		return -ENODEV;
+		break;
+	}
+
+	for (i = 0; i < (sizeof(ms02nv_addrs) / sizeof(*ms02nv_addrs)); i++)
+		if (!ms02nv_init_one(ms02nv_addrs[i] << stride))
+			count++;
+
+	return (count > 0) ? 0 : -ENODEV;
+}
+
+static void __exit ms02nv_cleanup(void)
+{
+	while (root_ms02nv_mtd)
+		ms02nv_remove_one();
+}
+
+
+module_init(ms02nv_init);
+module_exit(ms02nv_cleanup);
diff -Nru a/drivers/mtd/devices/ms02-nv.h b/drivers/mtd/devices/ms02-nv.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/devices/ms02-nv.h	Wed May 28 08:01:10 2003
@@ -0,0 +1,45 @@
+/*
+ *      Copyright (c) 2001 Maciej W. Rozycki
+ *
+ *      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.
+ *
+ *	$Id: ms02-nv.h,v 1.1 2002/09/13 13:46:55 dwmw2 Exp $
+ */
+
+#include <linux/ioport.h>
+#include <linux/mtd/mtd.h>
+
+/* MS02-NV iomem register offsets. */
+#define MS02NV_CSR		0x400000	/* control & status register */
+
+/* MS02-NV memory offsets. */
+#define MS02NV_DIAG		0x0003f8	/* diagnostic status */
+#define MS02NV_MAGIC		0x0003fc	/* MS02-NV magic ID */
+#define MS02NV_RAM		0x000400	/* general-purpose RAM start */
+
+/* MS02-NV diagnostic status constants. */
+#define MS02NV_DIAG_SIZE_MASK	0xf0		/* RAM size mask */
+#define MS02NV_DIAG_SIZE_SHIFT	0x10		/* RAM size shift (left) */
+
+/* MS02-NV general constants. */
+#define MS02NV_ID		0x03021966	/* MS02-NV magic ID value */
+#define MS02NV_SLOT_SIZE	0x800000	/* size of the address space
+						   decoded by the module */
+
+typedef volatile u32 ms02nv_uint;
+
+struct ms02nv_private {
+	struct mtd_info *next;
+	struct {
+		struct resource *module;
+		struct resource *diag_ram;
+		struct resource *user_ram;
+		struct resource *csr;
+	} resource;
+	u_char *addr;
+	size_t size;
+	u_char *uaddr;
+};
diff -Nru a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c
--- a/drivers/mtd/devices/mtdram.c	Mon Feb  4 23:49:33 2002
+++ b/drivers/mtd/devices/mtdram.c	Wed May 28 08:01:02 2003
@@ -1,6 +1,6 @@
 /*
  * mtdram - a test mtd device
- * $Id: mtdram.c,v 1.25 2001/10/02 15:05:13 dwmw2 Exp $
+ * $Id: mtdram.c,v 1.32 2003/05/21 15:15:07 dwmw2 Exp $
  * Author: Alexander Larsson <alex@cendio.se>
  *
  * Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
@@ -13,6 +13,8 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
 #include <linux/mtd/compatmac.h>
 #include <linux/mtd/mtd.h>
 
@@ -28,7 +30,9 @@
 static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE;
 static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE;
 MODULE_PARM(total_size,"l");
+MODULE_PARM_DESC(total_size, "Total device size in KiB");
 MODULE_PARM(erase_size,"l");
+MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
 #define MTDRAM_TOTAL_SIZE (total_size * 1024)
 #define MTDRAM_ERASE_SIZE (erase_size * 1024)
 #else
@@ -69,7 +73,8 @@
   return 0;
 }
 
-static void ram_unpoint (struct mtd_info *mtd, u_char *addr)
+static void ram_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
+			 size_t len)
 {
   DEBUG(MTD_DEBUG_LEVEL2, "ram_unpoint\n");
 }
@@ -108,65 +113,119 @@
 {
   if (mtd_info) {
     del_mtd_device(mtd_info);
+#if CONFIG_MTDRAM_TOTAL_SIZE > 0
     if (mtd_info->priv)
 #if CONFIG_MTDRAM_ABS_POS > 0
       iounmap(mtd_info->priv);
 #else
       vfree(mtd_info->priv);
 #endif	
+#endif
     kfree(mtd_info);
   }
 }
 
+int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, 
+                       unsigned long size, char *name)
+{
+   memset(mtd, 0, sizeof(*mtd));
+
+   /* Setup the MTD structure */
+   mtd->name = name;
+   mtd->type = MTD_RAM;
+   mtd->flags = MTD_CAP_RAM;
+   mtd->size = size;
+   mtd->erasesize = MTDRAM_ERASE_SIZE;
+   mtd->priv = mapped_address;
+
+   mtd->owner = THIS_MODULE;
+   mtd->erase = ram_erase;
+   mtd->point = ram_point;
+   mtd->unpoint = ram_unpoint;
+   mtd->read = ram_read;
+   mtd->write = ram_write;
+
+   if (add_mtd_device(mtd)) {
+     return -EIO;
+   }
+   
+   return 0;
+}
+
+#if CONFIG_MTDRAM_TOTAL_SIZE > 0
+#if CONFIG_MTDRAM_ABS_POS > 0
 int __init init_mtdram(void)
 {
-   // Allocate some memory
+  void *addr;
+  int err;
+  /* Allocate some memory */
    mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
    if (!mtd_info)
-      return 0;
+     return -ENOMEM;
    
-   memset(mtd_info, 0, sizeof(*mtd_info));
+  addr = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE);
+  if (!addr) {
+    DEBUG(MTD_DEBUG_LEVEL1, 
+          "Failed to ioremap) memory region of size %ld at ABS_POS:%ld\n", 
+          (long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS);
+    kfree(mtd_info);
+    mtd_info = NULL;
+    return -ENOMEM;
+  }
+  err = mtdram_init_device(mtd_info, addr, 
+                           MTDRAM_TOTAL_SIZE, "mtdram test device");
+  if (err) 
+  {
+    iounmap(addr);
+    kfree(mtd_info);
+    mtd_info = NULL;
+    return err;
+  }
+  memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
+  return err;
+}
 
-   // Setup the MTD structure
-   mtd_info->name = "mtdram test device";
-   mtd_info->type = MTD_RAM;
-   mtd_info->flags = MTD_CAP_RAM;
-   mtd_info->size = MTDRAM_TOTAL_SIZE;
-   mtd_info->erasesize = MTDRAM_ERASE_SIZE;
-#if CONFIG_MTDRAM_ABS_POS > 0
-   mtd_info->priv = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE);
-#else
-   mtd_info->priv = vmalloc(MTDRAM_TOTAL_SIZE);
-#endif
+#else /* CONFIG_MTDRAM_ABS_POS > 0 */
 
-   if (!mtd_info->priv) {
-     DEBUG(MTD_DEBUG_LEVEL1, "Failed to vmalloc(/ioremap) memory region of size %ld (ABS_POS:%ld)\n", (long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS);
-     kfree(mtd_info);
-     mtd_info = NULL;
+int __init init_mtdram(void)
+{
+  void *addr;
+  int err;
+  /* Allocate some memory */
+   mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+   if (!mtd_info)
      return -ENOMEM;
-   }
-   memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
 
-   mtd_info->module = THIS_MODULE;			
-   mtd_info->erase = ram_erase;
-   mtd_info->point = ram_point;
-   mtd_info->unpoint = ram_unpoint;
-   mtd_info->read = ram_read;
-   mtd_info->write = ram_write;
+  addr = vmalloc(MTDRAM_TOTAL_SIZE);
+  if (!addr) {
+    DEBUG(MTD_DEBUG_LEVEL1, 
+          "Failed to vmalloc memory region of size %ld\n", 
+          (long)MTDRAM_TOTAL_SIZE);
+    kfree(mtd_info);
+    mtd_info = NULL;
+    return -ENOMEM;
+  }
+  err = mtdram_init_device(mtd_info, addr, 
+                           MTDRAM_TOTAL_SIZE, "mtdram test device");
+  if (err) 
+  {
+    vfree(addr);
+    kfree(mtd_info);
+    mtd_info = NULL;
+    return err;
+  }
+  memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
+  return err;
+}
+#endif /* !(CONFIG_MTDRAM_ABS_POS > 0) */
 
-   if (add_mtd_device(mtd_info)) {
-#if CONFIG_MTDRAM_ABS_POS > 0
-     iounmap(mtd_info->priv);
-#else
-     vfree(mtd_info->priv);
-#endif	
-     kfree(mtd_info);
-     mtd_info = NULL;
-     return -EIO;
-   }
-   
-   return 0;
+#else /* CONFIG_MTDRAM_TOTAL_SIZE > 0 */
+
+int __init init_mtdram(void)
+{
+  return 0;
 }
+#endif /* !(CONFIG_MTDRAM_TOTAL_SIZE > 0) */
 
 module_init(init_mtdram);
 module_exit(cleanup_mtdram);
diff -Nru a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
--- a/drivers/mtd/devices/pmc551.c	Tue Feb 25 10:47:17 2003
+++ b/drivers/mtd/devices/pmc551.c	Wed May 28 08:01:02 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: pmc551.c,v 1.19 2001/10/02 15:05:13 dwmw2 Exp $
+ * $Id: pmc551.c,v 1.24 2003/05/20 21:03:08 dwmw2 Exp $
  *
  * PMC551 PCI Mezzanine Ram Device
  *
@@ -30,7 +30,7 @@
  *	 
  * Notes:
  *	 Due to what I assume is more buggy SROM, the 64M PMC551 I
- *	 have available claims that all 4 of its DRAM banks have 64M
+ *	 have available claims that all 4 of it's DRAM banks have 64M
  *	 of ram configured (making a grand total of 256M onboard).
  *	 This is slightly annoying since the BAR0 size reflects the
  *	 aperture size, not the dram size, and the V370PDC supplies no
@@ -98,7 +98,6 @@
 #include <linux/ioctl.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <stdarg.h>
 #include <linux/pci.h>
 
 #ifndef CONFIG_PCI
@@ -215,7 +214,7 @@
 }
 
 
-static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr)
+static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
 {
 #ifdef CONFIG_MTD_PMC551_DEBUG
 	printk(KERN_DEBUG "pmc551_unpoint()\n");
@@ -788,10 +787,10 @@
                 mtd->write 	= pmc551_write;
                 mtd->point 	= pmc551_point;
                 mtd->unpoint 	= pmc551_unpoint;
-                mtd->module 	= THIS_MODULE;
                 mtd->type 	= MTD_RAM;
                 mtd->name 	= "PMC551 RAM board";
                 mtd->erasesize 	= 0x10000;
+		mtd->owner = THIS_MODULE;
 
                 if (add_mtd_device(mtd)) {
                         printk(KERN_NOTICE "pmc551: Failed to register new device\n");
diff -Nru a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
--- a/drivers/mtd/devices/slram.c	Tue Feb  5 07:23:06 2002
+++ b/drivers/mtd/devices/slram.c	Wed May 28 08:01:02 2003
@@ -1,6 +1,32 @@
 /*======================================================================
 
-  $Id: slram.c,v 1.25 2001/10/02 15:05:13 dwmw2 Exp $
+  $Id: slram.c,v 1.30 2003/05/20 21:03:08 dwmw2 Exp $
+
+  This driver provides a method to access memory not used by the kernel
+  itself (i.e. if the kernel commandline mem=xxx is used). To actually
+  use slram at least mtdblock or mtdchar is required (for block or
+  character device access).
+
+  Usage:
+
+  if compiled as loadable module:
+    modprobe slram map=<name>,<start>,<end/offset>
+  if statically linked into the kernel use the following kernel cmd.line
+    slram=<name>,<start>,<end/offset>
+
+  <name>: name of the device that will be listed in /proc/mtd
+  <start>: start of the memory region, decimal or hex (0xabcdef)
+  <end/offset>: end of the memory region. It's possible to use +0x1234
+                to specify the offset instead of the absolute address
+    
+  NOTE:
+  With slram it's only possible to map a contigous memory region. Therfore
+  if there's a device mapped somewhere in the region specified slram will
+  fail to load (see kernel log if modprobe fails).
+
+  -
+  
+  Jochen Schaeuble <psionic@psionic.de>
 
 ======================================================================*/
 
@@ -20,7 +46,6 @@
 #include <linux/init.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <stdarg.h>
 
 #include <linux/mtd/mtd.h>
 
@@ -52,7 +77,7 @@
 
 int slram_erase(struct mtd_info *, struct erase_info *);
 int slram_point(struct mtd_info *, loff_t, size_t, size_t *, u_char **);
-void slram_unpoint(struct mtd_info *, u_char *);
+void slram_unpoint(struct mtd_info *, u_char *, loff_t,	size_t);
 int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 
@@ -93,7 +118,7 @@
 	return(0);
 }
 
-void slram_unpoint(struct mtd_info *mtd, u_char *addr)
+void slram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
 {
 }
 
@@ -174,9 +199,9 @@
 	(*curmtd)->mtdinfo->unpoint = slram_unpoint;
 	(*curmtd)->mtdinfo->read = slram_read;
 	(*curmtd)->mtdinfo->write = slram_write;
-	(*curmtd)->mtdinfo->module = THIS_MODULE;
+	(*curmtd)->mtdinfo->owner = THIS_MODULE;
 	(*curmtd)->mtdinfo->type = MTD_RAM;
-	(*curmtd)->mtdinfo->erasesize = 0x10000;
+	(*curmtd)->mtdinfo->erasesize = 0x0;
 
 	if (add_mtd_device((*curmtd)->mtdinfo))	{
 		E("slram: Failed to register new device\n");
diff -Nru a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
--- a/drivers/mtd/ftl.c	Mon Apr  7 06:36:32 2003
+++ b/drivers/mtd/ftl.c	Wed May 28 08:01:02 2003
@@ -1,5 +1,5 @@
 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
- * $Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $
+ * $Id: ftl.c,v 1.50 2003/05/21 10:49:47 dwmw2 Exp $
  *
  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
@@ -55,30 +55,27 @@
     contact M-Systems (http://www.m-sys.com) directly.
       
 ======================================================================*/
+#include <linux/mtd/blktrans.h>
 #include <linux/module.h>
-#include <linux/mtd/compatmac.h>
 #include <linux/mtd/mtd.h>
 /*#define PSYCHO_DEBUG */
 
 #include <linux/kernel.h>
-#include <linux/jiffies.h>
+#include <linux/sched.h>
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/major.h>
 #include <linux/fs.h>
-#include <linux/ioctl.h>
+#include <linux/init.h>
 #include <linux/hdreg.h>
-#include <stdarg.h>
-
 #include <linux/vmalloc.h>
 #include <linux/blkpg.h>
+#include <asm/uaccess.h>
 
 #include <linux/mtd/ftl.h>
 
-#define request_arg_t           request_queue_t *q
-
 /*====================================================================*/
 
 /* Parameters that can be set with 'insmod' */
@@ -92,10 +89,6 @@
 #define FTL_MAJOR	44
 #endif
 
-/* Funky stuff for setting up a block device */
-#define MAJOR_NR		FTL_MAJOR
-
-#include <linux/blk.h>
 
 /*====================================================================*/
 
@@ -106,8 +99,7 @@
 #define MAX_REGION	4
 
 /* Maximum number of partitions in an FTL region */
-#define PART_BITS	3
-#define MAX_PART	8
+#define PART_BITS	4
 
 /* Maximum number of outstanding erase requests per socket */
 #define MAX_ERASE	8
@@ -118,8 +110,7 @@
 
 /* Each memory region corresponds to a minor device */
 typedef struct partition_t {
-    struct mtd_info	*mtd;
-    struct gendisk	*disk;
+    struct mtd_blktrans_dev mbd;
     u_int32_t		state;
     u_int32_t		*VirtualBlockMap;
     u_int32_t		*VirtualPageMap;
@@ -144,21 +135,10 @@
     region_info_t	region;
     memory_handle_t	handle;
 #endif
-    atomic_t		open;
 } partition_t;
 
-partition_t *myparts[MAX_MTD_DEVICES];
-
-static void ftl_notify_add(struct mtd_info *mtd);
-static void ftl_notify_remove(struct mtd_info *mtd);
-
 void ftl_freepart(partition_t *part);
 
-static struct mtd_notifier ftl_notifier = {
-	.add	= ftl_notify_add,
-	.remove	= ftl_notify_remove,
-};
-
 /* Partition state flags */
 #define FTL_FORMATTED	0x01
 
@@ -171,21 +151,9 @@
 
 /*====================================================================*/
 
-static int ftl_ioctl(struct inode *inode, struct file *file,
-		     u_int cmd, u_long arg);
-static int ftl_open(struct inode *inode, struct file *file);
-static release_t ftl_close(struct inode *inode, struct file *file);
-static int ftl_revalidate(struct gendisk *disk);
 
 static void ftl_erase_callback(struct erase_info *done);
 
-static struct block_device_operations ftl_blk_fops = {
-	.owner		= THIS_MODULE,
-	.open		= ftl_open,
-	.release	= ftl_close,
-	.ioctl		= ftl_ioctl,
-	.revalidate_disk= ftl_revalidate,
-};
 
 /*======================================================================
 
@@ -201,13 +169,13 @@
     loff_t offset, max_offset;
     int ret;
     part->header.FormattedSize = 0;
-    max_offset = (0x100000<part->mtd->size)?0x100000:part->mtd->size;
+    max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size;
     /* Search first megabyte for a valid FTL header */
     for (offset = 0;
 	 (offset + sizeof(header)) < max_offset;
-	 offset += part->mtd->erasesize ? : 0x2000) {
+	 offset += part->mbd.mtd->erasesize ? : 0x2000) {
 
-	ret = part->mtd->read(part->mtd, offset, sizeof(header), &ret, 
+	ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret, 
 			      (unsigned char *)&header);
 	
 	if (ret) 
@@ -226,9 +194,9 @@
 	printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
 	return -1;
     }
-    if ((1 << header.EraseUnitSize) != part->mtd->erasesize) {
+    if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) {
 	printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n",
-	       1 << header.EraseUnitSize,part->mtd->erasesize);
+	       1 << header.EraseUnitSize,part->mbd.mtd->erasesize);
 	return -1;
     }
     part->header = header;
@@ -263,7 +231,7 @@
     for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
 	offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
 		      << part->header.EraseUnitSize);
-	ret = part->mtd->read(part->mtd, offset, sizeof(header), &retval, 
+	ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval, 
 			      (unsigned char *)&header);
 	
 	if (ret) 
@@ -328,7 +296,7 @@
 	part->EUNInfo[i].Deleted = 0;
 	offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
 	
-	ret = part->mtd->read(part->mtd, offset,  
+	ret = part->mbd.mtd->read(part->mbd.mtd, offset,  
 			      part->BlocksPerUnit * sizeof(u_int32_t), &retval, 
 			      (unsigned char *)part->bam_cache);
 	
@@ -393,7 +361,7 @@
     erase->len = 1 << part->header.EraseUnitSize;
     erase->priv = (u_long)part;
     
-    ret = part->mtd->erase(part->mtd, erase);
+    ret = part->mbd.mtd->erase(part->mbd.mtd, erase);
 
     if (!ret)
 	    xfer->EraseCount++;
@@ -460,7 +428,7 @@
     header.LogicalEUN = cpu_to_le16(0xffff);
     header.EraseCount = cpu_to_le32(xfer->EraseCount);
 
-    ret = part->mtd->write(part->mtd, xfer->Offset, sizeof(header),
+    ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset, sizeof(header),
 			   &retlen, (u_char *)&header);
 
     if (ret) {
@@ -476,7 +444,7 @@
 
     for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
 
-	ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t), 
+	ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), 
 			       &retlen, (u_char *)&ctl);
 
 	if (ret)
@@ -523,7 +491,7 @@
 
 	offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
 
-	ret = part->mtd->read(part->mtd, offset, 
+	ret = part->mbd.mtd->read(part->mbd.mtd, offset, 
 			      part->BlocksPerUnit * sizeof(u_int32_t),
 			      &retlen, (u_char *) (part->bam_cache));
 
@@ -541,7 +509,7 @@
     offset = xfer->Offset + 20; /* Bad! */
     unit = cpu_to_le16(0x7fff);
 
-    ret = part->mtd->write(part->mtd, offset, sizeof(u_int16_t),
+    ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t),
 			   &retlen, (u_char *) &unit);
     
     if (ret) {
@@ -561,7 +529,7 @@
 	    break;
 	case BLOCK_DATA:
 	case BLOCK_REPLACEMENT:
-	    ret = part->mtd->read(part->mtd, src, SECTOR_SIZE,
+	    ret = part->mbd.mtd->read(part->mbd.mtd, src, SECTOR_SIZE,
                         &retlen, (u_char *) buf);
 	    if (ret) {
 		printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n");
@@ -569,7 +537,7 @@
             }
 
 
-	    ret = part->mtd->write(part->mtd, dest, SECTOR_SIZE,
+	    ret = part->mbd.mtd->write(part->mbd.mtd, dest, SECTOR_SIZE,
                         &retlen, (u_char *) buf);
 	    if (ret)  {
 		printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n");
@@ -588,7 +556,7 @@
     }
 
     /* Write the BAM to the transfer unit */
-    ret = part->mtd->write(part->mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), 
+    ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), 
                     part->BlocksPerUnit * sizeof(int32_t), &retlen, 
 		    (u_char *)part->bam_cache);
     if (ret) {
@@ -598,7 +566,7 @@
 
     
     /* All clear? Then update the LogicalEUN again */
-    ret = part->mtd->write(part->mtd, xfer->Offset + 20, sizeof(u_int16_t),
+    ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t),
 			   &retlen, (u_char *)&srcunitswap);
 
     if (ret) {
@@ -686,8 +654,8 @@
 	    if (queued) {
 		DEBUG(1, "ftl_cs: waiting for transfer "
 		      "unit to be prepared...\n");
-		if (part->mtd->sync)
-			part->mtd->sync(part->mtd);
+		if (part->mbd.mtd->sync)
+			part->mbd.mtd->sync(part->mbd.mtd);
 	    } else {
 		static int ne = 0;
 		if (++ne < 5)
@@ -785,7 +753,7 @@
 	/* Invalidate cache */
 	part->bam_index = 0xffff;
 
-	ret = part->mtd->read(part->mtd, 
+	ret = part->mbd.mtd->read(part->mbd.mtd, 
 		       part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
 		       part->BlocksPerUnit * sizeof(u_int32_t),
 		       &retlen, (u_char *) (part->bam_cache));
@@ -814,64 +782,6 @@
     
 } /* find_free */
 
-/*======================================================================
-
-    This gets a memory handle for the region corresponding to the
-    minor device number.
-    
-======================================================================*/
-
-static int ftl_open(struct inode *inode, struct file *file)
-{
-	partition_t *partition = inode->i_bdev->bd_disk->private_data;
-	if (!partition)
-		return -ENODEV;
-
-	if (partition->state != FTL_FORMATTED)
-		return -ENXIO;
-    
-	if (get_capacity(partition->disk) == 0)
-		return -ENXIO;
-
-	if (!get_mtd_device(partition->mtd, -1))
-		return /* -E'SBUGGEREDOFF */ -ENXIO;
-
-	if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) {
-		put_mtd_device(partition->mtd);
-		return -EROFS;
-	}
-    
-	DEBUG(0, "ftl_cs: ftl_open(%s)\n", inode->i_bdev->bd_disk->disk_name);
-
-	atomic_inc(&partition->open);
-
-	return 0;
-}
-
-/*====================================================================*/
-
-static release_t ftl_close(struct inode *inode, struct file *file)
-{
-	partition_t *part = inode->i_bdev->bd_disk->private_data;
-	int i;
-    
-	DEBUG(0, "ftl_cs: ftl_close(%s)\n", inode->i_bdev->bd_disk->disk_name);
-
-	/* Wait for any pending erase operations to complete */
-	if (part->mtd->sync)
-		part->mtd->sync(part->mtd);
-    
-	for (i = 0; i < part->header.NumTransferUnits; i++) {
-		if (part->XferInfo[i].state == XFER_ERASED)
-			prepare_xfer(part, i);
-	}
-
-	atomic_dec(&part->open);
-
-	put_mtd_device(part->mtd);
-	release_return(0);
-} /* ftl_close */
-
 
 /*======================================================================
 
@@ -906,7 +816,7 @@
 	else {
 	    offset = (part->EUNInfo[log_addr / bsize].Offset
 			  + (log_addr % bsize));
-	    ret = part->mtd->read(part->mtd, offset, SECTOR_SIZE,
+	    ret = part->mbd.mtd->read(part->mbd.mtd, offset, SECTOR_SIZE,
 			   &retlen, (u_char *) buffer);
 
 	    if (ret) {
@@ -945,7 +855,7 @@
 		  le32_to_cpu(part->header.BAMOffset));
     
 #ifdef PSYCHO_DEBUG
-    ret = part->mtd->read(part->mtd, offset, sizeof(u_int32_t),
+    ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),
                         &retlen, (u_char *)&old_addr);
     if (ret) {
 	printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
@@ -982,7 +892,7 @@
 #endif
 	part->bam_cache[blk] = le_virt_addr;
     }
-    ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t),
+    ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
                             &retlen, (u_char *)&le_virt_addr);
 
     if (ret) {
@@ -1042,7 +952,7 @@
 	part->EUNInfo[part->bam_index].Deleted++;
 	offset = (part->EUNInfo[part->bam_index].Offset +
 		      blk * SECTOR_SIZE);
-	ret = part->mtd->write(part->mtd, offset, SECTOR_SIZE, &retlen, 
+	ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, 
                                      buffer);
 
 	if (ret) {
@@ -1080,94 +990,43 @@
 
 ======================================================================*/
 
-static int ftl_ioctl(struct inode *inode, struct file *file,
-		     u_int cmd, u_long arg)
+static int ftl_ioctl(struct mtd_blktrans_dev *dev, struct inode *inode, 
+		     struct file *file, u_int cmd, u_long arg)
 {
-	partition_t *part = inode->i_bdev->bd_disk->private_data;
-	struct hd_geometry *geo = (struct hd_geometry *)arg;
-	int ret = 0;
-	u_long sect;
-
-	if (!part)
-		return -ENODEV; /* How? */
-
-	if (cmd != HDIO_GETGEO)
-		return -EINVAL;
-	ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(*geo));
-	if (ret)
-		return ret;
+    struct hd_geometry *geo = (struct hd_geometry *)arg;
+    partition_t *part = (void *)dev;
+    u_long sect;
+
+    switch (cmd) {
+    case HDIO_GETGEO:
 	/* Sort of arbitrary: round size down to 4K boundary */
 	sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE;
-	put_user(1, (char *)&geo->heads);
-	put_user(8, (char *)&geo->sectors);
-	put_user((sect>>3), (short *)&geo->cylinders);
-	put_user(get_start_sect(inode->i_bdev), (u_long *)&geo->start);
-	return 0;
-} /* ftl_ioctl */
+	if (put_user(1, (char *)&geo->heads) ||
+	    put_user(8, (char *)&geo->sectors) ||
+	    put_user((sect>>3), (short *)&geo->cylinders) ||
+	    put_user(0, (u_long *)&geo->start))
+		return -EFAULT;
 
-/*======================================================================
+    case BLKFLSBUF:
+	    return 0;
+    }
+    return -ENOTTY;
+} /* ftl_ioctl */
 
-    Handler for block device requests
 
-======================================================================*/
+/*======================================================================*/
 
-static int ftl_revalidate(struct gendisk *disk)
+static int ftl_readsect(struct mtd_blktrans_dev *dev,
+			      unsigned long block, char *buf)
 {
-	partition_t *part = disk->private_data;
-	scan_header(part);
-	set_capacity(disk, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE);
-	return 0;
+	return ftl_read((void *)dev, buf, block, 1);
 }
 
-/*======================================================================
-
-    Handler for block device requests
-
-======================================================================*/
-
-static struct request_queue ftl_queue;
-
-static void do_ftl_request(struct request_queue *q)
+static int ftl_writesect(struct mtd_blktrans_dev *dev,
+			      unsigned long block, char *buf)
 {
-	struct request *req;
-	partition_t *part;
-	int ret;
-
-	do {
-		//	    sti();
-		req = elv_next_request(q);
-		if (!req)
-			return;
-		part = req->rq_disk->private_data;
-		if (part) {
-			ret = 0;
-			switch (rq_data_dir(req)) {
-			case READ:
-				ret = ftl_read(part, req->buffer, req->sector,
-						req->current_nr_sectors);
-				if (ret)
-					printk("ftl_read returned %d\n", ret);
-				break;
-			case WRITE:
-				ret = ftl_write(part, req->buffer, req->sector,
-						req->current_nr_sectors);
-				if (ret)
-					printk("ftl_write returned %d\n", ret);
-				break;
-			default:
-				panic("ftl_cs: unknown block command!\n");
-			}
-		} else {
-			ret = 1;
-			printk("NULL part in ftl_request\n");
-		}
-		 
-		if (!ret)
-			req->sector += req->current_nr_sectors;
-
-		end_request(req, (ret == 0) ? 1 : 0);
-	} while (1);
-} /* do_ftl_request */
+	return ftl_write((void *)dev, buf, block, 1);
+}
 
 /*====================================================================*/
 
@@ -1196,109 +1055,75 @@
     
 } /* ftl_freepart */
 
-static void ftl_notify_add(struct mtd_info *mtd)
+static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 {
 	partition_t *partition;
-	struct gendisk *disk;
-	int device;
-
-	for (device=0; device < MAX_MTD_DEVICES && myparts[device]; device++)
-		;
-
-	if (device == MAX_MTD_DEVICES) {
-		printk(KERN_NOTICE "Maximum number of FTL partitions reached\n"
-		       "Not scanning <%s>\n", mtd->name);
-		return;
-	}
 
 	partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
-	disk = alloc_disk(1 << PART_BITS);
 		
-	if (!partition||!disk) {
+	if (!partition) {
 		printk(KERN_WARNING "No memory to scan for FTL on %s\n",
-			mtd->name);
-		kfree(partition);
-		put_disk(disk);
+		       mtd->name);
 		return;
 	}    
 
 	memset(partition, 0, sizeof(partition_t));
-	sprintf(disk->disk_name, "ftl%c", 'a' + device);
-	disk->major = FTL_MAJOR;
-	disk->first_minor = device << 4;
-	disk->fops = &ftl_blk_fops;
-	partition->mtd = mtd;
-	partition->disk = disk;
 
-	if ((scan_header(partition) == 0) && (build_maps(partition) == 0)) {
+	partition->mbd.mtd = mtd;
+
+	if ((scan_header(partition) == 0) && 
+	    (build_maps(partition) == 0)) {
+		
 		partition->state = FTL_FORMATTED;
-		atomic_set(&partition->open, 0);
-		myparts[device] = partition;
-		set_capacity(disk, le32_to_cpu(partition->header.FormattedSize)/SECTOR_SIZE);
-		disk->private_data = partition;
-		disk->queue = &ftl_queue;
-		add_disk(disk);
 #ifdef PCMCIA_DEBUG
-		printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n",
+		printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
 		       le32_to_cpu(partition->header.FormattedSize) >> 10);
 #endif
-	} else {
+		partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
+		partition->mbd.blksize = SECTOR_SIZE;
+		partition->mbd.tr = tr;
+		partition->mbd.devnum = -1;
+		if (add_mtd_blktrans_dev((void *)partition))
+			kfree(partition);
+	
+	} else
 		kfree(partition);
-		put_disk(disk);
-	}
 }
 
-static void ftl_notify_remove(struct mtd_info *mtd)
+static void ftl_remove_dev(struct mtd_blktrans_dev *dev)
 {
-        int i;
-
-	/* Q: What happens if you try to remove a device which has
-	 *    a currently-open FTL partition on it?
-	 *
-	 * A: You don't. The ftl_open routine is responsible for
-	 *    increasing the use count of the driver module which
-	 *    it uses.
-	 */
-
-	/* That's the theory, anyway :) */
-
-	for (i=0; i< MAX_MTD_DEVICES; i++)
-		if (myparts[i] && myparts[i]->mtd == mtd) {
-
-			if (myparts[i]->state == FTL_FORMATTED)
-				ftl_freepart(myparts[i]);
-			
-			myparts[i]->state = 0;
-			del_gendisk(myparts[i]->disk);
-			put_disk(myparts[i]->disk);
-			kfree(myparts[i]);
-			myparts[i] = NULL;
-		}
+	del_mtd_blktrans_dev(dev);
+	kfree(dev);
 }
 
+struct mtd_blktrans_ops ftl_tr = {
+	.name		= "ftl",
+	.major		= FTL_MAJOR,
+	.part_bits	= PART_BITS,
+	.readsect	= ftl_readsect,
+	.writesect	= ftl_writesect,
+	.ioctl		= ftl_ioctl,
+	.add_mtd	= ftl_add_mtd,
+	.remove_dev	= ftl_remove_dev,
+	.owner		= THIS_MODULE,
+};
+
 int init_ftl(void)
 {
-	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
-	DEBUG(0, "$Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $\n");
-
-	if (register_blkdev(FTL_MAJOR, "ftl"))
-		return -EAGAIN;
+	DEBUG(0, "$Id: ftl.c,v 1.50 2003/05/21 10:49:47 dwmw2 Exp $\n");
 
-	blk_init_queue(&ftl_queue, &do_ftl_request, &lock);
-	register_mtd_user(&ftl_notifier);
-	return 0;
+	return register_mtd_blktrans(&ftl_tr);
 }
 
 static void __exit cleanup_ftl(void)
 {
-	unregister_mtd_user(&ftl_notifier);
-	unregister_blkdev(FTL_MAJOR, "ftl");
-	blk_cleanup_queue(&ftl_queue);
+	deregister_mtd_blktrans(&ftl_tr);
 }
 
 module_init(init_ftl);
 module_exit(cleanup_ftl);
 
+
 MODULE_LICENSE("Dual MPL/GPL");
 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices and M-Systems DiskOnChip 1000");
+MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices");
diff -Nru a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/inftlcore.c	Wed May 28 08:01:11 2003
@@ -0,0 +1,894 @@
+/* 
+ * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL)
+ *
+ * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
+ *
+ * Based heavily on the nftlcore.c code which is:
+ * (c) 1999 Machine Vision Holdings, Inc.
+ * Author: David Woodhouse <dwmw2@infradead.org>
+ *
+ * $Id: inftlcore.c,v 1.9 2003/05/23 11:41:47 dwmw2 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/hdreg.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nftl.h>
+#include <linux/mtd/inftl.h>
+#include <asm/uaccess.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+
+/*
+ * Maximum number of loops while examining next block, to have a
+ * chance to detect consistency problems (they should never happen
+ * because of the checks done in the mounting.
+ */
+#define MAX_LOOPS 10000
+
+extern void INFTL_dumptables(struct INFTLrecord *inftl);
+extern void INFTL_dumpVUchains(struct INFTLrecord *inftl);
+
+static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
+{
+	struct INFTLrecord *inftl;
+	unsigned long temp;
+
+	if (mtd->ecctype != MTD_ECC_RS_DiskOnChip)
+		return;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name);
+
+	inftl = kmalloc(sizeof(*inftl), GFP_KERNEL);
+
+	if (!inftl) {
+		printk(KERN_WARNING "INFTL: Out of memory for data structures\n");
+		return;
+	}
+	memset(inftl, 0, sizeof(*inftl));
+
+	inftl->mbd.mtd = mtd;
+	inftl->mbd.devnum = -1;
+	inftl->mbd.blksize = 512;
+	inftl->mbd.tr = tr;
+
+        if (INFTL_mount(inftl) < 0) {
+		printk(KERN_WARNING "INFTL: could not mount device\n");
+		kfree(inftl);
+		return;
+        }
+
+	/* OK, it's a new one. Set up all the data structures. */
+
+	/* Calculate geometry */
+	inftl->cylinders = 1024;
+	inftl->heads = 16;
+
+	temp = inftl->cylinders * inftl->heads;
+	inftl->sectors = inftl->mbd.size / temp;
+	if (inftl->mbd.size % temp) {
+		inftl->sectors++;
+		temp = inftl->cylinders * inftl->sectors;
+		inftl->heads = inftl->mbd.size / temp;
+
+		if (inftl->mbd.size % temp) {
+			inftl->heads++;
+			temp = inftl->heads * inftl->sectors;
+			inftl->cylinders = inftl->mbd.size / temp;
+		}
+	}
+
+	if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) {
+		/*
+		  Oh no we don't have 
+		   mbd.size == heads * cylinders * sectors
+		*/
+		printk(KERN_WARNING "INFTL: cannot calculate a geometry to "
+		       "match size of 0x%lx.\n", inftl->mbd.size);
+		printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d "
+			"(== 0x%lx sects)\n",
+			inftl->cylinders, inftl->heads , inftl->sectors, 
+			(long)inftl->cylinders * (long)inftl->heads *
+			(long)inftl->sectors );
+	}
+
+	if (add_mtd_blktrans_dev) {
+		if (inftl->PUtable)
+			kfree(inftl->PUtable);
+		if (inftl->VUtable)
+			kfree(inftl->VUtable);
+		kfree(inftl);
+		return;
+	}
+#ifdef PSYCHO_DEBUG
+	printk(KERN_INFO "INFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a');
+#endif
+	return;
+}
+
+static void inftl_remove_dev(struct mtd_blktrans_dev *dev)
+{
+	struct INFTLrecord *inftl = (void *)dev;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: remove_dev (i=%d)\n", dev->devnum);
+
+	del_mtd_blktrans_dev(dev);
+
+	if (inftl->PUtable)
+		kfree(inftl->PUtable);
+	if (inftl->VUtable)
+		kfree(inftl->VUtable);
+	kfree(inftl);
+}
+
+/*
+ * Actual INFTL access routines.
+ */
+
+/*
+ * INFTL_findfreeblock: Find a free Erase Unit on the INFTL partition.
+ *	This function is used when the give Virtual Unit Chain.
+ */
+static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate)
+{
+	u16 pot = inftl->LastFreeEUN;
+	int silly = inftl->nb_blocks;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findfreeblock(inftl=0x%x,"
+		"desperate=%d)\n", (int)inftl, desperate);
+
+	/*
+	 * Normally, we force a fold to happen before we run out of free
+	 * blocks completely.
+	 */
+	if (!desperate && inftl->numfreeEUNs < 2) {
+		DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free "
+			"EUNs (%d)\n", inftl->numfreeEUNs);
+		return 0xffff;
+	}
+
+	/* Scan for a free block */
+	do {
+		if (inftl->PUtable[pot] == BLOCK_FREE) {
+			inftl->LastFreeEUN = pot;
+			return pot;
+		}
+
+		if (++pot > inftl->lastEUN)
+			pot = 0;
+
+		if (!silly--) {
+			printk(KERN_WARNING "INFTL: no free blocks found!  "
+				"EUN range = %d - %d\n", 0, inftl->LastFreeEUN);
+			return BLOCK_NIL;
+		}
+	} while (pot != inftl->LastFreeEUN);
+
+	return BLOCK_NIL;
+}
+
+static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned pendingblock)
+{
+	u16 BlockMap[MAX_SECTORS_PER_UNIT];
+	unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
+	unsigned int thisEUN, prevEUN, status;
+	int block, silly;
+	unsigned int targetEUN;
+	struct inftl_oob oob;
+        size_t retlen;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=0x%x,thisVUC=%d,"
+		"pending=%d)\n", (int)inftl, thisVUC, pendingblock);
+
+	memset(BlockMap, 0xff, sizeof(BlockMap));
+	memset(BlockDeleted, 0, sizeof(BlockDeleted));
+
+	thisEUN = targetEUN = inftl->VUtable[thisVUC];
+
+	if (thisEUN == BLOCK_NIL) {
+		printk(KERN_WARNING "INFTL: trying to fold non-existent "
+		       "Virtual Unit Chain %d!\n", thisVUC);
+		return BLOCK_NIL;
+	}
+	
+	/*
+	 * Scan to find the Erase Unit which holds the actual data for each
+	 * 512-byte block within the Chain.
+	 */
+        silly = MAX_LOOPS;
+	while (thisEUN < inftl->nb_blocks) {
+		for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) {
+			if ((BlockMap[block] != 0xffff) || BlockDeleted[block])
+				continue;
+
+			if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize)
+			     + (block * SECTORSIZE), 16 , &retlen,
+			     (char *)&oob) < 0)
+				status = SECTOR_IGNORE;
+			else
+                        	status = oob.b.Status | oob.b.Status1;
+
+			switch(status) {
+			case SECTOR_FREE:
+			case SECTOR_IGNORE:
+				break;
+			case SECTOR_USED:
+				BlockMap[block] = thisEUN;
+				continue;
+			case SECTOR_DELETED:
+				BlockDeleted[block] = 1;
+				continue;
+			default:
+				printk(KERN_WARNING "INFTL: unknown status "
+					"for block %d in EUN %d: %x\n",
+					block, thisEUN, status);
+				break;
+			}
+		}
+
+		if (!silly--) {
+			printk(KERN_WARNING "INFTL: infinite loop in Virtual "
+				"Unit Chain 0x%x\n", thisVUC);
+			return BLOCK_NIL;
+		}
+		
+		thisEUN = inftl->PUtable[thisEUN];
+	}
+
+	/*
+	 * OK. We now know the location of every block in the Virtual Unit
+	 * Chain, and the Erase Unit into which we are supposed to be copying.
+	 * Go for it.
+	 */
+	DEBUG(MTD_DEBUG_LEVEL1, "INFTL: folding chain %d into unit %d\n",
+		thisVUC, targetEUN);
+
+	for (block = 0; block < inftl->EraseSize/SECTORSIZE ; block++) {
+		unsigned char movebuf[SECTORSIZE];
+		int ret;
+
+		/*
+		 * If it's in the target EUN already, or if it's pending write,
+		 * do nothing.
+		 */
+		if (BlockMap[block] == targetEUN || (pendingblock ==
+		    (thisVUC * (inftl->EraseSize / SECTORSIZE) + block))) {
+			continue;
+		}
+
+                /*
+		 * Copy only in non free block (free blocks can only
+                 * happen in case of media errors or deleted blocks).
+		 */
+                if (BlockMap[block] == BLOCK_NIL)
+                        continue;
+                
+                ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize *
+			BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
+			&retlen, movebuf, (char *)&oob, NULL); 
+                if (ret < 0) {
+			ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize *
+				BlockMap[block]) + (block * SECTORSIZE),
+				SECTORSIZE, &retlen, movebuf, (char *)&oob,
+				NULL); 
+			if (ret != -EIO) 
+                        	DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
+					"away on retry?\n");
+                }
+                MTD_WRITEECC(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
+			(block * SECTORSIZE), SECTORSIZE, &retlen,
+			movebuf, (char *)&oob, NULL);
+	}
+
+	/*
+	 * Newest unit in chain now contains data from _all_ older units.
+	 * So go through and erase each unit in chain, oldest first. (This
+	 * is important, by doing oldest first if we crash/reboot then it
+	 * it is relatively simple to clean up the mess).
+	 */
+	DEBUG(MTD_DEBUG_LEVEL1, "INFTL: want to erase virtual chain %d\n",
+		thisVUC);
+
+	for (;;) {
+		/* Find oldest unit in chain. */
+		thisEUN = inftl->VUtable[thisVUC];
+		prevEUN = BLOCK_NIL;
+		while (inftl->PUtable[thisEUN] != BLOCK_NIL) {
+			prevEUN = thisEUN;
+			thisEUN = inftl->PUtable[thisEUN];
+		}
+
+		/* Check if we are all done */
+		if (thisEUN == targetEUN)
+			break;
+
+                if (INFTL_formatblock(inftl, thisEUN) < 0) {
+			/*
+			 * Could not erase : mark block as reserved.
+			 * FixMe: Update Bad Unit Table on disk.
+			 */
+			inftl->PUtable[thisEUN] = BLOCK_RESERVED;
+                } else {
+			/* Correctly erased : mark it as free */
+			inftl->PUtable[thisEUN] = BLOCK_FREE;
+			inftl->PUtable[prevEUN] = BLOCK_NIL;
+			inftl->numfreeEUNs++;
+                }
+	}
+
+	return targetEUN;
+}
+
+u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock)
+{
+	/*
+	 * This is the part that needs some cleverness applied. 
+	 * For now, I'm doing the minimum applicable to actually
+	 * get the thing to work.
+	 * Wear-levelling and other clever stuff needs to be implemented
+	 * and we also need to do some assessment of the results when
+	 * the system loses power half-way through the routine.
+	 */
+	u16 LongestChain = 0;
+	u16 ChainLength = 0, thislen;
+	u16 chain, EUN;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_makefreeblock(inftl=0x%x,"
+		"pending=%d)\n", (int)inftl, pendingblock);
+
+	for (chain = 0; chain < inftl->nb_blocks; chain++) {
+		EUN = inftl->VUtable[chain];
+		thislen = 0;
+
+		while (EUN <= inftl->lastEUN) {
+			thislen++;
+			EUN = inftl->PUtable[EUN];
+			if (thislen > 0xff00) {
+				printk(KERN_WARNING "INFTL: endless loop in "
+					"Virtual Chain %d: Unit %x\n",
+					chain, EUN);
+				/*
+				 * Actually, don't return failure.
+				 * Just ignore this chain and get on with it.
+				 */
+				thislen = 0;
+				break;
+			}
+		}
+
+		if (thislen > ChainLength) {
+			ChainLength = thislen;
+			LongestChain = chain;
+		}
+	}
+
+	if (ChainLength < 2) {
+		printk(KERN_WARNING "INFTL: no Virtual Unit Chains available "
+			"for folding. Failing request\n");
+		return BLOCK_NIL;
+	}
+
+	return INFTL_foldchain(inftl, LongestChain, pendingblock);
+}
+
+static int nrbits(unsigned int val, int bitcount)
+{
+	int i, total = 0;
+
+	for (i = 0; (i < bitcount); i++)
+		total += (((0x1 << i) & val) ? 1 : 0);
+	return total;
+}
+
+/*
+ * INFTL_findwriteunit: Return the unit number into which we can write 
+ *                      for this block. Make it available if it isn't already.
+ */
+static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
+{
+	unsigned int thisVUC = block / (inftl->EraseSize / SECTORSIZE);
+	unsigned int thisEUN, writeEUN, prev_block, status;
+	unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize -1);
+	struct inftl_oob oob;
+	struct inftl_bci bci;
+	unsigned char anac, nacs, parity;
+	size_t retlen;
+	int silly, silly2 = 3;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=0x%x,"
+		"block=%d)\n", (int)inftl, block);
+
+	do {
+		/*
+		 * Scan the media to find a unit in the VUC which has
+		 * a free space for the block in question.
+		 */
+		writeEUN = BLOCK_NIL;
+		thisEUN = inftl->VUtable[thisVUC];
+		silly = MAX_LOOPS;
+
+		while (thisEUN <= inftl->lastEUN) {
+			MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
+				blockofs, 8, &retlen, (char *)&bci);
+
+                        status = bci.Status | bci.Status1;
+			DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in "
+				"EUN %d is %x\n", block , writeEUN, status);
+
+			switch(status) {
+			case SECTOR_FREE:
+				writeEUN = thisEUN;
+				break;
+			case SECTOR_DELETED:
+			case SECTOR_USED:
+				/* Can't go any further */
+				goto hitused;
+			case SECTOR_IGNORE:
+				break;
+			default:
+				/*
+				 * Invalid block. Don't use it any more.
+				 * Must implement.
+				 */
+				break;			
+			}
+			
+			if (!silly--) { 
+				printk(KERN_WARNING "INFTL: infinite loop in "
+					"Virtual Unit Chain 0x%x\n", thisVUC);
+				return 0xffff;
+			}
+
+			/* Skip to next block in chain */
+			thisEUN = inftl->PUtable[thisEUN];
+		}
+
+hitused:
+		if (writeEUN != BLOCK_NIL)
+			return writeEUN;
+
+
+		/*
+		 * OK. We didn't find one in the existing chain, or there 
+		 * is no existing chain. Allocate a new one.
+		 */
+		writeEUN = INFTL_findfreeblock(inftl, 0);
+
+		if (writeEUN == BLOCK_NIL) {
+			/*
+			 * That didn't work - there were no free blocks just
+			 * waiting to be picked up. We're going to have to fold
+			 * a chain to make room.
+			 */
+			thisEUN = INFTL_makefreeblock(inftl, 0xffff);
+
+			/*
+			 * Hopefully we free something, lets try again.
+			 * This time we are desperate...
+			 */
+			DEBUG(MTD_DEBUG_LEVEL1, "INFTL: using desperate==1 "
+				"to find free EUN to accommodate write to "
+				"VUC %d\n", thisVUC);
+			writeEUN = INFTL_findfreeblock(inftl, 1);
+			if (writeEUN == BLOCK_NIL) {
+				/*
+				 * Ouch. This should never happen - we should
+				 * always be able to make some room somehow. 
+				 * If we get here, we've allocated more storage 
+				 * space than actual media, or our makefreeblock
+				 * routine is missing something.
+				 */
+				printk(KERN_WARNING "INFTL: cannot make free "
+					"space.\n");
+#ifdef DEBUG
+				INFTL_dumptables(inftl);
+				INFTL_dumpVUchains(inftl);
+#endif
+				return BLOCK_NIL;
+			}			
+		}
+
+		/*
+		 * Insert new block into virtual chain. Firstly update the
+		 * block headers in flash...
+		 */
+		anac = 0;
+		nacs = 0;
+		thisEUN = inftl->VUtable[thisVUC];
+		if (thisEUN != BLOCK_NIL) {
+			MTD_READOOB(inftl->mbd.mtd, thisEUN * inftl->EraseSize
+				+ 8, 8, &retlen, (char *)&oob.u);
+			anac = oob.u.a.ANAC + 1;
+			nacs = oob.u.a.NACs + 1;
+		}
+
+		prev_block = inftl->VUtable[thisVUC];
+		if (prev_block < inftl->nb_blocks)
+			prev_block -= inftl->firstEUN;
+
+		parity = (nrbits(thisVUC, 16) & 0x1) ? 0x1 : 0;
+		parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0;
+		parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0;
+		parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0;
+ 
+		oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC);
+		oob.u.a.prevUnitNo = cpu_to_le16(prev_block);
+		oob.u.a.ANAC = anac;
+		oob.u.a.NACs = nacs;
+		oob.u.a.parityPerField = parity;
+		oob.u.a.discarded = 0xaa;
+
+		MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + 8, 8,
+			&retlen, (char *)&oob.u);
+
+		/* Also back up header... */
+		oob.u.b.virtualUnitNo = cpu_to_le16(thisVUC);
+		oob.u.b.prevUnitNo = cpu_to_le16(prev_block);
+		oob.u.b.ANAC = anac;
+		oob.u.b.NACs = nacs;
+		oob.u.b.parityPerField = parity;
+		oob.u.b.discarded = 0xaa;
+
+		MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + 
+			SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u);
+
+		inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC];
+		inftl->VUtable[thisVUC] = writeEUN;
+
+		inftl->numfreeEUNs--;
+		return writeEUN;
+
+	} while (silly2--);
+
+	printk(KERN_WARNING "INFTL: error folding to make room for Virtual "
+		"Unit Chain 0x%x\n", thisVUC);
+	return 0xffff;
+}
+
+/*
+ * Given a Virtual Unit Chain, see if it can be deleted, and if so do it.
+ */
+static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
+{
+	unsigned char BlockUsed[MAX_SECTORS_PER_UNIT];
+	unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT];
+	unsigned int thisEUN, prevEUN, status;
+	int block, silly;
+	struct inftl_bci bci;
+	size_t retlen;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=0x%x,"
+		"thisVUC=%d)\n", (int)inftl, thisVUC);
+
+	memset(BlockUsed, 0, sizeof(BlockUsed));
+	memset(BlockDeleted, 0, sizeof(BlockDeleted));
+
+	thisEUN = inftl->VUtable[thisVUC];
+	if (thisEUN == BLOCK_NIL) {
+		printk(KERN_WARNING "INFTL: trying to delete non-existent "
+		       "Virtual Unit Chain %d!\n", thisVUC);
+		return;
+	}
+	
+	/*
+	 * Scan through the Erase Units to determine whether any data is in
+	 * each of the 512-byte blocks within the Chain.
+	 */
+	silly = MAX_LOOPS;
+	while (thisEUN < inftl->nb_blocks) {
+		for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++) {
+			if (BlockUsed[block] || BlockDeleted[block])
+				continue;
+
+			if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize)
+			    + (block * SECTORSIZE), 8 , &retlen,
+			    (char *)&bci) < 0)
+				status = SECTOR_IGNORE;
+			else
+				status = bci.Status | bci.Status1;
+
+			switch(status) {
+			case SECTOR_FREE:
+			case SECTOR_IGNORE:
+				break;
+			case SECTOR_USED:
+				BlockUsed[block] = 1;
+				continue;
+			case SECTOR_DELETED:
+				BlockDeleted[block] = 1;
+				continue;
+			default:
+				printk(KERN_WARNING "INFTL: unknown status "
+					"for block %d in EUN %d: 0x%x\n",
+					block, thisEUN, status);
+			}
+		}
+
+		if (!silly--) {
+			printk(KERN_WARNING "INFTL: infinite loop in Virtual "
+				"Unit Chain 0x%x\n", thisVUC);
+			return;
+		}
+		
+		thisEUN = inftl->PUtable[thisEUN];
+	}
+
+	for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++)
+		if (BlockUsed[block])
+			return;
+
+	/*
+	 * For each block in the chain free it and make it available
+	 * for future use. Erase from the oldest unit first.
+	 */
+	DEBUG(MTD_DEBUG_LEVEL1, "INFTL: deleting empty VUC %d\n", thisVUC);
+
+	for (;;) {
+		/* Find oldest unit in chain. */
+		thisEUN = inftl->VUtable[thisVUC];
+		prevEUN = BLOCK_NIL;
+		while (inftl->PUtable[thisEUN] != BLOCK_NIL) {
+			prevEUN = thisEUN;
+			thisEUN = inftl->PUtable[thisEUN];
+		}
+
+                if (INFTL_formatblock(inftl, thisEUN) < 0) {
+			/*
+			 * Could not erase : mark block as reserved.
+			 * FixMe: Update Bad Unit Table on disk.
+			 */
+			inftl->PUtable[thisEUN] = BLOCK_RESERVED;
+                } else {
+			/* Correctly erased : mark it as free */
+			inftl->PUtable[thisEUN] = BLOCK_FREE;
+			inftl->PUtable[prevEUN] = BLOCK_NIL;
+			inftl->numfreeEUNs++;
+                }
+	}
+
+	inftl->VUtable[thisVUC] = BLOCK_NIL;
+}
+
+static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block)
+{
+	unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
+	unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
+	unsigned int status;
+	int silly = MAX_LOOPS;
+	size_t retlen;
+	struct inftl_bci bci;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=0x%x,"
+		"block=%d)\n", (int)inftl, block);
+
+	while (thisEUN < inftl->nb_blocks) {
+		if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
+		    blockofs, 8, &retlen, (char *)&bci) < 0)
+			status = SECTOR_IGNORE;
+		else
+			status = bci.Status | bci.Status1;
+
+		switch (status) {
+		case SECTOR_FREE:
+		case SECTOR_IGNORE:
+			break;
+		case SECTOR_DELETED:
+			thisEUN = BLOCK_NIL;
+			goto foundit;
+		case SECTOR_USED:
+			goto foundit;
+		default:
+			printk(KERN_WARNING "INFTL: unknown status for "
+				"block %d in EUN %d: 0x%x\n",
+				block, thisEUN, status);
+			break;
+		}
+
+		if (!silly--) {
+			printk(KERN_WARNING "INFTL: infinite loop in Virtual "
+				"Unit Chain 0x%x\n",
+				block / (inftl->EraseSize / SECTORSIZE));
+			return 1;
+		}
+		thisEUN = inftl->PUtable[thisEUN];
+	}
+
+foundit:
+	if (thisEUN != BLOCK_NIL) {
+		loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
+
+		if (MTD_READOOB(inftl->mbd.mtd, ptr, 8, &retlen, (char *)&bci) < 0)
+			return -EIO;
+		bci.Status = bci.Status1 = SECTOR_DELETED;
+		if (MTD_WRITEOOB(inftl->mbd.mtd, ptr, 8, &retlen, (char *)&bci) < 0)
+			return -EIO;
+		INFTL_trydeletechain(inftl, block / (inftl->EraseSize / SECTORSIZE));
+	}
+	return 0;
+}
+
+static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, 
+			    char *buffer)
+{
+	struct INFTLrecord *inftl = (void *)mbd;
+	unsigned int writeEUN;
+	unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
+	size_t retlen;
+	u8 eccbuf[6];
+	char *p, *pend;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=0x%x,block=%d,"
+		"buffer=0x%x)\n", (int)inftl, block, (int)buffer);
+
+	/* Is block all zero? */
+	pend = buffer + SECTORSIZE;
+	for (p = buffer; p < pend && !*p; p++)
+		;
+
+	if (p < pend) {
+		writeEUN = INFTL_findwriteunit(inftl, block);
+
+		if (writeEUN == BLOCK_NIL) {
+			printk(KERN_WARNING "inftl_writeblock(): cannot find "
+				"block to write to\n");
+			/*
+			 * If we _still_ haven't got a block to use,
+			 * we're screwed.
+			 */
+			return 1;
+		}
+
+		MTD_WRITEECC(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
+			blockofs, SECTORSIZE, &retlen, (char *)buffer,
+			(char *)eccbuf, NULL);
+		/*
+		 * No need to write SECTOR_USED flags since they are written
+		 * in mtd_writeecc
+		 */
+	} else {
+		INFTL_deleteblock(inftl, block);
+	}
+
+	return 0;
+}
+
+static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
+			   char *buffer)
+{
+	struct INFTLrecord *inftl = (void *)mbd;
+	unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
+	unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
+        unsigned int status;
+	int silly = MAX_LOOPS;
+        struct inftl_bci bci;
+	size_t retlen;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=0x%x,block=%d,"
+		"buffer=0x%x)\n", (int)inftl, block, (int)buffer);
+
+	while (thisEUN < inftl->nb_blocks) {
+		if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
+		     blockofs, 8, &retlen, (char *)&bci) < 0)
+			status = SECTOR_IGNORE;
+		else
+			status = bci.Status | bci.Status1;
+
+		switch (status) {
+		case SECTOR_DELETED:
+			thisEUN = BLOCK_NIL;
+			goto foundit;
+		case SECTOR_USED:
+			goto foundit;
+		case SECTOR_FREE:
+		case SECTOR_IGNORE:
+			break;
+		default:
+			printk(KERN_WARNING "INFTL: unknown status for "
+				"block %ld in EUN %d: 0x%04x\n",
+				block, thisEUN, status);
+			break;
+		}
+
+		if (!silly--) {
+			printk(KERN_WARNING "INFTL: infinite loop in "
+				"Virtual Unit Chain 0x%lx\n",
+				block / (inftl->EraseSize / SECTORSIZE));
+			return 1;
+		}
+
+		thisEUN = inftl->PUtable[thisEUN];
+	}
+
+foundit:
+	if (thisEUN == BLOCK_NIL) {
+		/* The requested block is not on the media, return all 0x00 */
+		memset(buffer, 0, SECTORSIZE);
+	} else {
+        	size_t retlen;
+		loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
+		u_char eccbuf[6];
+		if (MTD_READECC(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
+		    buffer, eccbuf, NULL))
+			return -EIO;
+	}
+	return 0;
+}
+
+
+static int inftl_ioctl(struct mtd_blktrans_dev *dev,
+		     struct inode *inode, struct file *file, 
+		     unsigned int cmd, unsigned long arg)
+{
+	struct NFTLrecord *nftl = (void *)dev;
+
+	switch (cmd) {
+	case HDIO_GETGEO: {
+		struct hd_geometry g;
+
+		g.heads = nftl->heads;
+		g.sectors = nftl->sectors;
+		g.cylinders = nftl->cylinders;
+		g.start = 0;
+		return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0;
+	}
+
+	default:
+		return -ENOTTY;
+	}
+}
+
+
+struct mtd_blktrans_ops inftl_tr = {
+	.name		= "inftl",
+	.major		= INFTL_MAJOR,
+	.part_bits	= INFTL_PARTN_BITS,
+	.ioctl		= inftl_ioctl,
+	.readsect	= inftl_readblock,
+	.writesect	= inftl_writeblock,
+	.add_mtd	= inftl_add_mtd,
+	.remove_dev	= inftl_remove_dev,
+	.owner		= THIS_MODULE,
+};
+
+extern char inftlmountrev[];
+
+int __init init_inftl(void)
+{
+	printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.9 $, "
+		"inftlmount.c %s\n", inftlmountrev);
+
+	return register_mtd_blktrans(&inftl_tr);
+}
+
+static void __exit cleanup_inftl(void)
+{
+	deregister_mtd_blktrans(&inftl_tr);
+}
+
+module_init(init_inftl);
+module_exit(cleanup_inftl);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>, David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
+MODULE_DESCRIPTION("Support code for Inverse Flash Translation Layer, used on M-Systems DiskOnChip 2000, Millennium and Millennium Plus");
diff -Nru a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/inftlmount.c	Wed May 28 08:01:12 2003
@@ -0,0 +1,815 @@
+/* 
+ * inftlmount.c -- INFTL mount code with extensive checks.
+ *
+ * Author: Greg Ungerer (gerg@snapgear.com)
+ * (C) Copyright 2002-2003, Greg Ungerer (gerg@snapgear.com)
+ *
+ * Based heavily on the nftlmount.c code which is:
+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
+ * Copyright (C) 2000 Netgem S.A.
+ *
+ * $Id: inftlmount.c,v 1.9 2003/05/23 11:35:07 dwmw2 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.
+ *
+ * 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 __NO_VERSION__
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nftl.h>
+#include <linux/mtd/inftl.h>
+#include <linux/mtd/compatmac.h>
+
+char inftlmountrev[]="$Revision: 1.9 $";
+
+/*
+ * find_boot_record: Find the INFTL Media Header and its Spare copy which
+ *	contains the various device information of the INFTL partition and
+ *	Bad Unit Table. Update the PUtable[] table according to the Bad
+ *	Unit Table. PUtable[] is used for management of Erase Unit in
+ *	other routines in inftlcore.c and inftlmount.c.
+ */
+static int find_boot_record(struct INFTLrecord *inftl)
+{
+	struct inftl_unittail h1;
+	//struct inftl_oob oob;
+	unsigned int i, block, boot_record_count = 0;
+	u8 buf[SECTORSIZE];
+	struct INFTLMediaHeader *mh = &inftl->MediaHdr;
+	struct INFTLPartition *ip;
+	int retlen;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: find_boot_record(inftl=0x%x)\n",
+		(int)inftl);
+
+        /*
+	 * Assume logical EraseSize == physical erasesize for starting the
+	 * scan. We'll sort it out later if we find a MediaHeader which says
+	 * otherwise.
+	 */
+	inftl->EraseSize = inftl->mbd.mtd->erasesize;
+        inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;
+
+	inftl->MediaUnit = BLOCK_NIL;
+	inftl->SpareMediaUnit = BLOCK_NIL;
+
+	/* Search for a valid boot record */
+	for (block = 0; block < inftl->nb_blocks; block++) {
+		int ret;
+
+		/*
+		 * Check for BNAND header first. Then whinge if it's found
+		 * but later checks fail.
+		 */
+		if ((ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize,
+		    SECTORSIZE, &retlen, buf))) {
+			static int warncount = 5;
+
+			if (warncount) {
+				printk(KERN_WARNING "INFTL: block read at 0x%x "
+					"of mtd%d failed: %d\n",
+					block * inftl->EraseSize,
+					inftl->mbd.mtd->index, ret);
+				if (!--warncount)
+					printk(KERN_WARNING "INFTL: further "
+						"failures for this block will "
+						"not be printed\n");
+			}
+			continue;
+		}
+
+		if (retlen < 6 || memcmp(buf, "BNAND", 6)) {
+			/* BNAND\0 not found. Continue */
+			continue;
+		}
+
+		/* To be safer with BIOS, also use erase mark as discriminant */
+		if ((ret = MTD_READOOB(inftl->mbd.mtd, block * inftl->EraseSize +
+		    SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0)) {
+			printk(KERN_WARNING "INFTL: ANAND header found at "
+				"0x%x in mtd%d, but OOB data read failed "
+				"(err %d)\n", block * inftl->EraseSize,
+				inftl->mbd.mtd->index, ret);
+			continue;
+		}
+
+		if (boot_record_count) {
+			/*
+			 * We've already processed one. So we just check if
+			 * this one is the same as the first one we found.
+			 */
+			if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) {
+				printk(KERN_WARNING "INFTL: Media Headers at "
+					"0x%x and 0x%x disagree.\n",
+					inftl->MediaUnit * inftl->EraseSize,
+					block * inftl->EraseSize);
+				return -1;
+			}
+			if (boot_record_count == 1)
+				inftl->SpareMediaUnit = block;
+
+			/*
+			 * Mark this boot record (INFTL MediaHeader) block as
+			 * reserved.
+			 */
+			inftl->PUtable[block] = BLOCK_RESERVED;
+
+			boot_record_count++;
+			continue;
+		}
+
+		/*
+		 * This is the first we've seen.
+		 * Copy the media header structure into place.
+		 */
+		memcpy(mh, buf, sizeof(struct INFTLMediaHeader));
+		mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks);
+		mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions);
+		mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions);
+		mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits);
+		mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
+		mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
+
+#ifdef CONFIG_MTD_DEBUG_VERBOSE
+		if (CONFIG_MTD_DEBUG_VERBOSE >= 2) {
+			printk("INFTL: Media Header ->\n"
+				"    bootRecordID          = %s\n"
+				"    NoOfBootImageBlocks   = %d\n"
+				"    NoOfBinaryPartitions  = %d\n"
+				"    NoOfBDTLPartitions    = %d\n"
+				"    BlockMultiplerBits    = %d\n"
+				"    FormatFlgs            = %d\n"
+				"    OsakVersion           = 0x%x\n"
+				"    PercentUsed           = %d\n",
+				mh->bootRecordID, mh->NoOfBootImageBlocks,
+				mh->NoOfBinaryPartitions,
+				mh->NoOfBDTLPartitions,
+				mh->BlockMultiplierBits, mh->FormatFlags,
+				mh->OsakVersion, mh->PercentUsed);
+		}
+#endif
+
+		if (mh->NoOfBDTLPartitions == 0) {
+			printk(KERN_WARNING "INFTL: Media Header sanity check "
+				"failed: NoOfBDTLPartitions (%d) == 0, "
+				"must be at least 1\n", mh->NoOfBDTLPartitions);
+			return -1;
+		}
+
+		if ((mh->NoOfBDTLPartitions + mh->NoOfBinaryPartitions) > 4) {
+			printk(KERN_WARNING "INFTL: Media Header sanity check "
+				"failed: Total Partitions (%d) > 4, "
+				"BDTL=%d Binary=%d\n", mh->NoOfBDTLPartitions +
+				mh->NoOfBinaryPartitions,
+				mh->NoOfBDTLPartitions,
+				mh->NoOfBinaryPartitions);
+			return -1;
+		}
+
+		if (mh->BlockMultiplierBits > 1) {
+			printk(KERN_WARNING "INFTL: sorry, we don't support "
+				"UnitSizeFactor 0x%02x\n",
+				mh->BlockMultiplierBits);
+			return -1;
+		} else if (mh->BlockMultiplierBits == 1) {
+			printk(KERN_WARNING "INFTL: support for INFTL with "
+				"UnitSizeFactor 0x%02x is experimental\n",
+				mh->BlockMultiplierBits);
+			inftl->EraseSize = inftl->mbd.mtd->erasesize <<
+				(0xff - mh->BlockMultiplierBits);
+			inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;
+		}
+
+		/* Scan the partitions */
+		for (i = 0; (i < 4); i++) {
+			ip = &mh->Partitions[i];
+			ip->virtualUnits = le32_to_cpu(ip->virtualUnits);
+			ip->firstUnit = le32_to_cpu(ip->firstUnit);
+			ip->lastUnit = le32_to_cpu(ip->lastUnit);
+			ip->flags = le32_to_cpu(ip->flags);
+			ip->spareUnits = le32_to_cpu(ip->spareUnits);
+			ip->Reserved0 = le32_to_cpu(ip->Reserved0);
+
+#ifdef CONFIG_MTD_DEBUG_VERBOSE
+			if (CONFIG_MTD_DEBUG_VERBOSE >= 2) {
+				printk("    PARTITION[%d] ->\n"
+					"        virtualUnits    = %d\n"
+					"        firstUnit       = %d\n"
+					"        lastUnit        = %d\n"
+					"        flags           = 0x%x\n"
+					"        spareUnits      = %d\n",
+					i, ip->virtualUnits, ip->firstUnit,
+					ip->lastUnit, ip->flags,
+					ip->spareUnits);
+			}
+#endif
+
+			if (ip->Reserved0 != ip->firstUnit) {
+				struct erase_info *instr = &inftl->instr;
+
+				/*
+				 * 	Most likely this is using the
+				 * 	undocumented qiuck mount feature.
+				 * 	We don't support that, we will need
+				 * 	to erase the hidden block for full
+				 * 	compatibility.
+				 */
+				instr->addr = ip->Reserved0 * inftl->EraseSize;
+				instr->len = inftl->EraseSize;
+				MTD_ERASE(inftl->mbd.mtd, instr);
+			}
+			if ((ip->lastUnit - ip->firstUnit + 1) < ip->virtualUnits) {
+				printk(KERN_WARNING "INFTL: Media Header "
+					"Parition %d sanity check failed\n"
+					"    firstUnit %d : lastUnit %d  >  "
+					"virtualUnits %d\n", i, ip->lastUnit,
+					ip->firstUnit, ip->Reserved0);
+				return -1;
+			}
+			if (ip->Reserved1 != 0) {
+				printk(KERN_WARNING "INFTL: Media Header "
+					"Parition %d sanity check failed: "
+					"Reserved1 %d != 0\n",
+					i, ip->Reserved1);
+				return -1;
+			}
+
+			if (ip->flags & INFTL_BDTL)
+				break;
+		}
+
+		if (i >= 4) {
+			printk(KERN_WARNING "INFTL: Media Header Parition "
+				"sanity check failed:\n       No partition "
+				"marked as Disk Partition\n");
+			return -1;
+		}
+
+		inftl->nb_boot_blocks = ip->firstUnit;
+		inftl->numvunits = ip->virtualUnits;
+		if (inftl->numvunits > (inftl->nb_blocks -
+		    inftl->nb_boot_blocks - 2)) {
+			printk(KERN_WARNING "INFTL: Media Header sanity check "
+				"failed:\n        numvunits (%d) > nb_blocks "
+				"(%d) - nb_boot_blocks(%d) - 2\n",
+				inftl->numvunits, inftl->nb_blocks,
+				inftl->nb_boot_blocks);
+			return -1;
+		}
+		
+		inftl->mbd.size  = inftl->numvunits *
+			(inftl->EraseSize / SECTORSIZE);
+
+		/*
+		 * Block count is set to last used EUN (we won't need to keep
+		 * any meta-data past that point).
+		 */
+		inftl->firstEUN = ip->firstUnit;
+		inftl->lastEUN = ip->lastUnit;
+		inftl->nb_blocks = ip->lastUnit + 1;
+
+		/* Memory alloc */
+		inftl->PUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL);
+		if (!inftl->PUtable) {
+			printk(KERN_WARNING "INFTL: allocation of PUtable "
+				"failed (%d bytes)\n",
+				inftl->nb_blocks * sizeof(u16));
+			return -ENOMEM;
+		}
+
+		inftl->VUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL);
+		if (!inftl->VUtable) {
+			kfree(inftl->PUtable);
+			printk(KERN_WARNING "INFTL: allocation of VUtable "
+				"failed (%d bytes)\n",
+				inftl->nb_blocks * sizeof(u16));
+			return -ENOMEM;
+		}
+		
+		/* Mark the blocks before INFTL MediaHeader as reserved */
+		for (i = 0; i < inftl->nb_boot_blocks; i++)
+			inftl->PUtable[i] = BLOCK_RESERVED;
+		/* Mark all remaining blocks as potentially containing data */
+		for (; i < inftl->nb_blocks; i++)
+			inftl->PUtable[i] = BLOCK_NOTEXPLORED;
+
+		/* Mark this boot record (NFTL MediaHeader) block as reserved */
+		inftl->PUtable[block] = BLOCK_RESERVED;
+
+#if 0
+		/* Read Bad Erase Unit Table and modify PUtable[] accordingly */
+		for (i = 0; i < inftl->nb_blocks; i++) {
+			if ((i & (SECTORSIZE - 1)) == 0) {
+				/* read one sector for every SECTORSIZE of blocks */
+				if ((ret = MTD_READECC(inftl->mbd.mtd,
+				    block * inftl->EraseSize + i + SECTORSIZE,
+				    SECTORSIZE, &retlen, buf,
+				    (char *)&oob, NULL)) < 0) {
+					printk(KERN_WARNING "INFTL: read of "
+						"bad sector table failed "
+						"(err %d)\n", ret);
+					kfree(inftl->VUtable);
+					kfree(inftl->PUtable);
+					return -1;
+				}
+			}
+			/* Mark the Bad Erase Unit as RESERVED in PUtable */
+			if (buf[i & (SECTORSIZE - 1)] != 0xff)
+				inftl->PUtable[i] = BLOCK_RESERVED;
+		}
+#endif
+
+		inftl->MediaUnit = block;
+		boot_record_count++;
+	}
+		
+	return boot_record_count ? 0 : -1;
+}
+
+static int memcmpb(void *a, int c, int n)
+{
+	int i;
+	for (i = 0; i < n; i++) {
+		if (c != ((unsigned char *)a)[i])
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * check_free_sector: check if a free sector is actually FREE,
+ *	i.e. All 0xff in data and oob area.
+ */
+static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
+	int len, int check_oob)
+{
+	int i, retlen;
+	u8 buf[SECTORSIZE];
+
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=0x%x,"
+		"address=0x%x,len=%d,check_oob=%d)\n", (int)inftl,
+		address, len, check_oob);
+
+	for (i = 0; i < len; i += SECTORSIZE) {
+		/*
+		 * We want to read the sector without ECC check here since a
+		 * free sector does not have ECC syndrome on it yet.
+		 */
+		if (MTD_READ(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0)
+			return -1;
+		if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
+			return -1;
+
+		if (check_oob) {
+			if (MTD_READOOB(inftl->mbd.mtd, address,
+			    inftl->mbd.mtd->oobsize, &retlen, buf) < 0)
+				return -1;
+			if (memcmpb(buf, 0xff, inftl->mbd.mtd->oobsize) != 0)
+				return -1;
+		}
+		address += SECTORSIZE;
+	}
+
+	return 0;
+}
+
+/*
+ * INFTL_format: format a Erase Unit by erasing ALL Erase Zones in the Erase
+ *		 Unit and Update INFTL metadata. Each erase operation is
+ *		 checked with check_free_sectors.
+ *
+ * Return: 0 when succeed, -1 on error.
+ *
+ * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? 
+ *       2. UnitSizeFactor != 0xFF
+ */
+int INFTL_formatblock(struct INFTLrecord *inftl, int block)
+{
+	int retlen;
+	struct inftl_unittail uci;
+	struct erase_info *instr = &inftl->instr;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=0x%x,"
+		"block=%d)\n", (int)inftl, block);
+
+	memset(instr, 0, sizeof(struct erase_info));
+
+	/* Use async erase interface, test return code */
+	instr->addr = block * inftl->EraseSize;
+	instr->len = inftl->EraseSize;
+	MTD_ERASE(inftl->mbd.mtd, instr);
+
+	if (instr->state == MTD_ERASE_FAILED) {
+		/*
+		 * Could not format, FixMe: We should update the BadUnitTable 
+		 * both in memory and on disk.
+		 */
+		printk(KERN_WARNING "INFTL: error while formatting block %d\n",
+			block);
+		return -1;
+	}
+
+	/*
+	 * Check the "freeness" of Erase Unit before updating metadata.
+	 * FixMe: is this check really necessary? Since we have check the
+	 *        return code after the erase operation.
+	 */
+	if (check_free_sectors(inftl, instr->addr, inftl->EraseSize, 1) != 0)
+		return -1;
+
+	uci.EraseMark = cpu_to_le16(ERASE_MARK);
+	uci.EraseMark1 = cpu_to_le16(ERASE_MARK);
+	uci.Reserved[0] = 0;
+	uci.Reserved[1] = 0;
+	uci.Reserved[2] = 0;
+	uci.Reserved[3] = 0;
+	if (MTD_WRITEOOB(inftl->mbd.mtd, block * inftl->EraseSize + SECTORSIZE * 2 +
+	    8, 8, &retlen, (char *)&uci) < 0)
+		return -1;
+	return 0;
+}
+
+/*
+ * format_chain: Format an invalid Virtual Unit chain. It frees all the Erase
+ *	Units in a Virtual Unit Chain, i.e. all the units are disconnected.
+ *
+ *	Since the chain is invalid then we will have to erase it from its
+ *	head (normally for INFTL we go from the oldest). But if it has a
+ *	loop then there is no oldest...
+ */
+static void format_chain(struct INFTLrecord *inftl, unsigned int first_block)
+{
+	unsigned int block = first_block, block1;
+
+	printk(KERN_WARNING "INFTL: formatting chain at block %d\n",
+		first_block);
+
+	for (;;) {
+		block1 = inftl->PUtable[block];
+
+		printk(KERN_WARNING "INFTL: formatting block %d\n", block);
+		if (INFTL_formatblock(inftl, block) < 0) {
+			/*
+			 * Cannot format !!!! Mark it as Bad Unit,
+			 * FixMe: update the BadUnitTable on disk.
+			 */
+			inftl->PUtable[block] = BLOCK_RESERVED;
+		} else {
+			inftl->PUtable[block] = BLOCK_FREE;
+		}
+
+		/* Goto next block on the chain */
+		block = block1;
+
+		if (block == BLOCK_NIL || block >= inftl->lastEUN)
+			break;
+	}
+}
+
+void INFTL_dumptables(struct INFTLrecord *s)
+{
+	int i;
+
+	printk("-------------------------------------------"
+		"----------------------------------\n");
+
+	printk("VUtable[%d] ->", s->nb_blocks);
+	for (i = 0; i < s->nb_blocks; i++) {
+		if ((i % 8) == 0)
+			printk("\n%04x: ", i);
+		printk("%04x ", s->VUtable[i]);
+	}
+
+	printk("\n-------------------------------------------"
+		"----------------------------------\n");
+
+	printk("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks);
+	for (i = 0; i <= s->lastEUN; i++) {
+		if ((i % 8) == 0)
+			printk("\n%04x: ", i);
+		printk("%04x ", s->PUtable[i]);
+	}
+
+	printk("\n-------------------------------------------"
+		"----------------------------------\n");
+
+	printk("INFTL ->\n"
+		"  EraseSize       = %d\n"
+		"  h/s/c           = %d/%d/%d\n"
+		"  numvunits       = %d\n"
+		"  firstEUN        = %d\n"
+		"  lastEUN         = %d\n"
+		"  numfreeEUNs     = %d\n"
+		"  LastFreeEUN     = %d\n"
+		"  nb_blocks       = %d\n"
+		"  nb_boot_blocks  = %d",
+		s->EraseSize, s->heads, s->sectors, s->cylinders,
+		s->numvunits, s->firstEUN, s->lastEUN, s->numfreeEUNs,
+		s->LastFreeEUN, s->nb_blocks, s->nb_boot_blocks);
+
+	printk("\n-------------------------------------------"
+		"----------------------------------\n");
+}
+
+void INFTL_dumpVUchains(struct INFTLrecord *s)
+{
+	int logical, block, i;
+
+	printk("-------------------------------------------"
+		"----------------------------------\n");
+
+	printk("INFTL Virtual Unit Chains:\n");
+	for (logical = 0; logical < s->nb_blocks; logical++) {
+		block = s->VUtable[logical];
+		if (block > s->nb_blocks)
+			continue;
+		printk("  LOGICAL %d --> %d ", logical, block);
+		for (i = 0; i < s->nb_blocks; i++) {
+			if (s->PUtable[block] == BLOCK_NIL)
+				break;
+			block = s->PUtable[block];
+			printk("%d ", block);
+		}
+		printk("\n");
+	}
+
+	printk("-------------------------------------------"
+		"----------------------------------\n");
+}
+
+int INFTL_mount(struct INFTLrecord *s)
+{
+	unsigned int block, first_block, prev_block, last_block;
+	unsigned int first_logical_block, logical_block, erase_mark;
+	int chain_length, do_format_chain;
+	struct inftl_unithead1 h0;
+	struct inftl_unittail h1;
+	int i, retlen;
+	u8 *ANACtable, ANAC;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_mount(inftl=0x%x)\n", (int)s);
+
+	/* Search for INFTL MediaHeader and Spare INFTL Media Header */
+	if (find_boot_record(s) < 0) {
+		printk(KERN_WARNING "INFTL: could not find valid boot record?\n");
+		return -1;
+	}
+
+	/* Init the logical to physical table */
+	for (i = 0; i < s->nb_blocks; i++)
+		s->VUtable[i] = BLOCK_NIL;
+
+	logical_block = block = BLOCK_NIL;
+
+	/* Temporary buffer to store ANAC numbers. */
+	ANACtable = kmalloc(s->nb_blocks * sizeof(u8), GFP_KERNEL);
+	memset(ANACtable, 0, s->nb_blocks);
+
+	/*
+	 * First pass is to explore each physical unit, and construct the
+	 * virtual chains that exist (newest physical unit goes into VUtable).
+	 * Any block that is in any way invalid will be left in the
+	 * NOTEXPLORED state. Then at the end we will try to format it and
+	 * mark it as free.
+	 */
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 1, explore each unit\n");
+	for (first_block = s->firstEUN; first_block <= s->lastEUN; first_block++) {
+		if (s->PUtable[first_block] != BLOCK_NOTEXPLORED)
+			continue;
+
+		do_format_chain = 0;
+		first_logical_block = BLOCK_NIL;
+		last_block = BLOCK_NIL;
+		block = first_block;
+
+		for (chain_length = 0; ; chain_length++) {
+
+			if ((chain_length == 0) && 
+			    (s->PUtable[block] != BLOCK_NOTEXPLORED)) {
+				/* Nothing to do here, onto next block */
+				break;
+			}
+
+			if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8,
+			    8, &retlen, (char *)&h0) < 0 ||
+			    MTD_READOOB(s->mbd.mtd, block * s->EraseSize +
+			    2 * SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) {
+				/* Should never happen? */
+				do_format_chain++;
+				break;
+			}
+
+			logical_block = le16_to_cpu(h0.virtualUnitNo);
+			prev_block = le16_to_cpu(h0.prevUnitNo);
+			erase_mark = le16_to_cpu((h1.EraseMark | h1.EraseMark1));
+			ANACtable[block] = h0.ANAC;
+
+			/* Previous block is relative to start of Partition */
+			if (prev_block < s->nb_blocks)
+				prev_block += s->firstEUN;
+
+			/* Already explored paritial chain? */
+			if (s->PUtable[block] != BLOCK_NOTEXPLORED) {
+				/* Check if chain for this logical */
+				if (logical_block == first_logical_block) {
+					if (last_block != BLOCK_NIL)
+						s->PUtable[last_block] = block;
+				}
+				break;
+			}
+
+			/* Check for invalid block */
+			if (erase_mark != ERASE_MARK) {
+				printk(KERN_WARNING "INFTL: corrupt block %d "
+					"in chain %d, chain length %d, erase "
+					"mark 0x%x?\n", block, first_block,
+					chain_length, erase_mark);
+				/*
+				 * Assume end of chain, probably incomplete
+				 * fold/erase...
+				 */
+				if (chain_length == 0)
+					do_format_chain++;
+				break;
+			}
+
+			/* Check for it being free already then... */
+			if ((logical_block == BLOCK_FREE) ||
+			    (logical_block == BLOCK_NIL)) {
+				s->PUtable[block] = BLOCK_FREE;
+				break;
+			}
+
+			/* Sanity checks on block numbers */
+			if ((logical_block >= s->nb_blocks) ||
+			    ((prev_block >= s->nb_blocks) &&
+			     (prev_block != BLOCK_NIL))) {
+				if (chain_length > 0) {
+					printk(KERN_WARNING "INFTL: corrupt "
+						"block %d in chain %d?\n",
+						block, first_block);
+					do_format_chain++;
+				}
+				break;
+			}
+
+			if (first_logical_block == BLOCK_NIL) {
+				first_logical_block = logical_block;
+			} else {
+				if (first_logical_block != logical_block) {
+					/* Normal for folded chain... */
+					break;
+				}
+			}
+
+			/*
+			 * Current block is valid, so if we followed a virtual
+			 * chain to get here then we can set the previous
+			 * block pointer in our PUtable now. Then move onto
+			 * the previous block in the chain.
+			 */
+			s->PUtable[block] = BLOCK_NIL;
+			if (last_block != BLOCK_NIL)
+				s->PUtable[last_block] = block;
+			last_block = block;
+			block = prev_block;
+
+			/* Check for end of chain */
+			if (block == BLOCK_NIL)
+				break;
+
+			/* Validate next block before following it... */
+			if (block > s->lastEUN) {
+				printk(KERN_WARNING "INFTL: invalid previous "
+					"block %d in chain %d?\n", block,
+					first_block);
+				do_format_chain++;
+				break;
+			}
+		}
+
+		if (do_format_chain) {
+			format_chain(s, first_block);
+			continue;
+		}
+
+		/*
+		 * Looks like a valid chain then. It may not really be the
+		 * newest block in the chain, but it is the newest we have
+		 * found so far. We might update it in later iterations of
+		 * this loop if we find something newer.
+		 */
+		s->VUtable[first_logical_block] = first_block;
+		logical_block = BLOCK_NIL;
+	}
+
+#ifdef CONFIG_MTD_DEBUG_VERBOSE
+	if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
+		INFTL_dumptables(s);
+#endif
+
+	/*
+	 * Second pass, check for infinite loops in chains. These are
+	 * possible because we don't update the previous pointers when
+	 * we fold chains. No big deal, just fix them up in PUtable.
+	 */
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 2, validate virtual chains\n");
+	for (logical_block = 0; logical_block < s->numvunits; logical_block++) {
+		block = s->VUtable[logical_block];
+		last_block = BLOCK_NIL;
+
+		/* Check for free/reserved/nil */
+		if (block >= BLOCK_RESERVED)
+			continue;
+
+		ANAC = ANACtable[block];
+		for (i = 0; i < s->numvunits; i++) {
+			if (s->PUtable[block] == BLOCK_NIL)
+				break;
+			if (s->PUtable[block] > s->lastEUN) {
+				printk(KERN_WARNING "INFTL: invalid prev %d, "
+					"in virtual chain %d\n",
+					s->PUtable[block], logical_block);
+				s->PUtable[block] = BLOCK_NIL;
+					
+			}
+			if (ANACtable[block] != ANAC) {
+				/*
+				 * Chain must point back to itself. This is ok,
+				 * but we will need adjust the tables with this
+				 * newest block and oldest block.
+				 */
+				s->VUtable[logical_block] = block;
+				s->PUtable[last_block] = BLOCK_NIL;
+				break;
+			}
+
+			ANAC--;
+			last_block = block;
+			block = s->PUtable[block];
+		}
+
+		if (i >= s->nb_blocks) {
+			/*
+			 * Uhoo, infinite chain with valid ANACS!
+			 * Format whole chain...
+			 */
+			format_chain(s, first_block);
+		}
+	}
+
+#ifdef CONFIG_MTD_DEBUG_VERBOSE
+	if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
+		INFTL_dumptables(s);
+	if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
+		INFTL_dumpVUchains(s);
+#endif
+
+	/*
+	 * Third pass, format unreferenced blocks and init free block count.
+	 */
+	s->numfreeEUNs = 0;
+	s->LastFreeEUN = BLOCK_NIL;
+
+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 3, format unused blocks\n");
+	for (block = s->firstEUN; block <= s->lastEUN; block++) {
+		if (s->PUtable[block] == BLOCK_NOTEXPLORED) {
+			printk("INFTL: unreferenced block %d, formatting it\n",
+				block);
+			if (INFTL_formatblock(s, block) < 0)
+				s->PUtable[block] = BLOCK_RESERVED;
+			else
+				s->PUtable[block] = BLOCK_FREE;
+		}
+		if (s->PUtable[block] == BLOCK_FREE) {
+			s->numfreeEUNs++;
+			if (s->LastFreeEUN == BLOCK_NIL)
+				s->LastFreeEUN = block;
+		}
+	}
+
+	kfree(ANACtable);
+	return 0;
+}
diff -Nru a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
--- a/drivers/mtd/maps/Kconfig	Tue Apr 15 09:21:15 2003
+++ b/drivers/mtd/maps/Kconfig	Wed May 28 08:56:01 2003
@@ -1,9 +1,16 @@
-# drivers/mtd/maps/Config.in
-# $Id: Config.in,v 1.16 2001/09/19 18:28:37 dwmw2 Exp $
+# drivers/mtd/maps/Kconfig
+# $Id: Kconfig,v 1.11 2003/05/28 15:16:56 dwmw2 Exp $
 
 menu "Mapping drivers for chip access"
 	depends on MTD!=n
 
+config MTD_COMPLEX_MAPPINGS
+	bool "Support non-linear mappings of flash chips"
+	depends on MTD
+	help
+	  This causes the chip drivers to allow for complicated
+	  paged mappings of flash chips.
+
 config MTD_PHYSMAP
 	tristate "CFI Flash device in physical memory map"
 	depends on MTD_CFI
@@ -80,7 +87,7 @@
 
 config MTD_SBC_GXX
 	tristate "CFI Flash device mapped on Arcom SBC-GXx boards"
-	depends on X86 && MTD_CFI_INTELEXT && MTD_PARTITIONS
+	depends on X86 && MTD_CFI_INTELEXT && MTD_PARTITIONS && MTD_COMPLEX_MAPPINGS
 	help
 	  This provides a driver for the on-board flash of Arcom Control
 	  Systems' SBC-GXn family of boards, formerly known as SBC-MediaGX.
@@ -91,7 +98,7 @@
 
 config MTD_ELAN_104NC
 	tristate "CFI Flash device mapped on Arcom ELAN-104NC"
-	depends on X86 && MTD_CFI_INTELEXT && MTD_PARTITIONS
+	depends on X86 && MTD_CFI_INTELEXT && MTD_PARTITIONS && MTD_COMPLEX_MAPPINGS
 	help
 	  This provides a driver for the on-board flash of the Arcom Control
 	  System's ELAN-104NC development board. By default the flash
@@ -99,20 +106,16 @@
 	  devices. This board utilizes Intel StrataFlash. More info at
 	  <http://www.arcomcontrols.com/products/icp/pc104/processors/>.
 
-config MTD_MIXMEM
-	tristate "JEDEC Flash device mapped on Mixcom piggyback card"
-	depends on X86 && MTD_JEDEC
-	help
-	  This supports the paging arrangement for access to flash chips
-	  on the MixCOM piggyback card, allowing the flash chip drivers
-	  to get on with their job of driving the flash chips without
-	  having to know about the paging. If you have one of these boards,
-	  you probably want to enable this mapping driver. More info is at
-	  <http://www.itc.hu/>.
+config MTD_LUBBOCK
+	tristate "CFI Flash device mapped on Intel Lubbock XScale eval board"
+	depends on ARCH_LUBBOCK && MTD_CFI_INTELEXT && MTD_PARTITIONS
+	help
+	  This provides a driver for the on-board flash of the Intel
+	  'Lubbock' XScale evaluation board.
 
 config MTD_OCTAGON
 	tristate "JEDEC Flash device mapped on Octagon 5066 SBC"
-	depends on X86 && MTD_JEDEC
+	depends on X86 && MTD_JEDEC && MTD_COMPLEX_MAPPINGS
 	help
 	  This provides a 'mapping' driver which supports the way in which
 	  the flash chips are connected in the Octagon-5066 Single Board
@@ -121,7 +124,7 @@
 
 config MTD_VMAX
 	tristate "JEDEC Flash device mapped on Tempustech VMAX SBC301"
-	depends on X86 && MTD_JEDEC
+	depends on X86 && MTD_JEDEC && MTD_COMPLEX_MAPPINGS
 	help
 	  This provides a 'mapping' driver which supports the way in which
 	  the flash chips are connected in the Tempustech VMAX SBC301 Single
@@ -139,9 +142,93 @@
 
 	  If compiled as a module, it will be called scx200_docflash.
 
+config MTD_AMD76XROM
+	tristate "BIOS flash chip on AMD76x southbridge"
+	depends on X86 && MTD_JEDECPROBE
+	help
+	  Support for treating the BIOS flash chip on AMD76x motherboards
+	  as an MTD device - with this you can reprogram your BIOS.
+
+	  BE VERY CAREFUL.
+
+config MTD_ICH2ROM
+	tristate "BIOS flash chip on Intel Hub Controller 2"
+	depends on X86 && MTD_JEDECPROBE && MTD_COMPLEX_MAPPINGS
+	help
+	  Support for treating the BIOS flash chip on ICH2 motherboards
+	  as an MTD device - with this you can reprogram your BIOS.
+
+	  BE VERY CAREFUL.
+
+config MTD_SCB2_FLASH
+	tristate "BIOS flash chip on Intel SCB2 boards"
+	depends on X86 && MTD_JEDECPROBE
+	help
+	  Support for treating the BIOS flash chip on Intel SCB2 boards
+	  as an MTD device - with this you can reprogram your BIOS.
+
+	  BE VERY CAREFUL.
+
+config MTD_TSUNAMI
+	tristate "Flash chips on Tsunami TIG bus"
+	depends on ALPHA_TSUNAMI && MTD_COMPLEX_MAPPINGS
+	help
+	  Support for the flash chip on Tsunami TIG bus.
+
+config MTD_LASAT
+	tristate "Flash chips on LASAT board"
+	depends on LASAT && MTD_CFI
+	help
+	  Support for the flash chips on the Lasat 100 and 200 boards.
+
+config MTD_NETtel
+	tristate "CFI flash device on SnapGear/SecureEdge"
+	depends on X86 && MTD_PARTITIONS && MTD_JEDECPROBE
+	help
+	  Support for flash chips on NETtel/SecureEdge/SnapGear boards.
+
+config MTD_PB1XXX
+	tristate "Flash devices on Alchemy PB1xxx boards"
+	depends on MIPS && ( MIPS_PB1000 || MIPS_PB1100 || MIPS_PB1500 )
+	help
+	  Flash memory access on Alchemy Pb1000/Pb1100/Pb1500 boards
+
+config MTD_PB1XXX_BOOT
+	bool "PB1x00 boot flash device"
+	depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 )
+	help
+	  Use the first of the two 32MiB flash banks on Pb1100/Pb1500 board.
+	  You can say 'Y' to both this and 'MTD_PB1XXX_USER' below, to use
+	  both banks.
+
+config MTD_PB1XXX_USER
+	bool "PB1x00 user flash device"
+	depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 )
+	default y if MTD_PB1XX_BOOT = n
+	help
+	  Use the second of the two 32MiB flash banks on Pb1100/Pb1500 board.
+	  You can say 'Y' to both this and 'MTD_PB1XXX_BOOT' above, to use
+	  both banks.
+
+config MTD_DILNETPC
+	tristate "CFI Flash device mapped on DIL/Net PC"
+	depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT
+	help
+	  MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP".
+	  For details, see http://www.ssv-embedded.de/ssv/pc104/p169.htm
+ 	  and http://www.ssv-embedded.de/ssv/pc104/p170.htm
+
+config MTD_DILNETPC_BOOTSIZE
+	hex "Size of DIL/Net PC flash boot partition"
+	depends on MTD_DILNETPC
+	default "0x80000"
+	help
+	  The amount of space taken up by the kernel or Etherboot
+	  on the DIL/Net PC flash chips.
+
 config MTD_L440GX
 	tristate "BIOS flash chip on Intel L440GX boards"
-	depends on X86 && MTD_JEDEC
+	depends on X86 && MTD_JEDECPROBE
 	help
 	  Support for treating the BIOS flash chip on Intel L440GX motherboards
 	  as an MTD device - with this you can reprogram your BIOS.
@@ -150,7 +237,7 @@
 
 config MTD_TQM8XXL
 	tristate "CFI Flash device mapped on TQM8XXL"
-	depends on MTD_CFI && TQM8xxL && PPC
+	depends on MTD_CFI && PPC32 && 8xx && TQM8xxL
 	help
 	  The TQM8xxL PowerPC board has up to two banks of CFI-compliant
 	  chips, currently uses AMD one. This 'mapping' driver supports
@@ -160,7 +247,7 @@
 
 config MTD_RPXLITE
 	tristate "CFI Flash device mapped on RPX Lite or CLLF"
-	depends on MTD_CFI && PPC
+	depends on MTD_CFI && PPC32 && 8xx && (RPXCLASSIC || RPXLITE)
 	help
 	  The RPXLite PowerPC board has CFI-compliant chips mapped in
 	  a strange sparse mapping. This 'mapping' driver supports that
@@ -168,9 +255,17 @@
 	  to communicate with the chips on the RPXLite board. More at
 	  <http://www.embeddedplanet.com/rpx_lite_specification_sheet.htm>.
 
+config MTD_MBX860
+	tristate "System flash on MBX860 board"
+	depends on MTD_CFI && PPC32 && 8xx && MBX
+	help
+	  This enables access routines for the flash chips on the Motorola
+	  MBX860 board. If you have one of these boards and would like
+	  to use the flash chips on it, say 'Y'.
+
 config MTD_DBOX2
 	tristate "CFI Flash device mapped on D-Box2"
-	depends on PPC && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD
+	depends on PPC32 && 8xx && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD
 	help
 	  This enables access routines for the flash chips on the Nokia/Sagem
 	  D-Box 2 board. If you have one of these boards and would like to use
@@ -178,15 +273,47 @@
 
 config MTD_CFI_FLAGADM
 	tristate "CFI Flash device mapping on FlagaDM"
-	depends on PPC && MTD_CFI
+	depends on PPC32 && 8xx && MTD_CFI
 	help
 	  Mapping for the Flaga digital module. If you don´t have one, ignore
 	  this setting.
 
+config MTD_BEECH
+	tristate "CFI Flash device mapped on IBM 405LP Beech"
+	depends on MTD_CFI && PPC32 && 40x && BEECH
+	help
+	  This enables access routines for the flash chips on the IBM
+	  405LP Beech board. If you have one of these boards and would like
+	  to use the flash chips on it, say 'Y'.
+
+config MTD_ARCTIC
+	tristate "CFI Flash device mapped on IBM 405LP Arctic"
+	depends on MTD_CFI && PPC32 && 40x && ARCTIC2
+	help
+	  This enables access routines for the flash chips on the IBM 405LP
+	  Arctic board. If you have one of these boards and would like to
+	  use the flash chips on it, say 'Y'.
+
+config MTD_EBONY
+	tristate "CFI Flash device mapped on IBM 440GP Ebony"
+	depends on MTD_CFI && PPC32 && 440 && EBONY
+	help
+	  This enables access routines for the flash chips on the IBM 440GP
+	  Ebony board. If you have one of these boards and would like to
+	  use the flash chips on it, say 'Y'.
+
+config MTD_REDWOOD
+	tristate "CFI Flash devices mapped on IBM Redwood"
+	depends on MTD_CFI && PPC32 && 4xx && 40x && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 )
+	help
+	  This enables access routines for the flash chips on the IBM
+	  Redwood board. If you have one of these boards and would like to
+	  use the flash chips on it, say 'Y'.
+
 config MTD_CSTM_MIPS_IXX
 	tristate "Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board"
-	depends on MIPS && MTD_CFI && MTD_JEDEC && MTD_PARTITIONS
-	---help---
+	depends on MIPS && MTD_CFI && MTD_JEDECPROBE && MTD_PARTITIONS
+	help
 	  This provides a mapping driver for the Integrated Tecnology
 	  Express, Inc (ITE) QED-4N-S01B eval board and the Globespan IVR
 	  Reference Board. It provides the necessary addressing, length,
@@ -242,12 +369,6 @@
 	  This enables access to the flash chips on the Hitachi SolutionEngine and
 	  similar boards. Say 'Y' if you are building a kernel for such a board.
 
-config MTD_NORA
-	tristate "CFI Flash device mapped on Nora"
-	depends on ARM && MTD_CFI
-	help
-	  If you had to ask, you don't have one. Say 'N'.
-
 config MTD_ARM_INTEGRATOR
 	tristate "CFI Flash device mapped on ARM Integrator/P720T"
 	depends on ARM && MTD_CFI
@@ -269,7 +390,7 @@
 
 config MTD_DC21285
 	tristate "CFI Flash device mapped on DC21285 Footbridge"
-	depends on ARM && MTD_CFI && ARCH_FOOTBRIDGE
+	depends on ARM && MTD_CFI && ARCH_FOOTBRIDGE && MTD_COMPLEX_MAPPINGS
 	help
 	  This provides a driver for the flash accessed using Intel's
 	  21285 bridge used with Intel's StrongARM processors. More info at
@@ -283,14 +404,6 @@
 	  IQ80310 evaluation board. If you have one of these boards and would 
 	  like to use the flash chips on it, say 'Y'.
 
-config MTD_IQ80321
-	tristate "CFI Flash device mapped on the XScale IQ80321 board"
-	depends on ARM && MTD_CFI && ARCH_IQ80321
-	help
-	  This enables access routines for the flash chips on the Intel XScale
-	  IQ80321 evaluation board. If you have one of these boards and would
-	  like to use the flash chips on it, say 'Y'.
-
 config MTD_EPXA10DB
 	tristate "CFI Flash device mapped on Epxa10db"
 	depends on ARM && MTD_CFI && MTD_PARTITIONS && ARCH_CAMELOT
@@ -335,10 +448,17 @@
 	  PhotoMax Digital Picture Frame.
 	  If you have such a device, say 'Y'.
 
+config MTD_H720X
+	tristate "Hynix evaluation board mappings"
+	depends on ARM && MTD_CFI && ( ARCH_H7201 || ARCH_H7202 )
+	help
+	  This enables access to the flash chips on the Hynix evaluation boards.
+	  If you have such a board, say 'Y'.
+
 # This needs CFI or JEDEC, depending on the cards found.
 config MTD_PCI
 	tristate "PCI MTD driver"
-	depends on MTD && PCI
+	depends on MTD && PCI && MTD_COMPLEX_MAPPINGS
 	help
 	  Mapping for accessing flash devices on add-in cards like the Intel XScale
 	  IQ80310 card, and the Intel EBSA285 card in blank ROM programming mode
@@ -348,7 +468,7 @@
 
 config MTD_PCMCIA
 	tristate "PCMCIA MTD driver"
-	depends on MTD && PCMCIA
+	depends on MTD && PCMCIA && MTD_COMPLEX_MAPPINGS
 	help
 	  Map driver for accessing PCMCIA linear flash memory cards. These
 	  cards are usually around 4-16MiB in size. This does not include
diff -Nru a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
--- a/drivers/mtd/maps/Makefile	Tue Apr 15 09:21:15 2003
+++ b/drivers/mtd/maps/Makefile	Wed May 28 08:01:02 2003
@@ -1,7 +1,11 @@
 #
 # linux/drivers/maps/Makefile
 #
-# $Id: Makefile,v 1.13 2001/08/16 15:16:58 rmk Exp $
+# $Id: Makefile.common,v 1.2 2003/05/28 10:48:41 dwmw2 Exp $
+
+ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y)
+obj-$(CONFIG_MTD)		+= map_funcs.o
+endif
 
 # Chip mappings
 obj-$(CONFIG_MTD_CDB89712)	+= cdb89712.o
@@ -9,12 +13,16 @@
 obj-$(CONFIG_MTD_CFI_FLAGADM)	+= cfi_flagadm.o
 obj-$(CONFIG_MTD_CSTM_MIPS_IXX)	+= cstm_mips_ixx.o
 obj-$(CONFIG_MTD_DC21285)	+= dc21285.o
+obj-$(CONFIG_MTD_DILNETPC)	+= dilnetpc.o
 obj-$(CONFIG_MTD_ELAN_104NC)	+= elan-104nc.o
 obj-$(CONFIG_MTD_EPXA10DB)	+= epxa10db-flash.o
 obj-$(CONFIG_MTD_IQ80310)	+= iq80310.o
-obj-$(CONFIG_MTD_IQ80321)	+= iq80321.o
 obj-$(CONFIG_MTD_L440GX)	+= l440gx.o
-obj-$(CONFIG_MTD_NORA)		+= nora.o
+obj-$(CONFIG_MTD_AMD76XROM)	+= amd76xrom.o
+obj-$(CONFIG_MTD_ICH2ROM)	+= ich2rom.o
+obj-$(CONFIG_MTD_TSUNAMI)	+= tsunami_flash.o
+obj-$(CONFIG_MTD_LUBBOCK)	+= lubbock-flash.o
+obj-$(CONFIG_MTD_MBX860)	+= mbx860.o
 obj-$(CONFIG_MTD_CEIVA)		+= ceiva.o
 obj-$(CONFIG_MTD_OCTAGON)	+= octagon-5066.o
 obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o 
@@ -31,10 +39,19 @@
 obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
 obj-$(CONFIG_MTD_DBOX2)		+= dbox2-flash.o
 obj-$(CONFIG_MTD_OCELOT)	+= ocelot.o
-obj-$(CONFIG_MTD_UCLINUX)	+= uclinux.o
 obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
 obj-$(CONFIG_MTD_PCI)		+= pci.o
+obj-$(CONFIG_MTD_PB1XXX)	+= pb1xxx-flash.o
+obj-$(CONFIG_MTD_LASAT)		+= lasat.o
 obj-$(CONFIG_MTD_AUTCPU12)	+= autcpu12-nvram.o
 obj-$(CONFIG_MTD_EDB7312)	+= edb7312.o
 obj-$(CONFIG_MTD_IMPA7)		+= impa7.o
 obj-$(CONFIG_MTD_FORTUNET)	+= fortunet.o
+obj-$(CONFIG_MTD_REDWOOD)	+= redwood.o
+obj-$(CONFIG_MTD_UCLINUX)	+= uclinux.o
+obj-$(CONFIG_MTD_NETtel)	+= nettel.o
+obj-$(CONFIG_MTD_SCB2_FLASH)	+= scb2_flash.o
+obj-$(CONFIG_MTD_EBONY)		+= ebony.o
+obj-$(CONFIG_MTD_BEECH)		+= beech-mtd.o
+obj-$(CONFIG_MTD_ARCTIC)	+= arctic-mtd.o
+obj-$(CONFIG_MTD_H720X)		+= h720x-flash.o
diff -Nru a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/amd76xrom.c	Wed May 28 08:56:01 2003
@@ -0,0 +1,215 @@
+/*
+ * amd76xrom.c
+ *
+ * Normal mappings of chips in physical memory
+ * $Id: amd76xrom.c,v 1.8 2003/05/28 15:44:28 dwmw2 Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+
+struct amd76xrom_map_info {
+	struct map_info map;
+	struct mtd_info *mtd;
+	unsigned long window_addr;
+	u32 window_start, window_size;
+	struct pci_dev *pdev;
+};
+
+
+static struct amd76xrom_map_info amd76xrom_map = {
+	.map = {
+		.name = "AMD76X rom",
+		.size = 0,
+		.buswidth = 1,
+	},
+	.mtd = 0,
+	.window_addr = 0,
+};
+
+static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
+	const struct pci_device_id *ent)
+{
+	struct rom_window {
+		u32 start;
+		u32 size;
+		u8 segen_bits;
+	};
+	static struct rom_window rom_window[] = {
+		{ 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), },
+		{ 0xffc00000, 4*1024*1024, (1<<7), },
+		{ 0xffff0000, 64*1024,     0 },
+		{ 0         , 0,           0 },
+	};
+	static const u32 rom_probe_sizes[] = { 
+		5*1024*1024, 4*1024*1024, 2*1024*1024, 1024*1024, 512*1024, 
+		256*1024, 128*1024, 64*1024, 0};
+	static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", 0 };
+	u8 byte;
+	struct amd76xrom_map_info *info = &amd76xrom_map;
+	struct rom_window *window;
+	int i;
+	u32 rom_size;
+
+	window = &rom_window[0];
+
+	/* disabled because it fights with BIOS reserved regions */
+#define REQUEST_MEM_REGION 0
+#if REQUEST_MEM_REGION
+	while(window->size) {
+		if (request_mem_region(window->start, window->size, "amd76xrom")) {
+			break;
+		}
+		window++;
+	}
+	if (!window->size) {
+		printk(KERN_ERR "amd76xrom: cannot reserve rom window\n");
+		goto err_out_none;
+	}
+#endif /* REQUEST_MEM_REGION */
+
+	/* Enable the selected rom window */
+	pci_read_config_byte(pdev, 0x43, &byte);
+	pci_write_config_byte(pdev, 0x43, byte | window->segen_bits);
+
+	/* Enable writes through the rom window */
+	pci_read_config_byte(pdev, 0x40, &byte);
+	pci_write_config_byte(pdev, 0x40, byte | 1);
+
+	/* FIXME handle registers 0x80 - 0x8C the bios region locks */
+
+	printk(KERN_NOTICE "amd76xrom window : %x at %x\n", 
+		window->size, window->start);
+	/* For write accesses caches are useless */
+	info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size);
+
+	if (!info->window_addr) {
+		printk(KERN_ERR "Failed to ioremap\n");
+		goto err_out_free_mmio_region;
+	}
+	info->mtd = 0;
+	for(i = 0; (rom_size = rom_probe_sizes[i]); i++) {
+		char **chip_type;
+		if (rom_size > window->size) {
+			continue;
+		}
+		info->map.phys = window->start + window->size - rom_size;
+		info->map.virt = 
+			info->window_addr + window->size - rom_size;
+		info->map.size = rom_size;
+		simple_map_init(&info->map);
+		chip_type = rom_probe_types;
+		for(; !info->mtd && *chip_type; chip_type++) {
+			info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map);
+		}
+		if (info->mtd) {
+			break;
+		}
+	}
+	if (!info->mtd) {
+		goto err_out_iounmap;
+	}
+	printk(KERN_NOTICE "amd76xrom chip at offset: 0x%x\n",
+		window->size - rom_size);
+		
+	info->mtd->owner = THIS_MODULE;
+	add_mtd_device(info->mtd);
+	info->window_start = window->start;
+	info->window_size = window->size;
+	return 0;
+
+err_out_iounmap:
+	iounmap((void *)(info->window_addr));
+err_out_free_mmio_region:
+#if REQUEST_MEM_REGION
+	release_mem_region(window->start, window->size);
+err_out_none:
+#endif /* REQUEST_MEM_REGION */
+	return -ENODEV;
+}
+
+
+static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
+{
+	struct amd76xrom_map_info *info = &amd76xrom_map;
+	u8 byte;
+
+	del_mtd_device(info->mtd);
+	map_destroy(info->mtd);
+	info->mtd = 0;
+	info->map.virt = 0;
+
+	iounmap((void *)(info->window_addr));
+	info->window_addr = 0;
+
+	/* Disable writes through the rom window */
+	pci_read_config_byte(pdev, 0x40, &byte);
+	pci_write_config_byte(pdev, 0x40, byte & ~1);
+
+#if REQUEST_MEM_REGION
+	release_mem_region(info->window_start, info->window_size);
+#endif /* REQUEST_MEM_REGION */
+}
+
+static struct pci_device_id amd76xrom_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,  
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,  
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, amd76xrom_pci_tbl);
+
+#if 0
+static struct pci_driver amd76xrom_driver = {
+	.name =		"amd76xrom",
+	.id_table =	amd76xrom_pci_tbl,
+	.probe =	amd76xrom_init_one,
+	.remove =	amd76xrom_remove_one,
+};
+#endif
+
+int __init init_amd76xrom(void)
+{
+	struct pci_dev *pdev;
+	struct pci_device_id *id;
+	pdev = 0;
+	for(id = amd76xrom_pci_tbl; id->vendor; id++) {
+		pdev = pci_find_device(id->vendor, id->device, 0);
+		if (pdev) {
+			break;
+		}
+	}
+	if (pdev) {
+		amd76xrom_map.pdev = pdev;
+		return amd76xrom_init_one(pdev, &amd76xrom_pci_tbl[0]);
+	}
+	return -ENXIO;
+#if 0
+	return pci_module_init(&amd76xrom_driver);
+#endif
+}
+
+static void __exit cleanup_amd76xrom(void)
+{
+	amd76xrom_remove_one(amd76xrom_map.pdev);
+}
+
+module_init(init_amd76xrom);
+module_exit(cleanup_amd76xrom);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
+MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD76X southbridge");
+
diff -Nru a/drivers/mtd/maps/arctic-mtd.c b/drivers/mtd/maps/arctic-mtd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/arctic-mtd.c	Wed May 28 08:01:13 2003
@@ -0,0 +1,128 @@
+/*
+ * $Id: arctic-mtd.c,v 1.8 2003/05/21 12:45:17 dwmw2 Exp $
+ * 
+ * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for 
+ *                              IBM 405LP Arctic boards.
+ *
+ * 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
+ *
+ * Copyright (C) 2002, International Business Machines Corporation
+ * All Rights Reserved.
+ *
+ * Bishop Brock
+ * IBM Research, Austin Center for Low-Power Computing
+ * bcbrock@us.ibm.com
+ * March 2002
+ *
+ * modified for Arctic by,
+ * David Gibson
+ * IBM OzLabs, Canberra, Australia
+ * <arctic@gibson.dropbear.id.au>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/ibm4xx.h>
+
+/*
+ * fe000000 -- ff9fffff  Arctic FFS (26MB)
+ * ffa00000 -- fff5ffff  kernel (5.504MB)
+ * fff60000 -- ffffffff  firmware (640KB)
+ */
+
+#define ARCTIC_FFS_SIZE		0x01a00000 /* 26 M */
+#define ARCTIC_FIRMWARE_SIZE	0x000a0000 /* 640K */
+
+#define NAME     "Arctic Linux Flash"
+#define PADDR    SUBZERO_BOOTFLASH_PADDR
+#define SIZE     SUBZERO_BOOTFLASH_SIZE
+#define BUSWIDTH 2
+
+/* Flash memories on these boards are memory resources, accessed big-endian. */
+
+{
+  /* do nothing for now */
+}
+
+static struct map_info arctic_mtd_map = {
+	.name		= NAME,
+	.size		= SIZE,
+	.buswidth	= BUSWIDTH,
+	.phys		= PADDR,
+};
+
+static struct mtd_info *arctic_mtd;
+
+static struct mtd_partition arctic_partitions[3] = {
+	{ .name		= "Arctic FFS",
+	  .size		= ARCTIC_FFS_SIZE,
+	  .offset	= 0,},
+	{ .name		= "Kernel",
+	  .size		= SUBZERO_BOOTFLASH_SIZE - ARCTIC_FFS_SIZE -
+	  		  ARCTIC_FIRMWARE_SIZE,
+	  .offset	= ARCTIC_FFS_SIZE,},
+	{ .name		= "Firmware",
+	  .size		= ARCTIC_FIRMWARE_SIZE,
+	  .offset	= SUBZERO_BOOTFLASH_SIZE - ARCTIC_FIRMWARE_SIZE,},
+};
+
+static int __init
+init_arctic_mtd(void)
+{
+	printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
+
+	arctic_mtd_map.virt = (unsigned long) ioremap(PADDR, SIZE);
+
+	if (!arctic_mtd_map.virt) {
+		printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
+		return -EIO;
+	}
+	simple_map_init(&arctic_mtd_map);
+
+	printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
+	arctic_mtd = do_map_probe("cfi_probe", &arctic_mtd_map);
+
+	if (!arctic_mtd)
+		return -ENXIO;
+
+	arctic_mtd->owner = THIS_MODULE;
+
+	return add_mtd_partitions(arctic_mtd, arctic_partitions, 3);
+}
+
+static void __exit
+cleanup_arctic_mtd(void)
+{
+	if (arctic_mtd) {
+		del_mtd_partitions(arctic_mtd);
+		map_destroy(arctic_mtd);
+		iounmap((void *) arctic_mtd_map.virt);
+	}
+}
+
+module_init(init_arctic_mtd);
+module_exit(cleanup_arctic_mtd);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Gibson <arctic@gibson.dropbear.id.au>");
+MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Arctic boards");
diff -Nru a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c
--- a/drivers/mtd/maps/autcpu12-nvram.c	Wed Feb 26 04:18:43 2003
+++ b/drivers/mtd/maps/autcpu12-nvram.c	Wed May 28 08:01:03 2003
@@ -2,7 +2,7 @@
  * NV-RAM memory access on autcpu12 
  * (C) 2002 Thomas Gleixner (gleixner@autronix.de)
  *
- * $Id: autcpu12-nvram.c,v 1.1 2002/02/22 09:30:24 gleixner Exp $ 
+ * $Id: autcpu12-nvram.c,v 1.5 2003/05/21 12:45:18 dwmw2 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
@@ -24,6 +24,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <asm/sizes.h>
 #include <asm/hardware.h>
@@ -32,81 +33,28 @@
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 
-__u8 autcpu12_read8(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readb(map->map_priv_1 + ofs);
-}
-
-__u16 autcpu12_read16(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readw(map->map_priv_1 + ofs);
-}
-
-__u32 autcpu12_read32(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readl(map->map_priv_1 + ofs);
-}
-
-void autcpu12_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	__raw_writeb(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void autcpu12_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	__raw_writew(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void autcpu12_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	__raw_writel(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void autcpu12_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, map->map_priv_1 + from, len);
-}
-
-void autcpu12_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	while(len) {
-		__raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
-		from++;
-		to++;
-		len--;
-	}
-}
 
 static struct mtd_info *sram_mtd;
 
 struct map_info autcpu12_sram_map = {
-	.name		= "SRAM",
-	.size		= 32768,
-	.buswidth	= 8,
-	.read8		= autcpu12_read8,
-	.read16		= autcpu12_read16,
-	.read32		= autcpu12_read32,
-	.copy_from	= autcpu12_copy_from,
-	.write8		= autcpu12_write8,
-	.write16	= autcpu12_write16,
-	.write32	= autcpu12_write32,
-	.copy_to	= autcpu12_copy_to
+	.name = "SRAM",
+	.size = 32768,
+	.buswidth = 4,
+	.phys = 0x12000000,
 };
 
 static int __init init_autcpu12_sram (void)
 {
 	int err, save0, save1;
 
-	autcpu12_sram_map.map_priv_1 = (unsigned long)ioremap(0x12000000, SZ_128K);
-	if (!autcpu12_sram_map.map_priv_1) {
+	autcpu12_sram_map.virt = (unsigned long)ioremap(0x12000000, SZ_128K);
+	if (!autcpu12_sram_map.virt) {
 		printk("Failed to ioremap autcpu12 NV-RAM space\n");
 		err = -EIO;
 		goto out;
 	}
-	
+	simple_map_init(&autcpu_sram_map);
+
 	/* 
 	 * Check for 32K/128K 
 	 * read ofs 0 
@@ -115,20 +63,20 @@
 	 * Read	and check result on ofs 0x0
 	 * Restore contents
 	 */
-	save0 = autcpu12_read32(&autcpu12_sram_map,0);
-	save1 = autcpu12_read32(&autcpu12_sram_map,0x10000);
-	autcpu12_write32(&autcpu12_sram_map,~save0,0x10000);
+	save0 = map_read32(&autcpu12_sram_map,0);
+	save1 = map_read32(&autcpu12_sram_map,0x10000);
+	map_write32(&autcpu12_sram_map,~save0,0x10000);
 	/* if we find this pattern on 0x0, we have 32K size 
 	 * restore contents and exit
 	 */
-	if ( autcpu12_read32(&autcpu12_sram_map,0) != save0) {
-		autcpu12_write32(&autcpu12_sram_map,save0,0x0);
+	if ( map_read32(&autcpu12_sram_map,0) != save0) {
+		map_write32(&autcpu12_sram_map,save0,0x0);
 		goto map;
 	}
 	/* We have a 128K found, restore 0x10000 and set size
 	 * to 128K
 	 */
-	autcpu12_write32(&autcpu12_sram_map,save1,0x10000);
+	ma[_write32(&autcpu12_sram_map,save1,0x10000);
 	autcpu12_sram_map.size = SZ_128K;
 
 map:
@@ -139,7 +87,7 @@
 		goto out_ioremap;
 	}
 
-	sram_mtd->module = THIS_MODULE;
+	sram_mtd->owner = THIS_MODULE;
 	sram_mtd->erasesize = 16;
 	
 	if (add_mtd_device(sram_mtd)) {
@@ -148,7 +96,7 @@
 		goto out_probe;
 	}
 
-	printk("NV-RAM device size %ldK registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K);
+	printk("NV-RAM device size %ldKiB registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K);
 		
 	return 0;
 
@@ -157,7 +105,7 @@
 	sram_mtd = 0;
 
 out_ioremap:
-	iounmap((void *)autcpu12_sram_map.map_priv_1);
+	iounmap((void *)autcpu12_sram_map.virt);
 out:
 	return err;
 }
@@ -167,7 +115,7 @@
 	if (sram_mtd) {
 		del_mtd_device(sram_mtd);
 		map_destroy(sram_mtd);
-		iounmap((void *)autcpu12_sram_map.map_priv_1);
+		iounmap((void *)autcpu12_sram_map.virt);
 	}
 }
 
diff -Nru a/drivers/mtd/maps/beech-mtd.c b/drivers/mtd/maps/beech-mtd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/beech-mtd.c	Wed May 28 08:01:14 2003
@@ -0,0 +1,112 @@
+/*
+ * $Id: beech-mtd.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $
+ * 
+ * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for 
+ *                              IBM 405LP Beech boards.
+ *
+ * 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
+ *
+ * Copyright (C) 2002, International Business Machines Corporation
+ * All Rights Reserved.
+ *
+ * Bishop Brock
+ * IBM Research, Austin Center for Low-Power Computing
+ * bcbrock@us.ibm.com
+ * March 2002
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/ibm4xx.h>
+
+#define NAME     "Beech Linux Flash"
+#define PADDR    BEECH_BIGFLASH_PADDR
+#define SIZE     BEECH_BIGFLASH_SIZE
+#define BUSWIDTH 1
+
+/* Flash memories on these boards are memory resources, accessed big-endian. */
+
+
+static struct map_info beech_mtd_map = {
+	.name =		NAME,
+	.size =		SIZE,
+	.buswidth =	BUSWIDTH,
+	.phys =		PADDR
+};
+
+static struct mtd_info *beech_mtd;
+
+static struct mtd_partition beech_partitions[2] = {
+	{
+	      .name = "Linux Kernel",
+	      .size = BEECH_KERNEL_SIZE,
+	      .offset = BEECH_KERNEL_OFFSET
+	}, {
+	      .name = "Free Area",
+	      .size = BEECH_FREE_AREA_SIZE,
+	      .offset = BEECH_FREE_AREA_OFFSET
+	}
+};
+
+static int __init
+init_beech_mtd(void)
+{
+	printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
+
+	beech_mtd_map.virt = (unsigned long) ioremap(PADDR, SIZE);
+
+	if (!beech_mtd_map.virt) {
+		printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
+		return -EIO;
+	}
+
+	simple_map_init(&beech_mtd_map);
+
+	printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
+	beech_mtd = do_map_probe("cfi_probe", &beech_mtd_map);
+
+	if (!beech_mtd)
+		return -ENXIO;
+
+	beech_mtd->owner = THIS_MODULE;
+
+	return add_mtd_partitions(beech_mtd, beech_partitions, 2);
+}
+
+static void __exit
+cleanup_beech_mtd(void)
+{
+	if (beech_mtd) {
+		del_mtd_partitions(beech_mtd);
+		map_destroy(beech_mtd);
+		iounmap((void *) beech_mtd_map.virt);
+	}
+}
+
+module_init(init_beech_mtd);
+module_exit(cleanup_beech_mtd);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Bishop Brock <bcbrock@us.ibm.com>");
+MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Beech boards");
diff -Nru a/drivers/mtd/maps/cdb89712.c b/drivers/mtd/maps/cdb89712.c
--- a/drivers/mtd/maps/cdb89712.c	Wed Feb 26 04:21:33 2003
+++ b/drivers/mtd/maps/cdb89712.c	Wed May 28 08:01:03 2003
@@ -1,89 +1,37 @@
 /*
  * Flash on Cirrus CDB89712
  *
- * $Id: cdb89712.c,v 1.3 2001/10/02 15:14:43 rmk Exp $
+ * $Id: cdb89712.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $
  */
 
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <asm/arch/hardware.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 
-__u8 cdb89712_read8(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readb(map->map_priv_1 + ofs);
-}
-
-__u16 cdb89712_read16(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readw(map->map_priv_1 + ofs);
-}
-
-__u32 cdb89712_read32(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readl(map->map_priv_1 + ofs);
-}
-
-void cdb89712_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	__raw_writeb(d, map->map_priv_1 + adr);
-	mb();
-}
 
-void cdb89712_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	__raw_writew(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void cdb89712_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	__raw_writel(d, map->map_priv_1 + adr);
-	mb();
-}
 
-void cdb89712_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	// printk ("cdb89712_copy_from: 0x%x@0x%x -> 0x%x\n", len, from, to);
-	memcpy_fromio(to, map->map_priv_1 + from, len);
-}
-
-void cdb89712_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	while(len) {
-		__raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
-		from++;
-		to++;
-		len--;
-	}
-}
 
 static struct mtd_info *flash_mtd;
 
 struct map_info cdb89712_flash_map = {
-	.name		= "flash",
-	.size		= FLASH_SIZE,
-	.buswidth	= FLASH_WIDTH,
-	.read8		= cdb89712_read8,
-	.read16		= cdb89712_read16,
-	.read32		= cdb89712_read32,
-	.copy_from	= cdb89712_copy_from,
-	.write8		= cdb89712_write8,
-	.write16	= cdb89712_write16,
-	.write32	= cdb89712_write32,
-	.copy_to	= cdb89712_copy_to
+	.name = "flash",
+	.size = FLASH_SIZE,
+	.buswidth = FLASH_WIDTH,
+	.phys = FLASH_START,
 };
 
 struct resource cdb89712_flash_resource = {
-	.name	= "Flash",
-	.start	= FLASH_START,
-	.end	= FLASH_START + FLASH_SIZE - 1,
-	.flags	= IORESOURCE_IO | IORESOURCE_BUSY,
+	.name =   "Flash",
+	.start =  FLASH_START,
+	.end =    FLASH_START + FLASH_SIZE - 1,
+	.flags =  IORESOURCE_IO | IORESOURCE_BUSY,
 };
 
 static int __init init_cdb89712_flash (void)
@@ -96,13 +44,13 @@
 		goto out;
 	}
 	
-	cdb89712_flash_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
-	if (!cdb89712_flash_map.map_priv_1) {
+	cdb89712_flash_map.virt = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
+	if (!cdb89712_flash_map.virt) {
 		printk(KERN_NOTICE "Failed to ioremap Cdb89712 FLASH space\n");
 		err = -EIO;
 		goto out_resource;
 	}
-
+	simple_map_init(&cdb89712_flash_map);
 	flash_mtd = do_map_probe("cfi_probe", &cdb89712_flash_map);
 	if (!flash_mtd) {
 		flash_mtd = do_map_probe("map_rom", &cdb89712_flash_map);
@@ -115,7 +63,7 @@
 		goto out_ioremap;
 	}
 
-	flash_mtd->module = THIS_MODULE;
+	flash_mtd->owner = THIS_MODULE;
 	
 	if (add_mtd_device(flash_mtd)) {
 		printk("FLASH device addition failed\n");
@@ -129,34 +77,31 @@
 	map_destroy(flash_mtd);
 	flash_mtd = 0;
 out_ioremap:
-	iounmap((void *)cdb89712_flash_map.map_priv_1);
+	iounmap((void *)cdb89712_flash_map.virt);
 out_resource:
 	release_resource (&cdb89712_flash_resource);
 out:
 	return err;
 }
 
+
+
+
+
 static struct mtd_info *sram_mtd;
 
 struct map_info cdb89712_sram_map = {
-	.name		= "SRAM",
-	.size		= SRAM_SIZE,
-	.buswidth	= SRAM_WIDTH,
-	.read8		= cdb89712_read8,
-	.read16		= cdb89712_read16,
-	.read32		= cdb89712_read32,
-	.copy_from	= cdb89712_copy_from,
-	.write8		= cdb89712_write8,
-	.write16	= cdb89712_write16,
-	.write32	= cdb89712_write32,
-	.copy_to	= cdb89712_copy_to
+	.name = "SRAM",
+	.size = SRAM_SIZE,
+	.buswidth = SRAM_WIDTH,
+	.phys = SRAM_START,
 };
 
 struct resource cdb89712_sram_resource = {
-	.name	= "SRAM",
-	.start	= SRAM_START,
-	.end	= SRAM_START + SRAM_SIZE - 1,
-	.flags	= IORESOURCE_IO | IORESOURCE_BUSY,
+	.name =   "SRAM",
+	.start =  SRAM_START,
+	.end =    SRAM_START + SRAM_SIZE - 1,
+	.flags =  IORESOURCE_IO | IORESOURCE_BUSY,
 };
 
 static int __init init_cdb89712_sram (void)
@@ -169,13 +114,13 @@
 		goto out;
 	}
 	
-	cdb89712_sram_map.map_priv_1 = (unsigned long)ioremap(SRAM_START, SRAM_SIZE);
-	if (!cdb89712_sram_map.map_priv_1) {
+	cdb89712_sram_map.virt = (unsigned long)ioremap(SRAM_START, SRAM_SIZE);
+	if (!cdb89712_sram_map.virt) {
 		printk(KERN_NOTICE "Failed to ioremap Cdb89712 SRAM space\n");
 		err = -EIO;
 		goto out_resource;
 	}
-
+	simple_map_init(&cdb89712_sram_map);
 	sram_mtd = do_map_probe("map_ram", &cdb89712_sram_map);
 	if (!sram_mtd) {
 		printk("SRAM probe failed\n");
@@ -183,7 +128,7 @@
 		goto out_ioremap;
 	}
 
-	sram_mtd->module = THIS_MODULE;
+	sram_mtd->owner = THIS_MODULE;
 	sram_mtd->erasesize = 16;
 	
 	if (add_mtd_device(sram_mtd)) {
@@ -198,30 +143,33 @@
 	map_destroy(sram_mtd);
 	sram_mtd = 0;
 out_ioremap:
-	iounmap((void *)cdb89712_sram_map.map_priv_1);
+	iounmap((void *)cdb89712_sram_map.virt);
 out_resource:
 	release_resource (&cdb89712_sram_resource);
 out:
 	return err;
 }
 
+
+
+
+
+
+
 static struct mtd_info *bootrom_mtd;
 
 struct map_info cdb89712_bootrom_map = {
-	.name		= "BootROM",
-	.size		= BOOTROM_SIZE,
-	.buswidth	= BOOTROM_WIDTH,
-	.read8		= cdb89712_read8,
-	.read16		= cdb89712_read16,
-	.read32		= cdb89712_read32,
-	.copy_from	= cdb89712_copy_from,
+	.name = "BootROM",
+	.size = BOOTROM_SIZE,
+	.buswidth = BOOTROM_WIDTH,
+	.phys = BOOTROM_START,
 };
 
 struct resource cdb89712_bootrom_resource = {
-	.name	= "BootROM",
-	.start	= BOOTROM_START,
-	.end	= BOOTROM_START + BOOTROM_SIZE - 1,
-	.flags	= IORESOURCE_IO | IORESOURCE_BUSY,
+	.name =   "BootROM",
+	.start =  BOOTROM_START,
+	.end =    BOOTROM_START + BOOTROM_SIZE - 1,
+	.flags =  IORESOURCE_IO | IORESOURCE_BUSY,
 };
 
 static int __init init_cdb89712_bootrom (void)
@@ -234,13 +182,13 @@
 		goto out;
 	}
 	
-	cdb89712_bootrom_map.map_priv_1 = (unsigned long)ioremap(BOOTROM_START, BOOTROM_SIZE);
-	if (!cdb89712_bootrom_map.map_priv_1) {
+	cdb89712_bootrom_map.virt = (unsigned long)ioremap(BOOTROM_START, BOOTROM_SIZE);
+	if (!cdb89712_bootrom_map.virt) {
 		printk(KERN_NOTICE "Failed to ioremap Cdb89712 BootROM space\n");
 		err = -EIO;
 		goto out_resource;
 	}
-
+	simple_map_init(&cdb89712_bootrom_map);
 	bootrom_mtd = do_map_probe("map_rom", &cdb89712_bootrom_map);
 	if (!bootrom_mtd) {
 		printk("BootROM probe failed\n");
@@ -248,7 +196,7 @@
 		goto out_ioremap;
 	}
 
-	bootrom_mtd->module = THIS_MODULE;
+	bootrom_mtd->owner = THIS_MODULE;
 	bootrom_mtd->erasesize = 0x10000;
 	
 	if (add_mtd_device(bootrom_mtd)) {
@@ -263,13 +211,17 @@
 	map_destroy(bootrom_mtd);
 	bootrom_mtd = 0;
 out_ioremap:
-	iounmap((void *)cdb89712_bootrom_map.map_priv_1);
+	iounmap((void *)cdb89712_bootrom_map.virt);
 out_resource:
 	release_resource (&cdb89712_bootrom_resource);
 out:
 	return err;
 }
 
+
+
+
+
 static int __init init_cdb89712_maps(void)
 {
 
@@ -289,21 +241,21 @@
 	if (sram_mtd) {
 		del_mtd_device(sram_mtd);
 		map_destroy(sram_mtd);
-		iounmap((void *)cdb89712_sram_map.map_priv_1);
+		iounmap((void *)cdb89712_sram_map.virt);
 		release_resource (&cdb89712_sram_resource);
 	}
 	
 	if (flash_mtd) {
 		del_mtd_device(flash_mtd);
 		map_destroy(flash_mtd);
-		iounmap((void *)cdb89712_flash_map.map_priv_1);
+		iounmap((void *)cdb89712_flash_map.virt);
 		release_resource (&cdb89712_flash_resource);
 	}
 
 	if (bootrom_mtd) {
 		del_mtd_device(bootrom_mtd);
 		map_destroy(bootrom_mtd);
-		iounmap((void *)cdb89712_bootrom_map.map_priv_1);
+		iounmap((void *)cdb89712_bootrom_map.virt);
 		release_resource (&cdb89712_bootrom_resource);
 	}
 }
diff -Nru a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c
--- a/drivers/mtd/maps/ceiva.c	Wed Feb 26 05:12:01 2003
+++ b/drivers/mtd/maps/ceiva.c	Wed May 28 08:01:03 2003
@@ -11,7 +11,7 @@
  *
  * (C) 2000 Nicolas Pitre <nico@cam.org>
  *
- * $Id: ceiva.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
+ * $Id: ceiva.c,v 1.8 2003/05/21 12:45:18 dwmw2 Exp $
  */
 
 #include <linux/config.h>
@@ -19,6 +19,7 @@
 #include <linux/types.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -31,62 +32,10 @@
 #include <asm/sizes.h>
 
 /*
- * This isnt complete yet, so...
+ * This isn't complete yet, so...
  */
 #define CONFIG_MTD_CEIVA_STATICMAP
 
-static __u8 clps_read8(struct map_info *map, unsigned long ofs)
-{
-	return readb(map->map_priv_1 + ofs);
-}
-
-static __u16 clps_read16(struct map_info *map, unsigned long ofs)
-{
-	return readw(map->map_priv_1 + ofs);
-}
-
-static __u32 clps_read32(struct map_info *map, unsigned long ofs)
-{
-	return readl(map->map_priv_1 + ofs);
-}
-
-static void clps_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy(to, (void *)(map->map_priv_1 + from), len);
-}
-
-static void clps_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	writeb(d, map->map_priv_1 + adr);
-}
-
-static void clps_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	writew(d, map->map_priv_1 + adr);
-}
-
-static void clps_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	writel(d, map->map_priv_1 + adr);
-}
-
-static void clps_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy((void *)(map->map_priv_1 + to), from, len);
-}
-
-static struct map_info clps_map __initdata = {
-	.name		= "clps flash",
-	.read8		= clps_read8,
-	.read16		= clps_read16,
-	.read32		= clps_read32,
-	.copy_from	= clps_copy_from,
-	.write8		= clps_write8,
-	.write16	= clps_write16,
-	.write32	= clps_write32,
-	.copy_to	= clps_copy_to,
-};
-
 #ifdef CONFIG_MTD_CEIVA_STATICMAP
 /*
  * See include/linux/mtd/partitions.h for definition of the mtd_partition
@@ -94,7 +43,7 @@
  *
  * Please note:
  *  1. The flash size given should be the largest flash size that can
- *     be accommodated.
+ *     be accomodated.
  *
  *  2. The bus width must defined in clps_setup_flash.
  *
@@ -115,25 +64,23 @@
 
 static struct mtd_partition ceiva_partitions[] = {
 	{
-		.name	= "Ceiva BOOT partition",
-		.size	= BOOT_PARTITION_SIZE_KiB*1024,
-
-	},
-	{
-		.name	= "Ceiva parameters partition",
-		.size	= PARAMS_PARTITION_SIZE_KiB*1024,
-		.offset	= (16 + 8) * 1024,
-	},
-	{
-		.name	= "Ceiva kernel partition",
-		.size	= (KERNEL_PARTITION_SIZE_KiB)*1024,
-		.offset	= 0x20000,
-
-	},
-	{
-		.name	= "Ceiva root filesystem partition",
-		.offset	= MTDPART_OFS_APPEND,
-		.size	= (ROOT_PARTITION_SIZE_KiB)*1024,
+		name: "Ceiva BOOT partition",
+		size:   BOOT_PARTITION_SIZE_KiB*1024,
+		offset: 0,
+
+	},{
+		name: "Ceiva parameters partition",
+		size:   PARAMS_PARTITION_SIZE_KiB*1024,
+		offset: (16 + 8) * 1024,
+	},{
+		name: "Ceiva kernel partition",
+		size: (KERNEL_PARTITION_SIZE_KiB)*1024,
+		offset: 0x20000,
+
+	},{
+		name: "Ceiva root filesystem partition",
+		offset: MTDPART_OFS_APPEND,
+		size: (ROOT_PARTITION_SIZE_KiB)*1024,
 	}
 };
 #endif
@@ -178,7 +125,7 @@
 	maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
 	if (!maps)
 		return -ENOMEM;
-
+	memset(maps, 0, sizeof(struct map_info) * nr);
 	/*
 	 * Claim and then map the memory regions.
 	 */
@@ -193,7 +140,9 @@
 		}
 
 		clps[i].map = maps + i;
-		memcpy(clps[i].map, &clps_map, sizeof(struct map_info));
+
+		clps[i].map->name = "clps flash";
+		clps[i].map->phys = clps[i].base;
 
 		clps[i].vbase = ioremap(clps[i].base, clps[i].size);
 		if (!clps[i].vbase) {
@@ -201,16 +150,18 @@
 			break;
 		}
 
-		clps[i].map->map_priv_1 = (unsigned long)clps[i].vbase;
+		clps[i].map->virt = (unsigned long)clps[i].vbase;
 		clps[i].map->buswidth = clps[i].width;
 		clps[i].map->size = clps[i].size;
 
+		simple_map_init(&clps[i].map);
+
 		clps[i].mtd = do_map_probe("jedec_probe", clps[i].map);
 		if (clps[i].mtd == NULL) {
 			ret = -ENXIO;
 			break;
 		}
-		clps[i].mtd->module = THIS_MODULE;
+		clps[i].mtd->owner = THIS_MODULE;
 		subdev[i] = clps[i].mtd;
 
 		printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, "
@@ -320,10 +271,8 @@
 	return nr;
 }
 
-extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
-extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
-
 static struct mtd_partition *parsed_parts;
+static const char *probes[] = { "cmdlinepart", "RedBoot", NULL };
 
 static void __init clps_locate_partitions(struct mtd_info *mtd)
 {
@@ -333,20 +282,11 @@
 		/*
 		 * Partition selection stuff.
 		 */
-#ifdef CONFIG_MTD_CMDLINE_PARTS
-		nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "clps");
+		nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0);
 		if (nr_parts > 0) {
 			part_type = "command line";
 			break;
 		}
-#endif
-#ifdef CONFIG_MTD_REDBOOT_PARTS
-		nr_parts = parse_redboot_partitions(mtd, &parsed_parts);
-		if (nr_parts > 0) {
-			part_type = "RedBoot";
-			break;
-		}
-#endif
 #ifdef CONFIG_MTD_CEIVA_STATICMAP
 		nr_parts = clps_static_partitions(&parsed_parts);
 		if (nr_parts > 0) {
diff -Nru a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c
--- a/drivers/mtd/maps/cfi_flagadm.c	Wed Feb 26 04:25:11 2003
+++ b/drivers/mtd/maps/cfi_flagadm.c	Wed May 28 08:01:03 2003
@@ -1,7 +1,7 @@
 /*
  *  Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson <kd@flaga.is>
  *
- *  $Id: cfi_flagadm.c,v 1.7 2001/10/02 15:05:13 dwmw2 Exp $
+ *  $Id: cfi_flagadm.c,v 1.11 2003/05/21 12:45:18 dwmw2 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
@@ -27,6 +27,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -55,83 +56,33 @@
 #define FLASH_PARTITION3_ADDR 0x00240000
 #define FLASH_PARTITION3_SIZE 0x001C0000
 
-__u8 flagadm_read8(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readb(map->map_priv_1 + ofs);
-}
-
-__u16 flagadm_read16(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readw(map->map_priv_1 + ofs);
-}
-
-__u32 flagadm_read32(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readl(map->map_priv_1 + ofs);
-}
-
-void flagadm_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, map->map_priv_1 + from, len);
-}
-
-void flagadm_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	__raw_writeb(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void flagadm_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	__raw_writew(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void flagadm_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	__raw_writel(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void flagadm_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy_toio(map->map_priv_1 + to, from, len);
-}
 
 struct map_info flagadm_map = {
-	.name		= "FlagaDM flash device",
-	.size		= FLASH_SIZE,
-	.buswidth	= 2,
-	.read8		= flagadm_read8,
-	.read16		= flagadm_read16,
-	.read32		= flagadm_read32,
-	.copy_from	= flagadm_copy_from,
-	.write8		= flagadm_write8,
-	.write16	= flagadm_write16,
-	.write32	= flagadm_write32,
-	.copy_to	= flagadm_copy_to
+		.name =		"FlagaDM flash device",
+		.size =		FLASH_SIZE,
+		.buswidth =	2,
 };
 
 struct mtd_partition flagadm_parts[] = {
 	{
-		.name	= "Bootloader",
-		.offset	= FLASH_PARTITION0_ADDR,
-		.size	= FLASH_PARTITION0_SIZE
+		.name =		"Bootloader",
+		.offset	=	FLASH_PARTITION0_ADDR,
+		.size =		FLASH_PARTITION0_SIZE
 	},
 	{
-		.name	= "Kernel image",
-		.offset	= FLASH_PARTITION1_ADDR,
-		.size	= FLASH_PARTITION1_SIZE
+		.name =		"Kernel image",
+		.offset =	FLASH_PARTITION1_ADDR,
+		.size =		FLASH_PARTITION1_SIZE
 	},
 	{
-		.name	= "Initial ramdisk image",
-		.offset	= FLASH_PARTITION2_ADDR,
-		.size	= FLASH_PARTITION2_SIZE
+		.name =		"Initial ramdisk image",
+		.offset =	FLASH_PARTITION2_ADDR,
+		.size =		FLASH_PARTITION2_SIZE
 	},
 	{	
-		.name	= "Persistant storage",
-		.offset	= FLASH_PARTITION3_ADDR,
-		.size	= FLASH_PARTITION3_SIZE
+		.name =		"Persistant storage",
+		.offset =	FLASH_PARTITION3_ADDR,
+		.size =		FLASH_PARTITION3_SIZE
 	}
 };
 
@@ -144,22 +95,26 @@
 	printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n",
 			FLASH_SIZE, FLASH_PHYS_ADDR);
 	
-	flagadm_map.map_priv_1 = (unsigned long)ioremap(FLASH_PHYS_ADDR,
+	flagadm_map.phys = FLASH_PHYS_ADDR;
+	flagadm_map.virt = (unsigned long)ioremap(FLASH_PHYS_ADDR,
 					FLASH_SIZE);
 
-	if (!flagadm_map.map_priv_1) {
+	if (!flagadm_map.virt) {
 		printk("Failed to ioremap\n");
 		return -EIO;
 	}
+
+	simple_map_init(&flagadm_map);
+
 	mymtd = do_map_probe("cfi_probe", &flagadm_map);
 	if (mymtd) {
-		mymtd->module = THIS_MODULE;
+		mymtd->owner = THIS_MODULE;
 		add_mtd_partitions(mymtd, flagadm_parts, PARTITION_COUNT);
 		printk(KERN_NOTICE "FlagaDM flash device initialized\n");
 		return 0;
 	}
 
-	iounmap((void *)flagadm_map.map_priv_1);
+	iounmap((void *)flagadm_map.virt);
 	return -ENXIO;
 }
 
@@ -169,9 +124,9 @@
 		del_mtd_partitions(mymtd);
 		map_destroy(mymtd);
 	}
-	if (flagadm_map.map_priv_1) {
-		iounmap((void *)flagadm_map.map_priv_1);
-		flagadm_map.map_priv_1 = 0;
+	if (flagadm_map.virt) {
+		iounmap((void *)flagadm_map.virt);
+		flagadm_map.virt = 0;
 	}
 }
 
diff -Nru a/drivers/mtd/maps/cstm_mips_ixx.c b/drivers/mtd/maps/cstm_mips_ixx.c
--- a/drivers/mtd/maps/cstm_mips_ixx.c	Wed Feb 26 05:14:42 2003
+++ b/drivers/mtd/maps/cstm_mips_ixx.c	Wed May 28 08:01:03 2003
@@ -1,11 +1,11 @@
 /*
- * $Id: cstm_mips_ixx.c,v 1.5 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: cstm_mips_ixx.c,v 1.9 2003/05/21 12:45:18 dwmw2 Exp $
  *
  * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions.
  * Config with both CFI and JEDEC device support.
  *
  * Basically physmap.c with the addition of partitions and 
- * an array of mapping info to accommodate more than one flash type per board.
+ * an array of mapping info to accomodate more than one flash type per board.
  *
  * Copyright 2000 MontaVista Software Inc.
  *
@@ -33,55 +33,13 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 #include <linux/config.h>
-
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
 #include <linux/delay.h>
-#endif
-
-__u8 cstm_mips_ixx_read8(struct map_info *map, unsigned long ofs)
-{
-	return *(__u8 *)(map->map_priv_1 + ofs);
-}
-
-__u16 cstm_mips_ixx_read16(struct map_info *map, unsigned long ofs)
-{
-	return *(__u16 *)(map->map_priv_1 + ofs);
-}
-
-__u32 cstm_mips_ixx_read32(struct map_info *map, unsigned long ofs)
-{
-	return *(__u32 *)(map->map_priv_1 + ofs);
-}
-
-void cstm_mips_ixx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, map->map_priv_1 + from, len);
-}
-
-void cstm_mips_ixx_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	*(__u8 *)(map->map_priv_1 + adr) = d;
-}
-
-void cstm_mips_ixx_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	*(__u16 *)(map->map_priv_1 + adr) = d;
-}
-
-void cstm_mips_ixx_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	*(__u32 *)(map->map_priv_1 + adr) = d;
-}
-
-void cstm_mips_ixx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy_toio(map->map_priv_1 + to, from, len);
-}
 
 #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
 #define CC_GCR             0xB4013818
@@ -97,51 +55,47 @@
 #define CC_GPAICR          0xB4013804
 #endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
 
+#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
 void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp)
 {
-  if (vpp) {
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-        __u16	data;
-        __u8	data1;
-	static u8 first = 1;
-
-	// Set GPIO port B pin3 to high
-	data = *(__u16 *)(CC_GPBCR);
-	data = (data & 0xff0f) | 0x0040;
-	*(__u16 *)CC_GPBCR = data;
-	*(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) | 0x08;
-	if (first) {
-		first = 0;
-		/* need to have this delay for first
-		   enabling vpp after powerup */
-		udelay(40);
+	static spinlock_t vpp_lock = SPIN_LOCK_UNLOCKED;
+	static int vpp_count = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vpp_lock, flags);
+
+	if (vpp) {
+		if (!vpp_count++) {
+			__u16	data;
+			__u8	data1;
+			static u8 first = 1;
+		
+			// Set GPIO port B pin3 to high
+			data = *(__u16 *)(CC_GPBCR);
+			data = (data & 0xff0f) | 0x0040;
+			*(__u16 *)CC_GPBCR = data;
+			*(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) | 0x08;
+			if (first) {
+				first = 0;
+				/* need to have this delay for first
+				   enabling vpp after powerup */
+				udelay(40);
+			}
+		}
+	} else {
+		if (!--vpp_count) {
+			__u16	data;
+		
+			// Set GPIO port B pin3 to high
+			data = *(__u16 *)(CC_GPBCR);
+			data = (data & 0xff3f) | 0x0040;
+			*(__u16 *)CC_GPBCR = data;
+			*(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) & 0xf7;
+		}
 	}
-#endif /* CONFIG_MIPS_ITE8172 */
-  }
-  else {
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-        __u16	data;
-
-	// Set GPIO port B pin3 to high
-	data = *(__u16 *)(CC_GPBCR);
-	data = (data & 0xff3f) | 0x0040;
-	*(__u16 *)CC_GPBCR = data;
-	*(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) & 0xf7;
-#endif /* CONFIG_MIPS_ITE8172 */
-  }
+	spin_unlock_irqrestore(&vpp_lock, flags);
 }
-
-const struct map_info basic_cstm_mips_ixx_map = {
-	.read8		= cstm_mips_ixx_read8,
-	.read16		= cstm_mips_ixx_read16,
-	.read32		= cstm_mips_ixx_read32,
-	.copy_from	= cstm_mips_ixx_copy_from,
-	.write8		= cstm_mips_ixx_write8,
-	.write16	= cstm_mips_ixx_write16,
-	.write32	= cstm_mips_ixx_write32,
-	.copy_to	= cstm_mips_ixx_copy_to,
-	.set_vpp	= cstm_mips_ixx_set_vpp,
-};
+#endif
 
 /* board and partition description */
 
@@ -170,8 +124,9 @@
 static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = {
 {   // 28F128J3A in 2x16 configuration
 	{
-		.name	= "main partition ",
-		.size	= 0x02000000, // 128 x 2 x 128k byte sectors
+		.name = "main partition ",
+		.size = 0x02000000, // 128 x 2 x 128k byte sectors
+		.offset = 0,
 	},
 },
 };
@@ -191,8 +146,9 @@
 static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = {
 { 
 	{
-		.name	= "main partition",
-		.size	= CONFIG_MTD_CSTM_MIPS_IXX_LEN,
+		.name = "main partition",
+		.size =  CONFIG_MTD_CSTM_MIPS_IXX_LEN,
+		.offset = 0,
 	},
 },
 };
@@ -209,17 +165,24 @@
 
 	/* Initialize mapping */
 	for (i=0;i<PHYSMAP_NUMBER;i++) {
-		printk(KERN_NOTICE "cstm_mips_ixx flash device: %lx at %lx\n", cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr);
-                memcpy((char *)&cstm_mips_ixx_map[i],(char *)&basic_cstm_mips_ixx_map,sizeof(struct map_info));
-		cstm_mips_ixx_map[i].map_priv_1 = (unsigned long)ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size);
-		if (!cstm_mips_ixx_map[i].map_priv_1) {
+		printk(KERN_NOTICE "cstm_mips_ixx flash device: 0x%lx at 0x%lx\n", 
+		       cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr);
+
+
+		cstm_mips_ixx_map[i].phys = cstm_mips_ixx_board_desc[i].window_addr;
+		cstm_mips_ixx_map[i].virt = (unsigned long)ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size);
+		if (!cstm_mips_ixx_map[i].virt) {
 			printk(KERN_WARNING "Failed to ioremap\n");
 			return -EIO;
 	        }
 		cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name;
 		cstm_mips_ixx_map[i].size = cstm_mips_ixx_board_desc[i].window_size;
 		cstm_mips_ixx_map[i].buswidth = cstm_mips_ixx_board_desc[i].buswidth;
-		//printk(KERN_NOTICE "cstm_mips_ixx: ioremap is %x\n",(unsigned int)(cstm_mips_ixx_map[i].map_priv_1));
+#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
+                cstm_mips_ixx_map[i].set_vpp = cstm_mips_ixx_set_vpp;
+#endif
+		simple_map_init(&cstm_mips_ixx_map[i]);
+		//printk(KERN_NOTICE "cstm_mips_ixx: ioremap is %x\n",(unsigned int)(cstm_mips_ixx_map[i].virt));
 	}
 
 #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
@@ -237,7 +200,7 @@
 		        printk(KERN_NOTICE "cstm_mips_ixx %d jedec: mymtd is %x\n",i,(unsigned int)mymtd);
 		}
 		if (mymtd) {
-			mymtd->module = THIS_MODULE;
+			mymtd->owner = THIS_MODULE;
 
 	                cstm_mips_ixx_map[i].map_priv_2 = (unsigned long)mymtd;
 		        add_mtd_partitions(mymtd, parts, cstm_mips_ixx_board_desc[i].num_partitions);
@@ -259,9 +222,9 @@
 			del_mtd_partitions(mymtd);
 			map_destroy(mymtd);
 		}
-		if (cstm_mips_ixx_map[i].map_priv_1) {
-			iounmap((void *)cstm_mips_ixx_map[i].map_priv_1);
-			cstm_mips_ixx_map[i].map_priv_1 = 0;
+		if (cstm_mips_ixx_map[i].virt) {
+			iounmap((void *)cstm_mips_ixx_map[i].virt);
+			cstm_mips_ixx_map[i].virt = 0;
 		}
 	}
 }
diff -Nru a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c
--- a/drivers/mtd/maps/dbox2-flash.c	Wed Feb 26 05:13:59 2003
+++ b/drivers/mtd/maps/dbox2-flash.c	Wed May 28 08:01:03 2003
@@ -1,12 +1,13 @@
 /*
- * $Id: dbox2-flash.c,v 1.4 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: dbox2-flash.c,v 1.9 2003/05/21 12:45:18 dwmw2 Exp $
  *
- * Nokia / Sagem D-Box 2 flash driver
+ * D-Box 2 flash driver
  */
 
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -18,24 +19,40 @@
  * device. */
 static struct mtd_partition partition_info[]= {
 	{
-		.name		= "BR bootloader",	/* raw */
-		.size		= 128 * 1024, 
-		.mask_flags	= MTD_WRITEABLE
+	.name		= "BR bootloader",
+	.size		= 128 * 1024, 
+	.offset		= 0,                  
+	.mask_flags	= MTD_WRITEABLE
 	},
 	{
-		.name		= "PPC bootloader",	/* flfs */
-		.size		= 128 * 1024, 
-		.offset		= MTDPART_OFS_APPEND, 
+	.name		= "flfs (ppcboot)",
+	.size		= 128 * 1024, 
+	.offset		= MTDPART_OFS_APPEND, 
+	.mask_flags	= 0
 	},
 	{
-		.name		= "Kernel",		/* idxfs */
-		.size		= 768 * 1024, 
-		.offset		= MTDPART_OFS_APPEND, 
+	.name		= "root (cramfs)",	
+	.size		= 7040 * 1024, 
+	.offset		= MTDPART_OFS_APPEND, 
+	.mask_flags	= 0
 	},
 	{
-		.name		= "System",		/* jffs */
-		.size		= MTDPART_SIZ_FULL, 
-		.offset		= MTDPART_OFS_APPEND, 
+	.name		= "var (jffs2)",
+	.size		= 896 * 1024, 
+	.offset		= MTDPART_OFS_APPEND, 
+	.mask_flags	= 0
+	},
+	{
+	.name		= "flash without bootloader",	
+	.size		= MTDPART_SIZ_FULL, 
+	.offset		= 128 * 1024, 
+	.mask_flags	= 0
+	},
+	{
+	.name		= "complete flash",	
+	.size		= MTDPART_SIZ_FULL, 
+	.offset		= 0, 
+	.mask_flags	= MTD_WRITEABLE
 	}
 };
 
@@ -46,72 +63,24 @@
 
 static struct mtd_info *mymtd;
 
-__u8 dbox2_flash_read8(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readb(map->map_priv_1 + ofs);
-}
-
-__u16 dbox2_flash_read16(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readw(map->map_priv_1 + ofs);
-}
-
-__u32 dbox2_flash_read32(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readl(map->map_priv_1 + ofs);
-}
-
-void dbox2_flash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, map->map_priv_1 + from, len);
-}
-
-void dbox2_flash_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	__raw_writeb(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void dbox2_flash_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	__raw_writew(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void dbox2_flash_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	__raw_writel(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void dbox2_flash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy_toio(map->map_priv_1 + to, from, len);
-}
 
 struct map_info dbox2_flash_map = {
 	.name		= "D-Box 2 flash memory",
 	.size		= WINDOW_SIZE,
 	.buswidth	= 4,
-	.read8		= dbox2_flash_read8,
-	.read16		= dbox2_flash_read16,
-	.read32		= dbox2_flash_read32,
-	.copy_from	= dbox2_flash_copy_from,
-	.write8		= dbox2_flash_write8,
-	.write16	= dbox2_flash_write16,
-	.write32	= dbox2_flash_write32,
-	.copy_to	= dbox2_flash_copy_to
+	.phys		= WINDOW_ADDR,
 };
 
 int __init init_dbox2_flash(void)
 {
        	printk(KERN_NOTICE "D-Box 2 flash driver (size->0x%X mem->0x%X)\n", WINDOW_SIZE, WINDOW_ADDR);
-	dbox2_flash_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
+	dbox2_flash_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
 
-	if (!dbox2_flash_map.map_priv_1) {
+	if (!dbox2_flash_map.virt) {
 		printk("Failed to ioremap\n");
 		return -EIO;
 	}
+	simple_map_init(&dbox2_flash_map);
 
 	// Probe for dual Intel 28F320 or dual AMD
 	mymtd = do_map_probe("cfi_probe", &dbox2_flash_map);
@@ -123,7 +92,7 @@
 	}
 	    
 	if (mymtd) {
-		mymtd->module = THIS_MODULE;
+		mymtd->owner = THIS_MODULE;
 
                 /* Create MTD devices for each partition. */
 	        add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
@@ -131,7 +100,7 @@
 		return 0;
 	}
 
-	iounmap((void *)dbox2_flash_map.map_priv_1);
+	iounmap((void *)dbox2_flash_map.virt);
 	return -ENXIO;
 }
 
@@ -141,9 +110,9 @@
 		del_mtd_partitions(mymtd);
 		map_destroy(mymtd);
 	}
-	if (dbox2_flash_map.map_priv_1) {
-		iounmap((void *)dbox2_flash_map.map_priv_1);
-		dbox2_flash_map.map_priv_1 = 0;
+	if (dbox2_flash_map.virt) {
+		iounmap((void *)dbox2_flash_map.virt);
+		dbox2_flash_map.virt = 0;
 	}
 }
 
@@ -152,5 +121,5 @@
 
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kári Davíðsson <kd@flaga.is>");
-MODULE_DESCRIPTION("MTD map driver for Nokia/Sagem D-Box 2 board");
+MODULE_AUTHOR("Kári Davíðsson <kd@flaga.is>, Bastian Blank <waldi@tuxbox.org>, Alexander Wild <wild@te-elektronik.com>");
+MODULE_DESCRIPTION("MTD map driver for D-Box 2 board");
diff -Nru a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c
--- a/drivers/mtd/maps/dc21285.c	Thu Feb 27 22:41:22 2003
+++ b/drivers/mtd/maps/dc21285.c	Wed May 28 08:01:03 2003
@@ -5,12 +5,13 @@
  *
  * This code is GPL
  * 
- * $Id: dc21285.c,v 1.9 2002/10/14 12:22:10 rmk Exp $
+ * $Id: dc21285.c,v 1.15 2003/05/21 12:45:18 dwmw2 Exp $
  */
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -92,28 +93,42 @@
 }
 
 struct map_info dc21285_map = {
-	.name		= "DC21285 flash",
-	.size		= 16*1024*1024,
-	.read8		= dc21285_read8,
-	.read16		= dc21285_read16,
-	.read32		= dc21285_read32,
-	.copy_from	= dc21285_copy_from,
-	.write8		= dc21285_write8,
-	.write16	= dc21285_write16,
-	.write32	= dc21285_write32,
-	.copy_to	= dc21285_copy_to
+	.name = "DC21285 flash",
+	.phys = NO_XIP,
+	.size = 16*1024*1024,
+	.read8 = dc21285_read8,
+	.read16 = dc21285_read16,
+	.read32 = dc21285_read32,
+	.copy_from = dc21285_copy_from,
+	.write8 = dc21285_write8,
+	.write16 = dc21285_write16,
+	.write32 = dc21285_write32,
+	.copy_to = dc21285_copy_to
 };
 
+
 /* Partition stuff */
 static struct mtd_partition *dc21285_parts;
-		      
-extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
-extern int parse_cmdline_partitions(struct mtd_info *master,
-				    struct mtd_partition **pparts,
-				    const char *mtd_id);
-
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
+#endif
+  
 int __init init_dc21285(void)
 {
+
+	/* 
+	 * Flash timing is determined with bits 19-16 of the
+	 * CSR_SA110_CNTL.  The value is the number of wait cycles, or
+	 * 0 for 16 cycles (the default).  Cycles are 20 ns.
+	 * Here we use 7 for 140 ns flash chips.
+	 */
+	/* access time */
+	*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
+	/* burst time */
+	*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
+	/* tristate time */
+	*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
+
 	/* Determine buswidth */
 	switch (*CSR_SA110_CNTL & (3<<14)) {
 		case SA110_CNTL_ROMWIDTH_8: 
@@ -142,50 +157,19 @@
 	mymtd = do_map_probe("cfi_probe", &dc21285_map);
 	if (mymtd) {
 		int nrparts = 0;
-		const char *part_type = NULL;
 
-		mymtd->module = THIS_MODULE;
+		mymtd->owner = THIS_MODULE;
 			
 		/* partition fixup */
-		do {
-#ifdef CONFIG_MTD_CMDLINE_PARTS
-			nrparts = parse_cmdline_partitions(mymtd, &dc21285_parts, "dc21285");
-			if (nrparts > 0) {
-				part_type = "command line";
-				break;
-			}
-#endif
-#ifdef CONFIG_MTD_REDBOOT_PARTS
-			nrparts = parse_redboot_partitions(mymtd, &dc21285_parts);
-			if (nrparts > 0) {
-				part_type = "RedBoot";
-				break;
-			}
-#endif
-		} while (0);
 
+#ifdef CONFIG_MTD_PARTITIONS
+		nrparts = parse_mtd_partitions(mymtd, probes, &dc21285_parts, (void *)0);
 		if (nrparts > 0) {
 			add_mtd_partitions(mymtd, dc21285_parts, nrparts);
-			printk(KERN_NOTICE "DC21285 using %s partition "
-			       "definition\n", part_type);
-		} else if (nrparts == 0) {
-			printk(KERN_NOTICE "DC21285 partition table failed\n");
-			add_mtd_device(mymtd);
+			return 0;
 		}
-
-		/* 
-		 * Flash timing is determined with bits 19-16 of the
-		 * CSR_SA110_CNTL.  The value is the number of wait cycles, or
-		 * 0 for 16 cycles (the default).  Cycles are 20 ns.
-		 * Here we use 7 for 140 ns flash chips.
-		 */
-		/* access time */
-		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
-		/* burst time */
-		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
-		/* tristate time */
-		*CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
-
+#endif
+		add_mtd_device(mymtd);
 		return 0;
 	}
 
@@ -195,17 +179,16 @@
 
 static void __exit cleanup_dc21285(void)
 {
-	if (mymtd) {
-		del_mtd_device(mymtd);
-		map_destroy(mymtd);
-		mymtd = NULL;
-	}
-	if (dc21285_map.map_priv_1) {
-		iounmap((void *)dc21285_map.map_priv_1);
-		dc21285_map.map_priv_1 = 0;
-	}
-	if(dc21285_parts)
+#ifdef CONFIG_MTD_PARTITIONS
+	if (dc21285_parts) {
+		del_mtd_partitions(mymtd);
 		kfree(dc21285_parts);
+	} else
+#endif
+		del_mtd_device(mymtd);
+
+	map_destroy(mymtd);
+	iounmap((void *)dc21285_map.map_priv_1);
 }
 
 module_init(init_dc21285);
diff -Nru a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/dilnetpc.c	Wed May 28 08:01:14 2003
@@ -0,0 +1,495 @@
+/* dilnetpc.c -- MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP"
+ *
+ * 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
+ *
+ * $Id: dilnetpc.c,v 1.12 2003/05/21 12:45:18 dwmw2 Exp $
+ *
+ * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems
+ * featuring the AMD Elan SC410 processor. There are two variants of this
+ * board: DNP/1486 and ADNP/1486. The DNP version has 2 megs of flash
+ * ROM (Intel 28F016S3) and 8 megs of DRAM, the ADNP version has 4 megs
+ * flash and 16 megs of RAM.
+ * For details, see http://www.ssv-embedded.de/ssv/pc104/p169.htm
+ * and http://www.ssv-embedded.de/ssv/pc104/p170.htm
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
+
+/*
+** The DIL/NetPC keeps its BIOS in two distinct flash blocks.
+** Destroying any of these blocks transforms the DNPC into
+** a paperweight (albeit not a very useful one, considering
+** it only weighs a few grams).
+**
+** Therefore, the BIOS blocks must never be erased or written to
+** except by people who know exactly what they are doing (e.g.
+** to install a BIOS update). These partitions are marked read-only
+** by default, but can be made read/write by undefining
+** DNPC_BIOS_BLOCKS_WRITEPROTECTED:
+*/
+#define DNPC_BIOS_BLOCKS_WRITEPROTECTED
+
+/*
+** The ID string (in ROM) is checked to determine whether we
+** are running on a DNP/1486 or ADNP/1486
+*/
+#define BIOSID_BASE	0x000fe100
+
+#define ID_DNPC	"DNP1486"
+#define ID_ADNP	"ADNP1486"
+
+/*
+** Address where the flash should appear in CPU space
+*/
+#define FLASH_BASE	0x2000000
+
+/*
+** Chip Setup and Control (CSC) indexed register space
+*/
+#define CSC_INDEX	0x22
+#define CSC_DATA	0x23
+
+#define CSC_MMSWAR	0x30	/* MMS window C-F attributes register */
+#define CSC_MMSWDSR	0x31	/* MMS window C-F device select register */
+
+#define CSC_RBWR	0xa7	/* GPIO Read-Back/Write Register B */
+
+#define CSC_CR		0xd0	/* internal I/O device disable/Echo */
+				/* Z-bus/configuration register */
+
+#define CSC_PCCMDCR	0xf1	/* PC card mode and DMA control register */
+
+
+/*
+** PC Card indexed register space:
+*/
+
+#define PCC_INDEX	0x3e0
+#define PCC_DATA	0x3e1
+
+#define PCC_AWER_B		0x46	/* Socket B Address Window enable register */
+#define PCC_MWSAR_1_Lo	0x58	/* memory window 1 start address low register */
+#define PCC_MWSAR_1_Hi	0x59	/* memory window 1 start address high register */
+#define PCC_MWEAR_1_Lo	0x5A	/* memory window 1 stop address low register */
+#define PCC_MWEAR_1_Hi	0x5B	/* memory window 1 stop address high register */
+#define PCC_MWAOR_1_Lo	0x5C	/* memory window 1 address offset low register */
+#define PCC_MWAOR_1_Hi	0x5D	/* memory window 1 address offset high register */
+
+
+/*
+** Access to SC4x0's Chip Setup and Control (CSC)
+** and PC Card (PCC) indexed registers:
+*/
+static inline void setcsc(int reg, unsigned char data)
+{
+	outb(reg, CSC_INDEX);
+	outb(data, CSC_DATA);
+}
+
+static inline unsigned char getcsc(int reg)
+{
+	outb(reg, CSC_INDEX);
+	return(inb(CSC_DATA));
+}
+
+static inline void setpcc(int reg, unsigned char data)
+{
+	outb(reg, PCC_INDEX);
+	outb(data, PCC_DATA);
+}
+
+static inline unsigned char getpcc(int reg)
+{
+	outb(reg, PCC_INDEX);
+	return(inb(PCC_DATA));
+}
+
+
+/*
+************************************************************
+** Enable access to DIL/NetPC's flash by mapping it into
+** the SC4x0's MMS Window C.
+************************************************************
+*/
+static void dnpc_map_flash(unsigned long flash_base, unsigned long flash_size)
+{
+	unsigned long flash_end = flash_base + flash_size - 1;
+
+	/*
+	** enable setup of MMS windows C-F:
+	*/
+	/* - enable PC Card indexed register space */
+	setcsc(CSC_CR, getcsc(CSC_CR) | 0x2);
+	/* - set PC Card controller to operate in standard mode */
+	setcsc(CSC_PCCMDCR, getcsc(CSC_PCCMDCR) & ~1);
+
+	/*
+	** Program base address and end address of window
+	** where the flash ROM should appear in CPU address space
+	*/
+	setpcc(PCC_MWSAR_1_Lo, (flash_base >> 12) & 0xff);
+	setpcc(PCC_MWSAR_1_Hi, (flash_base >> 20) & 0x3f);
+	setpcc(PCC_MWEAR_1_Lo, (flash_end >> 12) & 0xff);
+	setpcc(PCC_MWEAR_1_Hi, (flash_end >> 20) & 0x3f);
+
+	/* program offset of first flash location to appear in this window (0) */
+	setpcc(PCC_MWAOR_1_Lo, ((0 - flash_base) >> 12) & 0xff);
+	setpcc(PCC_MWAOR_1_Hi, ((0 - flash_base)>> 20) & 0x3f);
+
+	/* set attributes for MMS window C: non-cacheable, write-enabled */
+	setcsc(CSC_MMSWAR, getcsc(CSC_MMSWAR) & ~0x11);
+
+	/* select physical device ROMCS0 (i.e. flash) for MMS Window C */
+	setcsc(CSC_MMSWDSR, getcsc(CSC_MMSWDSR) & ~0x03);
+
+	/* enable memory window 1 */
+	setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) | 0x02);
+
+	/* now disable PC Card indexed register space again */
+	setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2);
+}
+
+
+/*
+************************************************************
+** Disable access to DIL/NetPC's flash by mapping it into
+** the SC4x0's MMS Window C.
+************************************************************
+*/
+static void dnpc_unmap_flash(void)
+{
+	/* - enable PC Card indexed register space */
+	setcsc(CSC_CR, getcsc(CSC_CR) | 0x2);
+
+	/* disable memory window 1 */
+	setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) & ~0x02);
+
+	/* now disable PC Card indexed register space again */
+	setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2);
+}
+
+
+
+/*
+************************************************************
+** Enable/Disable VPP to write to flash
+************************************************************
+*/
+
+static spinlock_t dnpc_spin   = SPIN_LOCK_UNLOCKED;
+static int        vpp_counter = 0;
+/*
+** This is what has to be done for the DNP board ..
+*/
+static void dnp_set_vpp(struct map_info *not_used, int on)
+{
+	spin_lock_irq(&dnpc_spin);
+
+	if (on)
+	{
+		if(++vpp_counter == 1)
+			setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x4);
+	}
+	else
+	{
+		if(--vpp_counter == 0)
+			setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x4);
+		else if(vpp_counter < 0)
+			BUG();
+	}
+	spin_unlock_irq(&dnpc_spin);
+}
+
+/*
+** .. and this the ADNP version:
+*/
+static void adnp_set_vpp(struct map_info *not_used, int on)
+{
+	spin_lock_irq(&dnpc_spin);
+
+	if (on)
+	{
+		if(++vpp_counter == 1)
+			setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x8);
+	}
+	else
+	{
+		if(--vpp_counter == 0)
+			setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x8);
+		else if(vpp_counter < 0)
+			BUG();
+	}
+	spin_unlock_irq(&dnpc_spin);
+}
+
+
+
+#define DNP_WINDOW_SIZE		0x00200000	/*  DNP flash size is 2MiB  */
+#define ADNP_WINDOW_SIZE	0x00400000	/* ADNP flash size is 4MiB */
+#define WINDOW_ADDR		FLASH_BASE
+
+static struct map_info dnpc_map = {
+	.name = "ADNP Flash Bank",
+	.size = ADNP_WINDOW_SIZE,
+	.buswidth = 1,
+	.set_vpp = adnp_set_vpp,
+	.phys = WINDOW_ADDR
+};
+
+/*
+** The layout of the flash is somewhat "strange":
+**
+** 1.  960 KiB (15 blocks) : Space for ROM Bootloader and user data
+** 2.   64 KiB (1 block)   : System BIOS
+** 3.  960 KiB (15 blocks) : User Data (DNP model) or
+** 3. 3008 KiB (47 blocks) : User Data (ADNP model)
+** 4.   64 KiB (1 block)   : System BIOS Entry
+*/
+
+static struct mtd_partition partition_info[]=
+{
+	{ 
+		.name =		"ADNP boot", 
+		.offset =	0, 
+		.size =		0xf0000,
+	},
+	{ 
+		.name =		"ADNP system BIOS", 
+		.offset =	MTDPART_OFS_NXTBLK,
+		.size =		0x10000,
+#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
+		.mask_flags =	MTD_WRITEABLE,
+#endif
+	},
+	{
+		.name =		"ADNP file system",
+		.offset =	MTDPART_OFS_NXTBLK,
+		.size =		0x2f0000,
+	},
+	{
+		.name =		"ADNP system BIOS entry", 
+		.offset =	MTDPART_OFS_NXTBLK,
+		.size =		MTDPART_SIZ_FULL,
+#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
+		.mask_flags =	MTD_WRITEABLE,
+#endif
+	},
+};
+
+#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
+
+static struct mtd_info *mymtd;
+static struct mtd_info *lowlvl_parts[NUM_PARTITIONS];
+static struct mtd_info *merged_mtd;
+
+/*
+** "Highlevel" partition info:
+**
+** Using the MTD concat layer, we can re-arrange partitions to our
+** liking: we construct a virtual MTD device by concatenating the
+** partitions, specifying the sequence such that the boot block
+** is immediately followed by the filesystem block (i.e. the stupid
+** system BIOS block is mapped to a different place). When re-partitioning
+** this concatenated MTD device, we can set the boot block size to
+** an arbitrary (though erase block aligned) value i.e. not one that
+** is dictated by the flash's physical layout. We can thus set the
+** boot block to be e.g. 64 KB (which is fully sufficient if we want
+** to boot an etherboot image) or to -say- 1.5 MB if we want to boot
+** a large kernel image. In all cases, the remainder of the flash
+** is available as file system space.
+*/
+
+static struct mtd_partition higlvl_partition_info[]=
+{
+	{ 
+		.name =		"ADNP boot block", 
+		.offset =	0, 
+		.size =		CONFIG_MTD_DILNETPC_BOOTSIZE,
+	},
+	{
+		.name =		"ADNP file system space",
+		.offset =	MTDPART_OFS_NXTBLK,
+		.size =		ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000,
+	},
+	{ 
+		.name =		"ADNP system BIOS + BIOS Entry", 
+		.offset =	MTDPART_OFS_NXTBLK,
+		.size =		MTDPART_SIZ_FULL,
+#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
+		.mask_flags =	MTD_WRITEABLE,
+#endif
+	},
+};
+
+#define NUM_HIGHLVL_PARTITIONS (sizeof(higlvl_partition_info)/sizeof(partition_info[0]))
+
+
+static int dnp_adnp_probe(void)
+{
+	char *biosid, rc = -1;
+
+	biosid = (char*)ioremap(BIOSID_BASE, 16);
+	if(biosid)
+	{
+		if(!strcmp(biosid, ID_DNPC))
+			rc = 1;		/* this is a DNPC  */
+		else if(!strcmp(biosid, ID_ADNP))
+			rc = 0;		/* this is a ADNPC */
+	}
+	iounmap((void *)biosid);
+	return(rc);
+}
+
+
+static int __init init_dnpc(void)
+{
+	int is_dnp;
+
+	/*
+	** determine hardware (DNP/ADNP/invalid)
+	*/	
+	if((is_dnp = dnp_adnp_probe()) < 0)
+		return -ENXIO;
+
+	/*
+	** Things are set up for ADNP by default
+	** -> modify all that needs to be different for DNP
+	*/
+	if(is_dnp)
+	{	/*
+		** Adjust window size, select correct set_vpp function.
+		** The partitioning scheme is identical on both DNP
+		** and ADNP except for the size of the third partition.
+		*/
+		int i;
+		dnpc_map.size          = DNP_WINDOW_SIZE;
+		dnpc_map.set_vpp       = dnp_set_vpp;
+		partition_info[2].size = 0xf0000;
+
+		/*
+		** increment all string pointers so the leading 'A' gets skipped,
+		** thus turning all occurrences of "ADNP ..." into "DNP ..."
+		*/
+		++dnpc_map.name;
+		for(i = 0; i < NUM_PARTITIONS; i++)
+			++partition_info[i].name;
+		higlvl_partition_info[1].size = DNP_WINDOW_SIZE - 
+			CONFIG_MTD_DILNETPC_BOOTSIZE - 0x20000;
+		for(i = 0; i < NUM_HIGHLVL_PARTITIONS; i++)
+			++higlvl_partition_info[i].name;
+	}
+
+	printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", 
+		is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys);
+
+	dnpc_map.virt = (unsigned long)ioremap_nocache(dnpc_map.phys, dnpc_map.size);
+
+	dnpc_map_flash(dnpc_map.phys, dnpc_map.size);
+
+	if (!dnpc_map.virt) {
+		printk("Failed to ioremap_nocache\n");
+		return -EIO;
+	}
+	simple_map_init(&dnpc_map);
+
+	printk("FLASH virtual address: 0x%lx\n", dnpc_map.virt);
+
+	mymtd = do_map_probe("jedec_probe", &dnpc_map);
+
+	if (!mymtd)
+		mymtd = do_map_probe("cfi_probe", &dnpc_map);
+
+	/*
+	** If flash probes fail, try to make flashes accessible
+	** at least as ROM. Ajust erasesize in this case since
+	** the default one (128M) will break our partitioning
+	*/
+	if (!mymtd)
+		if((mymtd = do_map_probe("map_rom", &dnpc_map)))
+			mymtd->erasesize = 0x10000;
+
+	if (!mymtd) {
+		iounmap((void *)dnpc_map.virt);
+		return -ENXIO;
+	}
+		
+	mymtd->owner = THIS_MODULE;
+
+	/*
+	** Supply pointers to lowlvl_parts[] array to add_mtd_partitions()
+	** -> add_mtd_partitions() will _not_ register MTD devices for
+	** the partitions, but will instead store pointers to the MTD
+	** objects it creates into our lowlvl_parts[] array.
+	** NOTE: we arrange the pointers such that the sequence of the
+	**       partitions gets re-arranged: partition #2 follows
+	**       partition #0.
+	*/
+	partition_info[0].mtdp = &lowlvl_parts[0];
+	partition_info[1].mtdp = &lowlvl_parts[2];
+	partition_info[2].mtdp = &lowlvl_parts[1];
+	partition_info[3].mtdp = &lowlvl_parts[3];
+
+	add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
+
+	/*
+	** now create a virtual MTD device by concatenating the for partitions
+	** (in the sequence given by the lowlvl_parts[] array.
+	*/
+	merged_mtd = mtd_concat_create(lowlvl_parts, NUM_PARTITIONS, "(A)DNP Flash Concatenated");
+	if(merged_mtd)
+	{	/*
+		** now partition the new device the way we want it. This time,
+		** we do not supply mtd pointers in higlvl_partition_info, so
+		** add_mtd_partitions() will register the devices.
+		*/
+		add_mtd_partitions(merged_mtd, higlvl_partition_info, NUM_HIGHLVL_PARTITIONS);
+	}
+
+	return 0;
+}
+
+static void __exit cleanup_dnpc(void)
+{
+	if(merged_mtd) {
+		del_mtd_partitions(merged_mtd);
+		mtd_concat_destroy(merged_mtd);
+	}
+
+	if (mymtd) {
+		del_mtd_partitions(mymtd);
+		map_destroy(mymtd);
+	}
+	if (dnpc_map.virt) {
+		iounmap((void *)dnpc_map.virt);
+		dnpc_unmap_flash();
+		dnpc_map.virt = 0;
+	}
+}
+
+module_init(init_dnpc);
+module_exit(cleanup_dnpc);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sysgo Real-Time Solutions GmbH");
+MODULE_DESCRIPTION("MTD map driver for SSV DIL/NetPC DNP & ADNP");
diff -Nru a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/ebony.c	Wed May 28 08:01:15 2003
@@ -0,0 +1,166 @@
+/*
+ * $Id: ebony.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $
+ * 
+ * Mapping for Ebony user flash
+ *
+ * Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/config.h>
+#include <asm/io.h>
+#include <asm/ibm440.h>
+#include <platforms/ebony.h>
+
+static struct mtd_info *flash;
+
+static struct map_info ebony_small_map = {
+	.name =		"Ebony small flash",
+	.size =		EBONY_SMALL_FLASH_SIZE,
+	.buswidth =	1,
+};
+
+static struct map_info ebony_large_map = {
+	.name =		"Ebony large flash",
+	.size =		EBONY_LARGE_FLASH_SIZE,
+	.buswidth =	1,
+};
+
+static struct mtd_partition ebony_small_partitions[] = {
+	{
+		.name =   "OpenBIOS",
+		.offset = 0x0,
+		.size =   0x80000,
+	}
+};
+
+static struct mtd_partition ebony_large_partitions[] = {
+	{
+		.name =   "fs",
+		.offset = 0,
+		.size =   0x380000,
+	},
+	{
+		.name =   "firmware",
+		.offset = 0x380000,
+		.size =   0x80000,
+	}
+};
+
+#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
+
+int __init init_ebony(void)
+{
+	u8 fpga0_reg;
+	unsigned long fpga0_adr;
+	unsigned long long small_flash_base, large_flash_base;
+
+	fpga0_adr = ioremap64(EBONY_FPGA_ADDR, 16);
+	if (!fpga0_adr)
+		return -ENOMEM;
+
+	fpga0_reg = readb(fpga0_adr);
+	iounmap64(fpga0_adr);
+
+	if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
+			!EBONY_FLASH_SEL(fpga0_reg))
+		small_flash_base = EBONY_SMALL_FLASH_HIGH2;
+	else if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
+			EBONY_FLASH_SEL(fpga0_reg))
+		small_flash_base = EBONY_SMALL_FLASH_HIGH1;
+	else if (!EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
+			!EBONY_FLASH_SEL(fpga0_reg))
+		small_flash_base = EBONY_SMALL_FLASH_LOW2;
+	else
+		small_flash_base = EBONY_SMALL_FLASH_LOW1;
+			
+	if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
+			!EBONY_ONBRD_FLASH_EN(fpga0_reg))
+		large_flash_base = EBONY_LARGE_FLASH_LOW;
+	else
+		large_flash_base = EBONY_LARGE_FLASH_HIGH;
+
+	ebony_small_map.phys = small_flash_base;
+	ebony_small_map.virt =
+		(unsigned long)ioremap64(small_flash_base,
+					 ebony_small_map.size);
+
+	if (!ebony_small_map.virt) {
+		printk("Failed to ioremap flash\n");
+		return -EIO;
+	}
+
+	simple_map_init(&ebony_small_map);
+
+	flash = do_map_probe("map_rom", &ebony_small_map);
+	if (flash) {
+		flash->owner = THIS_MODULE;
+		add_mtd_partitions(flash, ebony_small_partitions,
+					NB_OF(ebony_small_partitions));
+	} else {
+		printk("map probe failed for flash\n");
+		return -ENXIO;
+	}
+
+	ebony_large_map.phys = large_flash_base;
+	ebony_large_map.virt =
+		(unsigned long)ioremap64(large_flash_base,
+					 ebony_large_map.size);
+
+	if (!ebony_large_map.virt) {
+		printk("Failed to ioremap flash\n");
+		return -EIO;
+	}
+
+	simple_map_init(&ebony_large_map);
+
+	flash = do_map_probe("cfi_probe", &ebony_large_map);
+	if (flash) {
+		flash->owner = THIS_MODULE;
+		add_mtd_partitions(flash, ebony_large_partitions,
+					NB_OF(ebony_large_partitions));
+	} else {
+		printk("map probe failed for flash\n");
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static void __exit cleanup_ebony(void)
+{
+	if (flash) {
+		del_mtd_partitions(flash);
+		map_destroy(flash);
+	}
+
+	if (ebony_small_map.virt) {
+		iounmap((void *)ebony_small_map.virt);
+		ebony_small_map.virt = 0;
+	}
+
+	if (ebony_large_map.virt) {
+		iounmap((void *)ebony_large_map.virt);
+		ebony_large_map.virt = 0;
+	}
+}
+
+module_init(init_ebony);
+module_exit(cleanup_ebony);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Matt Porter <mporter@mvista.com>");
+MODULE_DESCRIPTION("MTD map and partitions for IBM 440GP Ebony boards");
diff -Nru a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c
--- a/drivers/mtd/maps/edb7312.c	Wed Feb 26 04:38:07 2003
+++ b/drivers/mtd/maps/edb7312.c	Wed May 28 08:01:03 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: edb7312.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
+ * $Id: edb7312.c,v 1.8 2003/05/21 12:45:18 dwmw2 Exp $
  *
  * Handle mapping of the NOR flash on Cogent EDB7312 boards
  *
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -35,61 +36,11 @@
 
 static struct mtd_info *mymtd;
 
-__u8 edb7312nor_read8(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readb(map->map_priv_1 + ofs);
-}
-
-__u16 edb7312nor_read16(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readw(map->map_priv_1 + ofs);
-}
-
-__u32 edb7312nor_read32(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readl(map->map_priv_1 + ofs);
-}
-
-void edb7312nor_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, map->map_priv_1 + from, len);
-}
-
-void edb7312nor_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	__raw_writeb(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void edb7312nor_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	__raw_writew(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void edb7312nor_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	__raw_writel(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void edb7312nor_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy_toio(map->map_priv_1 + to, from, len);
-}
-
 struct map_info edb7312nor_map = {
-	.name		= "NOR flash on EDB7312",
-	.size		= WINDOW_SIZE,
-	.buswidth	= BUSWIDTH,
-	.read8		= edb7312nor_read8,
-	.read16		= edb7312nor_read16,
-	.read32		= edb7312nor_read32,
-	.copy_from	= edb7312nor_copy_from,
-	.write8		= edb7312nor_write8,
-	.write16	= edb7312nor_write16,
-	.write32	= edb7312nor_write32,
-	.copy_to	= edb7312nor_copy_to
+	.name = "NOR flash on EDB7312",
+	.size = WINDOW_SIZE,
+	.buswidth = BUSWIDTH,
+	.phys = WINDOW_ADDR,
 };
 
 #ifdef CONFIG_MTD_PARTITIONS
@@ -97,7 +48,8 @@
 /*
  * MTD partitioning stuff 
  */
-static struct mtd_partition static_partitions[3] = {
+static struct mtd_partition static_partitions[3] =
+{
 	{
 		.name = "ARMboot",
 		.size = 0x40000,
@@ -116,12 +68,7 @@
 };
 
 #define NB_OF(x) (sizeof (x) / sizeof (x[0]))
-
-#ifdef CONFIG_MTD_CMDLINE_PARTS
-int parse_cmdline_partitions(struct mtd_info *master, 
-			     struct mtd_partition **pparts,
-			     const char *mtd_id);
-#endif
+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
 
 #endif
 
@@ -136,13 +83,15 @@
 
        	printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", 
 	       WINDOW_SIZE, WINDOW_ADDR);
-	edb7312nor_map.map_priv_1 = (unsigned long)
+	edb7312nor_map.virt = (unsigned long)
 	  ioremap(WINDOW_ADDR, WINDOW_SIZE);
 
-	if (!edb7312nor_map.map_priv_1) {
+	if (!edb7312nor_map.virt) {
 		printk(MSG_PREFIX "failed to ioremap\n");
 		return -EIO;
 	}
+	
+	simple_map_init(&edb7312nor_map);
 
 	mymtd = 0;
 	type = rom_probe_types;
@@ -150,14 +99,13 @@
 		mymtd = do_map_probe(*type, &edb7312nor_map);
 	}
 	if (mymtd) {
-		mymtd->module = THIS_MODULE;
+		mymtd->owner = THIS_MODULE;
 
 #ifdef CONFIG_MTD_PARTITIONS
-#ifdef CONFIG_MTD_CMDLINE_PARTS
-		mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, MTDID);
+		mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, MTDID);
 		if (mtd_parts_nb > 0)
-		  part_type = "command line";
-#endif
+		  part_type = "detected";
+
 		if (mtd_parts_nb == 0)
 		{
 			mtd_parts = static_partitions;
@@ -177,7 +125,7 @@
 		return 0;
 	}
 
-	iounmap((void *)edb7312nor_map.map_priv_1);
+	iounmap((void *)edb7312nor_map.virt);
 	return -ENXIO;
 }
 
@@ -187,9 +135,9 @@
 		del_mtd_device(mymtd);
 		map_destroy(mymtd);
 	}
-	if (edb7312nor_map.map_priv_1) {
-		iounmap((void *)edb7312nor_map.map_priv_1);
-		edb7312nor_map.map_priv_1 = 0;
+	if (edb7312nor_map.virt) {
+		iounmap((void *)edb7312nor_map.virt);
+		edb7312nor_map.virt = 0;
 	}
 }
 
diff -Nru a/drivers/mtd/maps/elan-104nc.c b/drivers/mtd/maps/elan-104nc.c
--- a/drivers/mtd/maps/elan-104nc.c	Wed Feb 26 05:14:46 2003
+++ b/drivers/mtd/maps/elan-104nc.c	Wed May 28 08:01:03 2003
@@ -16,7 +16,7 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
-   $Id: elan-104nc.c,v 1.12 2001/10/02 15:05:14 dwmw2 Exp $
+   $Id: elan-104nc.c,v 1.17 2003/05/21 15:15:07 dwmw2 Exp $
 
 The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16
 mode.  This drivers uses the CFI probe and Intel Extended Command Set drivers.
@@ -27,7 +27,7 @@
    
    16 bit I/O port (0x22) for some sort of paging.
 
-The single flash device is divided into 3 partition which appear as separate
+The single flash device is divided into 3 partition which appear as seperate
 MTD devices.
 
 Linux thinks that the I/O port is used by the PIC and hence check_region() will
@@ -40,6 +40,7 @@
 #include <asm/io.h>
 
 #include <linux/mtd/map.h>
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
 #define WINDOW_START 0xb0000
@@ -58,20 +59,15 @@
 /* partition_info gives details on the logical partitions that the split the 
  * single flash device into. If the size if zero we use up to the end of the
  * device. */
-static struct mtd_partition partition_info[] = {
-	{
-		.name	= "ELAN-104NC flash boot partition", 
-		.size	= 640*1024
-	},
-	{
-		.name	= "ELAN-104NC flash partition 1", 
-		.offset	= 640*1024, 
-		.size	= 896*1024
-	},
-	{
-		.name	= "ELAN-104NC flash partition 2", 
-		.offset = (640+896)*1024,
-	}
+static struct mtd_partition partition_info[]={
+    { .name = "ELAN-104NC flash boot partition", 
+      .offset = 0, 
+      .size = 640*1024 },
+    { .name = "ELAN-104NC flash partition 1", 
+      .offset = 640*1024, 
+      .size = 896*1024 },
+    { .name = "ELAN-104NC flash partition 2", 
+      .offset = (640+896)*1024 }
 };
 #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
 
@@ -200,20 +196,20 @@
 }
 
 static struct map_info elan_104nc_map = {
-	.name		= "ELAN-104NC flash",
-	.size		= 8*1024*1024, /* this must be set to a maximum
-					  possible amount of flash so the
-					  cfi probe routines find all
-					  the chips */
-	.buswidth	= 2,
-	.read8		= elan_104nc_read8,
-	.read16		= elan_104nc_read16,
-	.read32		= elan_104nc_read32,
-	.copy_from	= elan_104nc_copy_from,
-	.write8		= elan_104nc_write8,
-	.write16	= elan_104nc_write16,
-	.write32	= elan_104nc_write32,
-	.copy_to	= elan_104nc_copy_to
+	.name = "ELAN-104NC flash",
+	.phys = NO_XIP,
+	.size = 8*1024*1024, /* this must be set to a maximum possible amount
+			of flash so the cfi probe routines find all
+			the chips */
+	.buswidth = 2,
+	.read8 = elan_104nc_read8,
+	.read16 = elan_104nc_read16,
+	.read32 = elan_104nc_read32,
+	.copy_from = elan_104nc_copy_from,
+	.write8 = elan_104nc_write8,
+	.write16 = elan_104nc_write16,
+	.write32 = elan_104nc_write32,
+	.copy_to = elan_104nc_copy_to
 };
 
 /* MTD device for all of the flash. */
@@ -266,7 +262,7 @@
 		return -ENXIO;
 	}
 	
-	all_mtd->module=THIS_MODULE;
+	all_mtd->owner = THIS_MODULE;
 
 	/* Create MTD devices for each partition. */
 	add_mtd_partitions( all_mtd, partition_info, NUM_PARTITIONS );
diff -Nru a/drivers/mtd/maps/epxa10db-flash.c b/drivers/mtd/maps/epxa10db-flash.c
--- a/drivers/mtd/maps/epxa10db-flash.c	Wed Mar 26 07:19:43 2003
+++ b/drivers/mtd/maps/epxa10db-flash.c	Wed May 28 08:01:03 2003
@@ -5,7 +5,7 @@
  *  Copyright (C) 2001 Altera Corporation
  *  Copyright (C) 2001 Red Hat, Inc.
  *
- * $Id: epxa10db-flash.c,v 1.4 2002/08/22 10:46:19 cdavies Exp $ 
+ * $Id: epxa10db-flash.c,v 1.10 2003/05/21 12:45:18 dwmw2 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
@@ -26,6 +26,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -43,87 +44,38 @@
 
 static struct mtd_info *mymtd;
 
-extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
 static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts);
 
-static __u8 epxa_read8(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readb(map->map_priv_1 + ofs);
-}
-
-static __u16 epxa_read16(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readw(map->map_priv_1 + ofs);
-}
-
-static __u32 epxa_read32(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readl(map->map_priv_1 + ofs);
-}
-
-static void epxa_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
-}
-
-static void epxa_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	__raw_writeb(d, map->map_priv_1 + adr);
-	mb();
-}
-
-static void epxa_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	__raw_writew(d, map->map_priv_1 + adr);
-	mb();
-}
-
-static void epxa_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	__raw_writel(d, map->map_priv_1 + adr);
-	mb();
-}
-
-static void epxa_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy_toio((void *)(map->map_priv_1 + to), from, len);
-}
-
-
 
 static struct map_info epxa_map = {
-	.name		= "EPXA flash",
-	.size		= FLASH_SIZE,
-	.buswidth	= 2,
-	.read8		= epxa_read8,
-	.read16		= epxa_read16,
-	.read32		= epxa_read32,
-	.copy_from	= epxa_copy_from,
-	.write8		= epxa_write8,
-	.write16	= epxa_write16,
-	.write32	= epxa_write32,
-	.copy_to	= epxa_copy_to
+	.name =		"EPXA flash",
+	.size =		FLASH_SIZE,
+	.buswidth =	2,
+	.phys =		FLASH_START,
 };
 
+static const char *probes[] = { "RedBoot", "afs", NULL };
 
 static int __init epxa_mtd_init(void)
 {
 	int i;
 	
-	printk(KERN_NOTICE "%s flash device: %x at %x\n", BOARD_NAME, FLASH_SIZE, FLASH_START);
-	epxa_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
-	if (!epxa_map.map_priv_1) {
+	printk(KERN_NOTICE "%s flash device: 0x%x at 0x%x\n", BOARD_NAME, FLASH_SIZE, FLASH_START);
+
+	epxa_map.virt = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
+	if (!epxa_map.virt) {
 		printk("Failed to ioremap %s flash\n",BOARD_NAME);
 		return -EIO;
 	}
+	simple_map_init(&epxa_map);
 
 	mymtd = do_map_probe("cfi_probe", &epxa_map);
 	if (!mymtd) {
-		iounmap((void *)epxa_map.map_priv_1);
+		iounmap((void *)epxa_map.virt);
 		return -ENXIO;
 	}
 
-	mymtd->module = THIS_MODULE;
+	mymtd->owner = THIS_MODULE;
 
 	/* Unlock the flash device. */
 	if(mymtd->unlock){
@@ -135,23 +87,14 @@
 		}
 	}
 
-#ifdef CONFIG_MTD_REDBOOT_PARTS
-	nr_parts = parse_redboot_partitions(mymtd, &parts);
+#ifdef CONFIG_MTD_PARTITIONS
+	nr_parts = parse_mtd_partitions(mymtd, probes, &parts, 0);
 
 	if (nr_parts > 0) {
 		add_mtd_partitions(mymtd, parts, nr_parts);
 		return 0;
 	}
 #endif
-#ifdef CONFIG_MTD_AFS_PARTS
-	nr_parts = parse_afs_partitions(mymtd, &parts);
-
-	if (nr_parts > 0) {
-		add_mtd_partitions(mymtd, parts, nr_parts);
-		return 0;
-	}
-#endif
-
 	/* No recognised partitioning schemes found - use defaults */
 	nr_parts = epxa_default_partitions(mymtd, &parts);
 	if (nr_parts > 0) {
@@ -173,9 +116,9 @@
 			del_mtd_device(mymtd);
 		map_destroy(mymtd);
 	}
-	if (epxa_map.map_priv_1) {
-		iounmap((void *)epxa_map.map_priv_1);
-		epxa_map.map_priv_1 = 0;
+	if (epxa_map.virt) {
+		iounmap((void *)epxa_map.virt);
+		epxa_map.virt = 0;
 	}
 }
 
@@ -199,12 +142,12 @@
 
 	printk("Using default partitions for %s\n",BOARD_NAME);
 	npartitions=1;
-	parts = kmalloc(npartitions*sizeof(*parts)+strlen(name)+1, GFP_KERNEL);
+	parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL);
+	memzero(parts,npartitions*sizeof(*parts)+strlen(name));
 	if (!parts) {
 		ret = -ENOMEM;
 		goto out;
 	}
-	memzero(parts,npartitions*sizeof(*parts)+strlen(name));
 	i=0;
 	names = (char *)&parts[npartitions];	
 	parts[i].name = names;
@@ -218,11 +161,10 @@
 	parts[i].size = FLASH_SIZE-0x00180000;
 	parts[i].offset = 0x00180000;
 #endif
-	ret = npartitions;
 
  out:
 	*pparts = parts;
-	return ret;
+	return npartitions;
 }
 
 
diff -Nru a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c
--- a/drivers/mtd/maps/fortunet.c	Wed Feb 26 04:42:32 2003
+++ b/drivers/mtd/maps/fortunet.c	Wed May 28 08:01:03 2003
@@ -1,11 +1,12 @@
 /* fortunet.c memory map
  *
- * $Id: fortunet.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
+ * $Id: fortunet.c,v 1.6 2003/05/21 12:45:18 dwmw2 Exp $
  */
 
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -23,7 +24,7 @@
 
 struct map_region
 {
-	int			window_addr_phyical;
+	int			window_addr_physical;
 	int			altbuswidth;
 	struct map_info		map_info;
 	struct mtd_info		*mymtd;
@@ -37,57 +38,10 @@
 static int			map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
 
 
-__u8 fortunet_read8(struct map_info *map, unsigned long ofs)
-{
-	return *(__u8 *)(map->map_priv_1 + ofs);
-}
-
-__u16 fortunet_read16(struct map_info *map, unsigned long ofs)
-{
-	return *(__u16 *)(map->map_priv_1 + ofs);
-}
-
-__u32 fortunet_read32(struct map_info *map, unsigned long ofs)
-{
-	return *(__u32 *)(map->map_priv_1 + ofs);
-}
-
-void fortunet_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy(to, (void *)(map->map_priv_1 + from), len);
-}
-
-void fortunet_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	*(__u8 *)(map->map_priv_1 + adr) = d;
-}
-
-void fortunet_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	*(__u16 *)(map->map_priv_1 + adr) = d;
-}
-
-void fortunet_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	*(__u32 *)(map->map_priv_1 + adr) = d;
-}
-
-void fortunet_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy((void *)(map->map_priv_1 + to), from, len);
-}
 
 struct map_info default_map = {
-	.size		= DEF_WINDOW_SIZE,
-	.buswidth	= 4,
-	.read8		= fortunet_read8,
-	.read16		= fortunet_read16,
-	.read32		= fortunet_read32,
-	.copy_from	= fortunet_copy_from,
-	.write8		= fortunet_write8,
-	.write16	= fortunet_write16,
-	.write32	= fortunet_write32,
-	.copy_to	= fortunet_copy_to
+	.size = DEF_WINDOW_SIZE,
+	.buswidth = 4,
 };
 
 static char * __init get_string_option(char *dest,int dest_size,char *sor)
@@ -147,7 +101,7 @@
 	get_options (get_string_option(string,sizeof(string),line),6,params);
 	if(params[0]<1)
 	{
-		printk(MTD_FORTUNET_PK "Bad paramters for MTD Region "
+		printk(MTD_FORTUNET_PK "Bad parameters for MTD Region "
 			" name,region-number[,base,size,buswidth,altbuswidth]\n");
 		return 1;
 	}
@@ -161,14 +115,14 @@
 	memcpy(&map_regions[params[1]].map_info,
 		&default_map,sizeof(map_regions[params[1]].map_info));
         map_regions_set[params[1]] = 1;
-        map_regions[params[1]].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
+        map_regions[params[1]].window_addr_physical = DEF_WINDOW_ADDR_PHY;
         map_regions[params[1]].altbuswidth = 2;
         map_regions[params[1]].mymtd = NULL;
 	map_regions[params[1]].map_info.name = map_regions[params[1]].map_name;
 	strcpy(map_regions[params[1]].map_info.name,string);
 	if(params[0]>1)
 	{
-		map_regions[params[1]].window_addr_phyical = params[2];
+		map_regions[params[1]].window_addr_physical = params[2];
 	}
 	if(params[0]>2)
 	{
@@ -185,14 +139,14 @@
 	return 1;
 }
 
-static int __init MTD_New_Partion(char *line)
+static int __init MTD_New_Partition(char *line)
 {
 	char	string[MAX_NAME_SIZE];
 	int	params[4];
 	get_options (get_string_option(string,sizeof(string),line),4,params);
 	if(params[0]<3)
 	{
-		printk(MTD_FORTUNET_PK "Bad paramters for MTD Partion "
+		printk(MTD_FORTUNET_PK "Bad parameters for MTD Partition "
 			" name,region-number,size,offset\n");
 		return 1;
 	}
@@ -204,7 +158,7 @@
 	}
 	if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS)
 	{
-		printk(MTD_FORTUNET_PK "Out of space for partion in this region\n");
+		printk(MTD_FORTUNET_PK "Out of space for partition in this region\n");
 		return 1;
 	}
 	map_regions[params[1]].parts[map_regions_parts[params[1]]].name =
@@ -220,7 +174,10 @@
 }
 
 __setup("MTD_Region=", MTD_New_Region);
-__setup("MTD_Partion=", MTD_New_Partion);
+__setup("MTD_Partition=", MTD_New_Partition);
+
+/* Backwards-spelling-compatibility */
+__setup("MTD_Partion=", MTD_New_Partition);
 
 int __init init_fortunet(void)
 {
@@ -229,13 +186,13 @@
 	{
 		if(map_regions_parts[ix]&&(!map_regions_set[ix]))
 		{
-			printk(MTD_FORTUNET_PK "Region %d is not setup (Seting to default)\n",
+			printk(MTD_FORTUNET_PK "Region %d is not setup (Setting to default)\n",
 				ix);
 			memset(&map_regions[ix],0,sizeof(map_regions[ix]));
 			memcpy(&map_regions[ix].map_info,&default_map,
 				sizeof(map_regions[ix].map_info));
 			map_regions_set[ix] = 1;
-			map_regions[ix].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
+			map_regions[ix].window_addr_physical = DEF_WINDOW_ADDR_PHY;
 			map_regions[ix].altbuswidth = 2;
 			map_regions[ix].mymtd = NULL;
 			map_regions[ix].map_info.name = map_regions[ix].map_name;
@@ -244,30 +201,35 @@
 		if(map_regions_set[ix])
 		{
 			iy++;
-			printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at phyicaly "
+			printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at physically "
 				" address %x size %x\n",
 				map_regions[ix].map_info.name,
-				map_regions[ix].window_addr_phyical,
+				map_regions[ix].window_addr_physical,
 				map_regions[ix].map_info.size);
-			map_regions[ix].map_info.map_priv_1 =
+
+			map_regions[ix].map_info.phys =	map_regions[ix].window_addr_physical,
+
+			map_regions[ix].map_info.virt =
 				(int)ioremap_nocache(
-				map_regions[ix].window_addr_phyical,
+				map_regions[ix].window_addr_physical,
 				map_regions[ix].map_info.size);
-			if(!map_regions[ix].map_info.map_priv_1)
+			if(!map_regions[ix].map_info.virt)
 			{
 				printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
 					map_regions[ix].map_info.name);
 				return -ENXIO;
 			}
-			printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is veritualy at: %x\n",
+			simple_map_init(&map_regions[ix].map_info);
+
+			printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is virtually at: %x\n",
 				map_regions[ix].map_info.name,
-				map_regions[ix].map_info.map_priv_1);
+				map_regions[ix].map_info.virt);
 			map_regions[ix].mymtd = do_map_probe("cfi_probe",
 				&map_regions[ix].map_info);
 			if((!map_regions[ix].mymtd)&&(
 				map_regions[ix].altbuswidth!=map_regions[ix].map_info.buswidth))
 			{
-				printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternet buswidth "
+				printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternate buswidth "
 					"for %s flash.\n",
 					map_regions[ix].map_info.name);
 				map_regions[ix].map_info.buswidth =
@@ -275,7 +237,7 @@
 				map_regions[ix].mymtd = do_map_probe("cfi_probe",
 					&map_regions[ix].map_info);
 			}
-			map_regions[ix].mymtd->module = THIS_MODULE;
+			map_regions[ix].mymtd->owner = THIS_MODULE;
 			add_mtd_partitions(map_regions[ix].mymtd,
 				map_regions[ix].parts,map_regions_parts[ix]);
 		}
@@ -297,7 +259,7 @@
 				del_mtd_partitions( map_regions[ix].mymtd );
 				map_destroy( map_regions[ix].mymtd );
 			}
-			iounmap((void *)map_regions[ix].map_info.map_priv_1);
+			iounmap((void *)map_regions[ix].map_info.virt);
 		}
 	}
 }
diff -Nru a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/h720x-flash.c	Wed May 28 08:01:16 2003
@@ -0,0 +1,142 @@
+/*
+ * Flash memory access on Hynix GMS30C7201/HMS30C7202 based 
+ * evaluation boards
+ * 
+ * (C) 2002 Jungjun Kim <jungjun.kim@hynix.com>
+ *     2003 Thomas Gleixner <tglx@linutronix.de>	
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+static struct mtd_info *mymtd;
+
+static struct map_info h720x_map = {
+	.name =		"H720X",
+	.buswidth =	4,
+	.size =		FLASH_SIZE,
+	.phys =		FLASH_PHYS,
+};
+
+static struct mtd_partition h720x_partitions[] = {
+        {
+                .name = "ArMon",
+                .size = 0x00080000,
+                .offset = 0,
+                .mask_flags = MTD_WRITEABLE
+        },{
+                .name = "Env",
+                .size = 0x00040000,
+                .offset = 0x00080000,
+                .mask_flags = MTD_WRITEABLE
+        },{
+                .name = "Kernel",
+                .size = 0x00180000,
+                .offset = 0x000c0000,
+                .mask_flags = MTD_WRITEABLE
+        },{
+                .name = "Ramdisk",
+                .size = 0x00400000,
+                .offset = 0x00240000,
+                .mask_flags = MTD_WRITEABLE
+        },{
+                .name = "jffs2",
+                .size = MTDPART_SIZ_FULL,
+                .offset = MTDPART_OFS_APPEND
+        }
+};
+
+#define NUM_PARTITIONS  (sizeof(h720x_partitions)/sizeof(h720x_partitions[0]))
+
+static int                   nr_mtd_parts;
+static struct mtd_partition *mtd_parts;
+static const char *probes[] = { "cmdlinepart", NULL };
+
+/*
+ * Initialize FLASH support
+ */
+int __init h720x_mtd_init(void)
+{
+
+	char	*part_type = NULL;
+	
+	h720x_map.virt = (unsigned long)ioremap(FLASH_PHYS, FLASH_SIZE);
+
+	if (!h720x_map.virt) {
+		printk(KERN_ERR "H720x-MTD: ioremap failed\n");
+		return -EIO;
+	}
+
+	simple_map_init(&h720x_map);
+
+	// Probe for flash buswidth 4
+	printk (KERN_INFO "H720x-MTD probing 32bit FLASH\n");
+	mymtd = do_map_probe("cfi_probe", &h720x_map);
+	if (!mymtd) {
+		printk (KERN_INFO "H720x-MTD probing 16bit FLASH\n");
+	    // Probe for buswidth 2
+	    h720x_map.buswidth = 2;
+	    mymtd = do_map_probe("cfi_probe", &h720x_map);
+	}
+	    
+	if (mymtd) {
+		mymtd->owner = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+		nr_mtd_parts = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0);
+		if (nr_mtd_parts > 0)
+			part_type = "command line";
+#endif
+		if (nr_mtd_parts <= 0) {
+			mtd_parts = h720x_partitions;
+			nr_mtd_parts = NUM_PARTITIONS;
+			part_type = "builtin";
+		}
+		printk(KERN_INFO "Using %s partition table\n", part_type);
+		add_mtd_partitions(mymtd, mtd_parts, nr_mtd_parts);
+		return 0;
+	}
+
+	iounmap((void *)h720x_map.virt);
+	return -ENXIO;
+}
+
+/*
+ * Cleanup
+ */
+static void __exit h720x_mtd_cleanup(void)
+{
+
+	if (mymtd) {
+		del_mtd_partitions(mymtd);
+		map_destroy(mymtd);
+	}
+	
+	/* Free partition info, if commandline partition was used */
+	if (mtd_parts && (mtd_parts != h720x_partitions))
+		kfree (mtd_parts);
+	
+	if (h720x_map.virt) {
+		iounmap((void *)h720x_map.virt);
+		h720x_map.virt = 0;
+	}
+}
+
+
+module_init(h720x_mtd_init);
+module_exit(h720x_mtd_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION("MTD map driver for Hynix evaluation boards");
diff -Nru a/drivers/mtd/maps/ich2rom.c b/drivers/mtd/maps/ich2rom.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/ich2rom.c	Wed May 28 08:01:16 2003
@@ -0,0 +1,316 @@
+/*
+ * ich2rom.c
+ *
+ * Normal mappings of chips in physical memory
+ * $Id: ich2rom.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#define RESERVE_MEM_REGION 0
+
+#define ICH2_FWH_REGION_START	0xFF000000UL
+#define ICH2_FWH_REGION_SIZE	0x01000000UL
+#define BIOS_CNTL	0x4e
+#define FWH_DEC_EN1	0xE3
+#define FWH_DEC_EN2	0xF0
+#define FWH_SEL1	0xE8
+#define FWH_SEL2	0xEE
+
+struct ich2rom_map_info {
+	struct map_info map;
+	struct mtd_info *mtd;
+	unsigned long window_addr;
+};
+
+static inline unsigned long addr(struct map_info *map, unsigned long ofs)
+{
+	unsigned long offset;
+	offset = ((8*1024*1024) - map->size) + ofs;
+	if (offset >= (4*1024*1024)) {
+		offset += 0x400000;
+	}
+	return map->map_priv_1 + 0x400000 + offset;
+}
+
+static inline unsigned long dbg_addr(struct map_info *map, unsigned long addr)
+{
+	return addr - map->map_priv_1 + ICH2_FWH_REGION_START;
+}
+	
+static __u8 ich2rom_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(addr(map, ofs));
+}
+
+static __u16 ich2rom_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(addr(map, ofs));
+}
+
+static __u32 ich2rom_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(addr(map, ofs));
+}
+
+static void ich2rom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, addr(map, from), len);
+}
+
+static void ich2rom_write8(struct map_info *map, __u8 d, unsigned long ofs)
+{
+	__raw_writeb(d, addr(map,ofs));
+	mb();
+}
+
+static void ich2rom_write16(struct map_info *map, __u16 d, unsigned long ofs)
+{
+	__raw_writew(d, addr(map, ofs));
+	mb();
+}
+
+static void ich2rom_write32(struct map_info *map, __u32 d, unsigned long ofs)
+{
+	__raw_writel(d, addr(map, ofs));
+	mb();
+}
+
+static void ich2rom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(addr(map, to), from, len);
+}
+
+static struct ich2rom_map_info ich2rom_map = {
+	.map = {
+		.name = "ICH2 rom",
+		.phys = NO_XIP,
+		.size = 0,
+		.buswidth = 1,
+		.read8 = ich2rom_read8,
+		.read16 = ich2rom_read16,
+		.read32 = ich2rom_read32,
+		.copy_from = ich2rom_copy_from,
+		.write8 = ich2rom_write8,
+		.write16 = ich2rom_write16,
+		.write32 = ich2rom_write32,
+		.copy_to = ich2rom_copy_to,
+		/* Firmware hubs only use vpp when being programmed
+		 * in a factory setting.  So in place programming
+		 * needs to use a different method.
+		 */
+	},
+	.mtd = 0,
+	.window_addr = 0,
+};
+
+enum fwh_lock_state {
+	FWH_DENY_WRITE = 1,
+	FWH_IMMUTABLE  = 2,
+	FWH_DENY_READ  = 4,
+};
+
+static int ich2rom_set_lock_state(struct mtd_info *mtd, loff_t ofs, size_t len,
+	enum fwh_lock_state state)
+{
+	struct map_info *map = mtd->priv;
+	unsigned long start = ofs;
+	unsigned long end = start + len -1;
+
+	/* FIXME do I need to guard against concurrency here? */
+	/* round down to 64K boundaries */
+	start = start & ~0xFFFF;
+	end = end & ~0xFFFF;
+	while (start <= end) {
+		unsigned long ctrl_addr;
+		ctrl_addr = addr(map, start) - 0x400000 + 2;
+		writeb(state, ctrl_addr);
+		start = start + 0x10000;
+	}
+	return 0;
+}
+
+static int ich2rom_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	return ich2rom_set_lock_state(mtd, ofs, len, FWH_DENY_WRITE);
+}
+
+static int ich2rom_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	return ich2rom_set_lock_state(mtd, ofs, len, 0);
+}
+
+static int __devinit ich2rom_init_one (struct pci_dev *pdev,
+	const struct pci_device_id *ent)
+{
+	u16 word;
+	struct ich2rom_map_info *info = &ich2rom_map;
+	unsigned long map_size;
+
+	/* For now I just handle the ich2 and I assume there
+	 * are not a lot of resources up at the top of the address
+	 * space.  It is possible to handle other devices in the
+	 * top 16MB but it is very painful.  Also since
+	 * you can only really attach a FWH to an ICH2 there
+	 * a number of simplifications you can make.
+	 *
+	 * Also you can page firmware hubs if an 8MB window isn't enough 
+	 * but don't currently handle that case either.
+	 */
+
+#if RESERVE_MEM_REGION
+	/* Some boards have this reserved and I haven't found a good work
+	 * around to say I know what I'm doing!
+	 */
+	if (!request_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE, "ich2rom")) {
+		printk(KERN_ERR "ich2rom: cannot reserve rom window\n");
+		goto err_out_none;
+	}
+#endif /* RESERVE_MEM_REGION */
+	
+	/* Enable writes through the rom window */
+	pci_read_config_word(pdev, BIOS_CNTL, &word);
+	if (!(word & 1)  && (word & (1<<1))) {
+		/* The BIOS will generate an error if I enable
+		 * this device, so don't even try.
+		 */
+		printk(KERN_ERR "ich2rom: firmware access control, I can't enable writes\n");
+		goto err_out_none;
+	}
+	pci_write_config_word(pdev, BIOS_CNTL, word | 1);
+
+
+	/* Map the firmware hub into my address space. */
+	/* Does this use to much virtual address space? */
+	info->window_addr = (unsigned long)ioremap(
+		ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE);
+	if (!info->window_addr) {
+		printk(KERN_ERR "Failed to ioremap\n");
+		goto err_out_free_mmio_region;
+	}
+
+	/* For now assume the firmware has setup all relevant firmware
+	 * windows.  We don't have enough information to handle this case
+	 * intelligently.
+	 */
+
+	/* FIXME select the firmware hub and enable a window to it. */
+
+	info->mtd = 0;
+	info->map.map_priv_1 = 	info->window_addr;
+
+	map_size = ICH2_FWH_REGION_SIZE;
+	while(!info->mtd && (map_size > 0)) {
+		info->map.size = map_size;
+		info->mtd = do_map_probe("jedec_probe", &ich2rom_map.map);
+		map_size -= 512*1024;
+	}
+	if (!info->mtd) {
+		goto err_out_iounmap;
+	}
+	/* I know I can only be a firmware hub here so put
+	 * in the special lock and unlock routines.
+	 */
+	info->mtd->lock = ich2rom_lock;
+	info->mtd->unlock = ich2rom_unlock;
+		
+	info->mtd->owner = THIS_MODULE;
+	add_mtd_device(info->mtd);
+	return 0;
+
+err_out_iounmap:
+	iounmap((void *)(info->window_addr));
+err_out_free_mmio_region:
+#if RESERVE_MEM_REGION
+	release_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE);
+#endif
+err_out_none:
+	return -ENODEV;
+}
+
+
+static void __devexit ich2rom_remove_one (struct pci_dev *pdev)
+{
+	struct ich2rom_map_info *info = &ich2rom_map;
+	u16 word;
+
+	del_mtd_device(info->mtd);
+	map_destroy(info->mtd);
+	info->mtd = 0;
+	info->map.map_priv_1 = 0;
+
+	iounmap((void *)(info->window_addr));
+	info->window_addr = 0;
+
+	/* Disable writes through the rom window */
+	pci_read_config_word(pdev, BIOS_CNTL, &word);
+	pci_write_config_word(pdev, BIOS_CNTL, word & ~1);
+
+#if RESERVE_MEM_REGION	
+	release_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE);
+#endif
+}
+
+static struct pci_device_id ich2rom_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 
+	  PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, 
+	  PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, 
+	  PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, ich2rom_pci_tbl);
+
+#if 0
+static struct pci_driver ich2rom_driver = {
+	.name =		"ich2rom",
+	.id_table =	ich2rom_pci_tbl,
+	.probe =	ich2rom_init_one,
+	.remove =	ich2rom_remove_one,
+};
+#endif
+
+static struct pci_dev *mydev;
+int __init init_ich2rom(void)
+{
+	struct pci_dev *pdev;
+	struct pci_device_id *id;
+	pdev = 0;
+	for(id = ich2rom_pci_tbl; id->vendor; id++) {
+		pdev = pci_find_device(id->vendor, id->device, 0);
+		if (pdev) {
+			break;
+		}
+	}
+	if (pdev) {
+		mydev = pdev;
+		return ich2rom_init_one(pdev, &ich2rom_pci_tbl[0]);
+	}
+	return -ENXIO;
+#if 0
+	return pci_module_init(&ich2rom_driver);
+#endif
+}
+
+static void __exit cleanup_ich2rom(void)
+{
+	ich2rom_remove_one(mydev);
+}
+
+module_init(init_ich2rom);
+module_exit(cleanup_ich2rom);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
+MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICH2 southbridge");
diff -Nru a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c
--- a/drivers/mtd/maps/impa7.c	Wed Feb 26 04:45:46 2003
+++ b/drivers/mtd/maps/impa7.c	Wed May 28 08:01:03 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: impa7.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
+ * $Id: impa7.c,v 1.8 2003/05/21 12:45:18 dwmw2 Exp $
  *
  * Handle mapping of the NOR flash on implementa A7 boards
  *
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -37,75 +38,17 @@
 
 static struct mtd_info *impa7_mtd[NUM_FLASHBANKS] = { 0 };
 
-__u8 impa7_read8(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readb(map->map_priv_1 + ofs);
-}
-
-__u16 impa7_read16(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readw(map->map_priv_1 + ofs);
-}
-
-__u32 impa7_read32(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readl(map->map_priv_1 + ofs);
-}
-
-void impa7_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, map->map_priv_1 + from, len);
-}
-
-void impa7_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	__raw_writeb(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void impa7_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	__raw_writew(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void impa7_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	__raw_writel(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void impa7_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy_toio(map->map_priv_1 + to, from, len);
-}
 
 static struct map_info impa7_map[NUM_FLASHBANKS] = {
 	{
-		.name		= "impA7 NOR Flash Bank #0",
-		.size		= WINDOW_SIZE0,
-		.buswidth	= BUSWIDTH,
-		.read8		= impa7_read8,
-		.read16		= impa7_read16,
-		.read32		= impa7_read32,
-		.copy_from	= impa7_copy_from,
-		.write8		= impa7_write8,
-		.write16	= impa7_write16,
-		.write32	= impa7_write32,
-		.copy_to	= impa7_copy_to
+		.name = "impA7 NOR Flash Bank #0",
+		.size = WINDOW_SIZE0,
+		.buswidth = BUSWIDTH,
 	},
 	{
-		.name		= "impA7 NOR Flash Bank #1",
-		.size		= WINDOW_SIZE1,
-		.buswidth	= BUSWIDTH,
-		.read8		= impa7_read8,
-		.read16		= impa7_read16,
-		.read32		= impa7_read32,
-		.copy_from	= impa7_copy_from,
-		.write8		= impa7_write8,
-		.write16	= impa7_write16,
-		.write32	= impa7_write32,
-		.copy_to = impa7_copy_to
+		.name = "impA7 NOR Flash Bank #1",
+		.size = WINDOW_SIZE1,
+		.buswidth = BUSWIDTH,
 	},
 };
 
@@ -114,26 +57,22 @@
 /*
  * MTD partitioning stuff 
  */
-static struct mtd_partition static_partitions[] = {
+static struct mtd_partition static_partitions[] =
+{
 	{
-		.name	= "FileSystem",
-		.size	= 0x800000,
-		.offset	= 0x00000000
+		.name = "FileSystem",
+		.size = 0x800000,
+		.offset = 0x00000000
 	},
 };
 
 #define NB_OF(x) (sizeof (x) / sizeof (x[0]))
 
-#ifdef CONFIG_MTD_CMDLINE_PARTS
-int parse_cmdline_partitions(struct mtd_info *master, 
-			     struct mtd_partition **pparts,
-			     const char *mtd_id);
-#endif
-
 #endif
 
 static int                   mtd_parts_nb = 0;
 static struct mtd_partition *mtd_parts    = 0;
+static const char *probes[] = { "cmdlinepart", NULL };
 
 int __init init_impa7(void)
 {
@@ -142,8 +81,8 @@
 	const char *part_type = 0;
 	int i;
 	static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = {
-	  { .addr = WINDOW_ADDR0, .size = WINDOW_SIZE0 },
-	  { .addr = WINDOW_ADDR1, .size = WINDOW_SIZE1 },
+	  { WINDOW_ADDR0, WINDOW_SIZE0 },
+	  { WINDOW_ADDR1, WINDOW_SIZE1 },
         };
 	char mtdid[10];
 	int devicesfound = 0;
@@ -152,13 +91,15 @@
 	{
 		printk(KERN_NOTICE MSG_PREFIX "probing 0x%08lx at 0x%08lx\n",
 		       pt[i].size, pt[i].addr);
-		impa7_map[i].map_priv_1 = (unsigned long)
-		  ioremap(pt[i].addr, pt[i].size);
 
-		if (!impa7_map[i].map_priv_1) {
+		impa7_map[i].phys = pt[i].addr;
+		impa7_map[i].virt = (unsigned long)
+		  ioremap(pt[i].addr, pt[i].size);
+		if (!impa7_map[i].virt) {
 			printk(MSG_PREFIX "failed to ioremap\n");
 			return -EIO;
 		}
+		simple_map_init(&impa7_map[i]);
 
 		impa7_mtd[i] = 0;
 		type = rom_probe_types;
@@ -168,15 +109,14 @@
 
 		if (impa7_mtd[i]) 
 		{
-			impa7_mtd[i]->module = THIS_MODULE;
+			impa7_mtd[i]->owner = THIS_MODULE;
 			add_mtd_device(impa7_mtd[i]);
 			devicesfound++;
 #ifdef CONFIG_MTD_PARTITIONS
-#ifdef CONFIG_MTD_CMDLINE_PARTS
-			sprintf(mtdid, MTDID, i);
-			mtd_parts_nb = parse_cmdline_partitions(impa7_mtd[i], 
-								&mtd_parts, 
-								mtdid);
+			mtd_parts_nb = parse_mtd_partitions(impa7_mtd[i], 
+							    probes,
+							    &mtd_parts, 
+							    0);
 			if (mtd_parts_nb > 0)
 			  part_type = "command line";
 #endif
@@ -202,7 +142,7 @@
 #endif
 		}
 		else 
-		  iounmap((void *)impa7_map[i].map_priv_1);
+		  iounmap((void *)impa7_map[i].virt);
 	}
 	return devicesfound == 0 ? -ENXIO : 0;
 }
@@ -217,10 +157,10 @@
 			del_mtd_device(impa7_mtd[i]);
 			map_destroy(impa7_mtd[i]);
 		}
-		if (impa7_map[i].map_priv_1)
+		if (impa7_map[i].virt)
 		{
-			iounmap((void *)impa7_map[i].map_priv_1);
-			impa7_map[i].map_priv_1 = 0;
+			iounmap((void *)impa7_map[i].virt);
+			impa7_map[i].virt = 0;
 		}
 	}
 }
diff -Nru a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c
--- a/drivers/mtd/maps/integrator-flash.c	Wed Feb 26 04:10:05 2003
+++ b/drivers/mtd/maps/integrator-flash.c	Wed May 28 08:01:03 2003
@@ -21,7 +21,7 @@
    This is access code for flashes using ARM's flash partitioning 
    standards.
 
-   $Id: integrator-flash.c,v 1.7 2001/11/01 20:55:47 rmk Exp $
+   $Id: integrator-flash.c,v 1.12 2003/05/20 20:59:30 dwmw2 Exp $
 
 ======================================================================*/
 
@@ -41,8 +41,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-extern int parse_afs_partitions(struct mtd_info *, struct mtd_partition **);
-
 // board specific stuff - sorry, it should be in arch/arm/mach-*.
 #ifdef CONFIG_ARCH_INTEGRATOR
 
@@ -153,62 +151,17 @@
 }
 #endif
 
-static __u8 armflash_read8(struct map_info *map, unsigned long ofs)
-{
-	return readb(ofs + map->map_priv_2);
-}
-
-static __u16 armflash_read16(struct map_info *map, unsigned long ofs)
-{
-	return readw(ofs + map->map_priv_2);
-}
-
-static __u32 armflash_read32(struct map_info *map, unsigned long ofs)
-{
-	return readl(ofs + map->map_priv_2);
-}
-
-static void armflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy(to, (void *) (from + map->map_priv_2), len);
-}
-
-static void armflash_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	writeb(d, adr + map->map_priv_2);
-}
-
-static void armflash_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	writew(d, adr + map->map_priv_2);
-}
-
-static void armflash_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	writel(d, adr + map->map_priv_2);
-}
-
-static void armflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy((void *) (to + map->map_priv_2), from, len);
-}
 
 static struct map_info armflash_map =
 {
-	.name		= "AFS",
-	.read8		= armflash_read8,
-	.read16		= armflash_read16,
-	.read32		= armflash_read32,
-	.copy_from	= armflash_copy_from,
-	.write8		= armflash_write8,
-	.write16	= armflash_write16,
-	.write32	= armflash_write32,
-	.copy_to	= armflash_copy_to,
-	.set_vpp	= armflash_set_vpp,
+	.name =		"AFS",
+	.set_vpp =	armflash_set_vpp,
+	.phys =		FLASH_BASE,
 };
 
 static struct mtd_info *mtd;
 static struct mtd_partition *parts;
+static const char *probes[] = { "RedBoot", "afs", NULL };
 
 static int __init armflash_cfi_init(void *base, u_int size)
 {
@@ -222,7 +175,9 @@
 	 */
 	armflash_map.size       = size;
 	armflash_map.buswidth   = 4;
-	armflash_map.map_priv_2 = (unsigned long) base;
+	armflash_map.virt = (unsigned long) base;
+
+	simple_map_init(&armflash_map);
 
 	/*
 	 * Also, the CFI layer automatically works out what size
@@ -233,9 +188,9 @@
 	if (!mtd)
 		return -ENXIO;
 
-	mtd->module = THIS_MODULE;
+	mtd->owner = THIS_MODULE;
 
-	ret = parse_afs_partitions(mtd, &parts);
+	ret = parse_mtd_partitions(mtd, probes, &parts, (void *)0);
 	if (ret > 0) {
 		ret = add_mtd_partitions(mtd, parts, ret);
 		if (ret)
@@ -290,7 +245,7 @@
 static void __exit armflash_exit(void)
 {
 	armflash_cfi_exit();
-	iounmap((void *)armflash_map.map_priv_2);
+	iounmap((void *)armflash_map.virt);
 	release_mem_region(FLASH_BASE, FLASH_SIZE);
 	armflash_flash_exit();
 }
diff -Nru a/drivers/mtd/maps/iq80310.c b/drivers/mtd/maps/iq80310.c
--- a/drivers/mtd/maps/iq80310.c	Wed Feb 26 04:47:14 2003
+++ b/drivers/mtd/maps/iq80310.c	Wed May 28 08:01:03 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: iq80310.c,v 1.9 2002/01/01 22:45:02 rmk Exp $
+ * $Id: iq80310.c,v 1.16 2003/05/21 15:15:07 dwmw2 Exp $
  *
  * Mapping for the Intel XScale IQ80310 evaluation board
  *
@@ -14,6 +14,8 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -26,81 +28,32 @@
 
 static struct mtd_info *mymtd;
 
-static __u8 iq80310_read8(struct map_info *map, unsigned long ofs)
-{
-	return *(__u8 *)(map->map_priv_1 + ofs);
-}
-
-static __u16 iq80310_read16(struct map_info *map, unsigned long ofs)
-{
-	return *(__u16 *)(map->map_priv_1 + ofs);
-}
-
-static __u32 iq80310_read32(struct map_info *map, unsigned long ofs)
-{
-	return *(__u32 *)(map->map_priv_1 + ofs);
-}
-
-static void iq80310_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy(to, (void *)(map->map_priv_1 + from), len);
-}
-
-static void iq80310_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	*(__u8 *)(map->map_priv_1 + adr) = d;
-}
-
-static void iq80310_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	*(__u16 *)(map->map_priv_1 + adr) = d;
-}
-
-static void iq80310_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	*(__u32 *)(map->map_priv_1 + adr) = d;
-}
-
-static void iq80310_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy((void *)(map->map_priv_1 + to), from, len);
-}
-
 static struct map_info iq80310_map = {
-	.name		= "IQ80310 flash",
-	.size		= WINDOW_SIZE,
-	.buswidth	= BUSWIDTH,
-	.read8		= iq80310_read8,
-	.read16		= iq80310_read16,
-	.read32		= iq80310_read32,
-	.copy_from	= iq80310_copy_from,
-	.write8		= iq80310_write8,
-	.write16	= iq80310_write16,
-	.write32	= iq80310_write32,
-	.copy_to	= iq80310_copy_to
+	.name = "IQ80310 flash",
+	.size = WINDOW_SIZE,
+	.buswidth = BUSWIDTH,
+	.phys = WINDOW_ADDR
 };
 
 static struct mtd_partition iq80310_partitions[4] = {
 	{
-		.name		= "Firmware",
-		.size		= 0x00080000,
-		.mask_flags	= MTD_WRITEABLE  /* force read-only */
-	},
-	{
-		.name		= "Kernel",
-		.size		= 0x000a0000,
-		.offset		= 0x00080000,
-	},
-	{
-		.name		= "Filesystem",
-		.size		= 0x00600000,
-		.offset		= 0x00120000
-	},
-	{
-		.name		= "RedBoot",
-		.size		= 0x000e0000,
-		.offset		= 0x00720000,
-		.mask_flags	= MTD_WRITEABLE
+		.name =		"Firmware",
+		.size =		0x00080000,
+		.offset =	0,
+		.mask_flags =	MTD_WRITEABLE  /* force read-only */
+	},{
+		.name =		"Kernel",
+		.size =		0x000a0000,
+		.offset =	0x00080000,
+	},{
+		.name =		"Filesystem",
+		.size =		0x00600000,
+		.offset =	0x00120000
+	},{
+		.name =		"RedBoot",
+		.size =		0x000e0000,
+		.offset =	0x00720000,
+		.mask_flags =	MTD_WRITEABLE
 	}
 };
 
@@ -108,38 +61,33 @@
 
 static struct mtd_info *mymtd;
 static struct mtd_partition *parsed_parts;
-
-extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
 
 static int __init init_iq80310(void)
 {
 	struct mtd_partition *parts;
 	int nb_parts = 0;
 	int parsed_nr_parts = 0;
-	char *part_type = "static";
+	int ret;
 
-	iq80310_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-	if (!iq80310_map.map_priv_1) {
+	iq80310_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
+	if (!iq80310_map.virt) {
 		printk("Failed to ioremap\n");
 		return -EIO;
 	}
+	simple_map_init(&iq80310_map);
+
 	mymtd = do_map_probe("cfi_probe", &iq80310_map);
 	if (!mymtd) {
-		iounmap((void *)iq80310_map.map_priv_1);
+		iounmap((void *)iq80310_map.virt);
 		return -ENXIO;
 	}
-	mymtd->module = THIS_MODULE;
+	mymtd->owner = THIS_MODULE;
 
-#ifdef CONFIG_MTD_REDBOOT_PARTS
-	if (parsed_nr_parts == 0) {
-		int ret = parse_redboot_partitions(mymtd, &parsed_parts);
-
-		if (ret > 0) {
-			part_type = "RedBoot";
-			parsed_nr_parts = ret;
-		}
-	}
-#endif
+	ret = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0);
+
+	if (ret > 0)
+		parsed_nr_parts = ret;
 
 	if (parsed_nr_parts > 0) {
 		parts = parsed_parts;
@@ -148,7 +96,6 @@
 		parts = iq80310_partitions;
 		nb_parts = NB_OF(iq80310_partitions);
 	}
-	printk(KERN_NOTICE "Using %s partition definition\n", part_type);
 	add_mtd_partitions(mymtd, parts, nb_parts);
 	return 0;
 }
@@ -161,8 +108,8 @@
 		if (parsed_parts)
 			kfree(parsed_parts);
 	}
-	if (iq80310_map.map_priv_1)
-		iounmap((void *)iq80310_map.map_priv_1);
+	if (iq80310_map.virt)
+		iounmap((void *)iq80310_map.virt);
 }
 
 module_init(init_iq80310);
diff -Nru a/drivers/mtd/maps/iq80321.c b/drivers/mtd/maps/iq80321.c
--- a/drivers/mtd/maps/iq80321.c	Tue Apr 22 07:16:39 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,169 +0,0 @@
-/*
- * $Id: iq80321.c,v 1.1.2.1 2003/03/04 16:14:31 ejc Exp $
- *
- * Mapping for the Intel XScale IQ80321 evaluation board
- *
- * Author:	Rory Bolt <rorybolt@pacbell.net>
- * Copyright:	(C) 2002 Rory Bolt
- *
- * 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/types.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-
-#define WINDOW_ADDR 	0xf0000000
-#define WINDOW_SIZE 	8*1024*1024
-#define BUSWIDTH 	1
-
-static struct mtd_info *mymtd;
-
-static __u8 iq80321_read8(struct map_info *map, unsigned long ofs)
-{
-	return *(__u8 *)(map->map_priv_1 + ofs);
-}
-
-static __u16 iq80321_read16(struct map_info *map, unsigned long ofs)
-{
-	return *(__u16 *)(map->map_priv_1 + ofs);
-}
-
-static __u32 iq80321_read32(struct map_info *map, unsigned long ofs)
-{
-	return *(__u32 *)(map->map_priv_1 + ofs);
-}
-
-static void iq80321_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy(to, (void *)(map->map_priv_1 + from), len);
-}
-
-static void iq80321_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	*(__u8 *)(map->map_priv_1 + adr) = d;
-}
-
-static void iq80321_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	*(__u16 *)(map->map_priv_1 + adr) = d;
-}
-
-static void iq80321_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	*(__u32 *)(map->map_priv_1 + adr) = d;
-}
-
-static void iq80321_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy((void *)(map->map_priv_1 + to), from, len);
-}
-
-static struct map_info iq80321_map = {
-	.name	= "IQ80321 flash",
-	.size	= WINDOW_SIZE,
-	.buswidth	= BUSWIDTH,
-	.read8	= iq80321_read8,
-	.read16	= iq80321_read16,
-	.read32	= iq80321_read32,
-	.copy_from	= iq80321_copy_from,
-	.write8	= iq80321_write8,
-	.write16	= iq80321_write16,
-	.write32	= iq80321_write32,
-	.copy_to	= iq80321_copy_to
-};
-
-static struct mtd_partition iq80321_partitions[4] = {
-	{
-		.name	= "Firmware",
-		.size	= 0x00080000,
-		.offset	= 0,
-		.mask_flags	= MTD_WRITEABLE  /* force read-only */
-	},{
-		.name	= "Kernel",
-		.size	= 0x000a0000,
-		.offset	= 0x00080000,
-	},{
-		.name	= "Filesystem",
-		.size	= 0x00600000,
-		.offset	= 0x00120000
-	},{
-		.name	= "RedBoot",
-		.size	= 0x000e0000,
-		.offset	= 0x00720000,
-		.mask_flags	= MTD_WRITEABLE
-	}
-};
-
-#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-
-static struct mtd_info *mymtd;
-static struct mtd_partition *parsed_parts;
-
-extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
-
-static int __init init_iq80321(void)
-{
-	struct mtd_partition *parts;
-	int nb_parts = 0;
-	int parsed_nr_parts = 0;
-	char *part_type = "Static";
-
-	iq80321_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-	if (!iq80321_map.map_priv_1) {
-		printk("Failed to ioremap\n");
-		return -EIO;
-	}
-	mymtd = do_map_probe("cfi_probe", &iq80321_map);
-	if (!mymtd) {
-		iounmap((void *)iq80321_map.map_priv_1);
-		return -ENXIO;
-	}
-	mymtd->module = THIS_MODULE;
-
-#ifdef CONFIG_MTD_REDBOOT_PARTS
-	if (parsed_nr_parts == 0) {
-		int ret = parse_redboot_partitions(mymtd, &parsed_parts);
-
-		if (ret > 0) {
-			part_type = "RedBoot";
-			parsed_nr_parts = ret;
-		}
-	}
-#endif
-
-	if (parsed_nr_parts > 0) {
-		parts = parsed_parts;
-		nb_parts = parsed_nr_parts;
-	} else {
-		parts = iq80321_partitions;
-		nb_parts = NB_OF(iq80321_partitions);
-	}
-	printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-	add_mtd_partitions(mymtd, parts, nb_parts);
-	return 0;
-}
-
-static void __exit cleanup_iq80321(void)
-{
-	if (mymtd) {
-		del_mtd_partitions(mymtd);
-		map_destroy(mymtd);
-		if (parsed_parts)
-			kfree(parsed_parts);
-	}
-	if (iq80321_map.map_priv_1)
-		iounmap((void *)iq80321_map.map_priv_1);
-}
-
-module_init(init_iq80321);
-module_exit(cleanup_iq80321);
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("MTD map driver for Intel XScale IQ80321 evaluation board");
diff -Nru a/drivers/mtd/maps/l440gx.c b/drivers/mtd/maps/l440gx.c
--- a/drivers/mtd/maps/l440gx.c	Wed Feb 26 04:47:52 2003
+++ b/drivers/mtd/maps/l440gx.c	Wed May 28 08:01:03 2003
@@ -1,142 +1,143 @@
 /*
- * $Id: l440gx.c,v 1.7 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: l440gx.c,v 1.12 2003/05/21 12:45:19 dwmw2 Exp $
  *
  * BIOS Flash chip on Intel 440GX board.
+ *
+ * Bugs this currently does not work under linuxBIOS.
  */
 
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/config.h>
 
+#define PIIXE_IOBASE_RESOURCE	11
 
 #define WINDOW_ADDR 0xfff00000
 #define WINDOW_SIZE 0x00100000
 #define BUSWIDTH 1
 
-#define IOBASE 0xc00
+static u32 iobase;
+#define IOBASE iobase
 #define TRIBUF_PORT (IOBASE+0x37)
 #define VPP_PORT (IOBASE+0x28)
 
 static struct mtd_info *mymtd;
 
-__u8 l440gx_read8(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readb(map->map_priv_1 + ofs);
-}
-
-__u16 l440gx_read16(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readw(map->map_priv_1 + ofs);
-}
-
-__u32 l440gx_read32(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readl(map->map_priv_1 + ofs);
-}
-
-void l440gx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, map->map_priv_1 + from, len);
-}
-
-void l440gx_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	__raw_writeb(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void l440gx_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	__raw_writew(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void l440gx_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	__raw_writel(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void l440gx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy_toio(map->map_priv_1 + to, from, len);
-}
 
+/* Is this really the vpp port? */
 void l440gx_set_vpp(struct map_info *map, int vpp)
 {
 	unsigned long l;
 
 	l = inl(VPP_PORT);
-	l = vpp?(l | 1):(l & ~1);
+	if (vpp) {
+		l |= 1;
+	} else {
+		l &= ~1;
+	}
 	outl(l, VPP_PORT);
 }
 
 struct map_info l440gx_map = {
-	.name		= "L440GX BIOS",
-	.size		= WINDOW_SIZE,
-	.buswidth	= BUSWIDTH,
-	.read8		= l440gx_read8,
-	.read16		= l440gx_read16,
-	.read32		= l440gx_read32,
-	.copy_from	= l440gx_copy_from,
-	.write8		= l440gx_write8,
-	.write16	= l440gx_write16,
-	.write32	= l440gx_write32,
-	.copy_to	= l440gx_copy_to,
-	.set_vpp	= l440gx_set_vpp
+	.name = "L440GX BIOS",
+	.size = WINDOW_SIZE,
+	.buswidth = BUSWIDTH,
+	.phys = WINDOW_ADDR,
+#if 0
+	/* FIXME verify that this is the 
+	 * appripriate code for vpp enable/disable
+	 */
+	.set_vpp = l440gx_set_vpp
+#endif
 };
 
 static int __init init_l440gx(void)
 {
-	struct pci_dev *dev;
-	unsigned char b;
-	__u16 w;
+	struct pci_dev *dev, *pm_dev;
+	struct resource *pm_iobase;
+	__u16 word;
+
+	dev = pci_find_device(PCI_VENDOR_ID_INTEL, 
+		PCI_DEVICE_ID_INTEL_82371AB_0, NULL);
 
-	dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
-			      NULL);
+	pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL, 
+		PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
 
-	if (!dev) {
+	if (!dev || !pm_dev) {
 		printk(KERN_NOTICE "L440GX flash mapping: failed to find PIIX4 ISA bridge, cannot continue\n");
 		return -ENODEV;
 	}
 
+	l440gx_map.virt = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
 
-	l440gx_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-
-	if (!l440gx_map.map_priv_1) {
-		printk("Failed to ioremap L440GX flash region\n");
+	if (!l440gx_map.virt) {
+		printk(KERN_WARNING "Failed to ioremap L440GX flash region\n");
 		return -ENOMEM;
 	}
+	simple_map_init(&l440gx_map);
+	printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.virt);
+
+	/* Setup the pm iobase resource 
+	 * This code should move into some kind of generic bridge
+	 * driver but for the moment I'm content with getting the
+	 * allocation correct. 
+	 */
+	pm_iobase = &pm_dev->resource[PIIXE_IOBASE_RESOURCE];
+	if (!(pm_iobase->flags & IORESOURCE_IO)) {
+		pm_iobase->name = "pm iobase";
+		pm_iobase->start = 0;
+		pm_iobase->end = 63;
+		pm_iobase->flags = IORESOURCE_IO;
+
+		/* Put the current value in the resource */
+		pci_read_config_dword(pm_dev, 0x40, &iobase);
+		iobase &= ~1;
+		pm_iobase->start += iobase & ~1;
+		pm_iobase->end += iobase & ~1;
+
+		/* Allocate the resource region */
+		if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) {
+			printk(KERN_WARNING "Could not allocate pm iobase resource\n");
+			iounmap((void *)l440gx_map.virt);
+			return -ENXIO;
+		}
+	}
+	/* Set the iobase */
+	iobase = pm_iobase->start;
+	pci_write_config_dword(pm_dev, 0x40, iobase | 1);
+	
 
 	/* Set XBCS# */
-	pci_read_config_word(dev, 0x4e, &w);
-	w |= 0x4;
-        pci_write_config_word(dev, 0x4e, w);
+	pci_read_config_word(dev, 0x4e, &word);
+	word |= 0x4;
+        pci_write_config_word(dev, 0x4e, word);
+
+	/* Supply write voltage to the chip */
+	l440gx_set_vpp(&l440gx_map, 1);
 
 	/* Enable the gate on the WE line */
-	b = inb(TRIBUF_PORT);
-	b |= 1;
-	outb(b, TRIBUF_PORT);
+	outb(inb(TRIBUF_PORT) & ~1, TRIBUF_PORT);
 	
        	printk(KERN_NOTICE "Enabled WE line to L440GX BIOS flash chip.\n");
 
-	mymtd = do_map_probe("jedec", &l440gx_map);
+	mymtd = do_map_probe("jedec_probe", &l440gx_map);
 	if (!mymtd) {
 		printk(KERN_NOTICE "JEDEC probe on BIOS chip failed. Using ROM\n");
 		mymtd = do_map_probe("map_rom", &l440gx_map);
 	}
 	if (mymtd) {
-		mymtd->module = THIS_MODULE;
+		mymtd->owner = THIS_MODULE;
 
 		add_mtd_device(mymtd);
 		return 0;
 	}
 
-	iounmap((void *)l440gx_map.map_priv_1);
+	iounmap((void *)l440gx_map.virt);
 	return -ENXIO;
 }
 
@@ -145,7 +146,7 @@
 	del_mtd_device(mymtd);
 	map_destroy(mymtd);
 	
-	iounmap((void *)l440gx_map.map_priv_1);
+	iounmap((void *)l440gx_map.virt);
 }
 
 module_init(init_l440gx);
diff -Nru a/drivers/mtd/maps/lasat.c b/drivers/mtd/maps/lasat.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/lasat.c	Wed May 28 08:01:17 2003
@@ -0,0 +1,94 @@
+/*
+ * Flash device on lasat 100 and 200 boards
+ *
+ * Presumably (C) 2002 Brian Murphy <brian@murphy.dk> or whoever he
+ * works for.
+ *
+ * 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.
+ *
+ * $Id: lasat.c,v 1.5 2003/05/21 12:45:19 dwmw2 Exp $
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/config.h>
+#include <asm/lasat/lasat.h>
+#include <asm/lasat/lasat_mtd.h>
+
+static struct mtd_info *mymtd;
+
+static struct map_info sp_map = {
+	.name = "SP flash",
+	.buswidth = 4,
+};
+
+static struct mtd_partition partition_info[LASAT_MTD_LAST];
+static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Filesystem", "Config"};
+
+static int __init init_sp(void)
+{
+	int i;
+	/* this does not play well with the old flash code which 
+	 * protects and uprotects the flash when necessary */
+	/* FIXME: Implement set_vpp() */
+       	printk(KERN_NOTICE "Unprotecting flash\n");
+	*lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit;
+
+	sp_map.virt = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER);
+	sp_map.phys = virt_to_phys(sp_map.virt);
+	sp_map.size = lasat_board_info.li_flash_size;
+
+	simple_map_init(&sp_map);
+
+       	printk(KERN_NOTICE "sp flash device: %lx at %lx\n", 
+			sp_map.size, sp_map.phys);
+
+	for (i=0; i < LASAT_MTD_LAST; i++)
+		partition_info[i].name = lasat_mtd_partnames[i];
+
+	mymtd = do_map_probe("cfi_probe", &sp_map);
+	if (mymtd) {
+		u32 size, offset = 0;
+
+		mymtd->owner = THIS_MODULE;
+
+		for (i=0; i < LASAT_MTD_LAST; i++) {
+			size = lasat_flash_partition_size(i);
+			partition_info[i].size = size;
+			partition_info[i].offset = offset;
+			offset += size;
+		}
+
+		add_mtd_partitions( mymtd, partition_info, LASAT_MTD_LAST );
+		return 0;
+	}
+
+	return -ENXIO;
+}
+
+static void __exit cleanup_sp(void)
+{
+	if (mymtd) {
+		del_mtd_partitions(mymtd);
+		map_destroy(mymtd);
+	}
+	if (sp_map.virt) {
+		sp_map.virt = 0;
+	}
+}
+
+module_init(init_sp);
+module_exit(cleanup_sp);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Brian Murphy <brian@murphy.dk>");
+MODULE_DESCRIPTION("Lasat Safepipe/Masquerade MTD map driver");
diff -Nru a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/lubbock-flash.c	Wed May 28 08:01:18 2003
@@ -0,0 +1,153 @@
+/*
+ * $Id: lubbock-flash.c,v 1.8 2003/05/21 12:45:19 dwmw2 Exp $
+ *
+ * Map driver for the Lubbock developer platform.
+ *
+ * Author:	Nicolas Pitre
+ * Copyright:	(C) 2001 MontaVista Software Inc.
+ * 
+ * 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/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <asm/hardware.h>
+
+
+#define ROM_ADDR	0x00000000
+#define FLASH_ADDR	0x04000000
+
+#define WINDOW_SIZE 	64*1024*1024
+
+static struct map_info lubbock_maps[2] = { {
+	.size =		WINDOW_SIZE,
+	.phys =		0x00000000,
+}, {
+	.size =		WINDOW_SIZE,
+	.phys =		0x04000000,
+} };
+
+static struct mtd_partition lubbock_partitions[] = {
+	{
+		.name =		"Bootloader",
+		.size =		0x00040000,
+		.offset =	0,
+		.mask_flags =	MTD_WRITEABLE  /* force read-only */
+	},{
+		.name =		"Kernel",
+		.size =		0x00100000,
+		.offset =	0x00040000,
+	},{
+		.name =		"Filesystem",
+		.size =		MTDPART_SIZ_FULL,
+		.offset =	0x00140000
+	}
+};
+
+#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
+
+static struct mtd_info *mymtds[2];
+static struct mtd_partition *parsed_parts[2];
+static int nr_parsed_parts[2];
+
+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
+
+static int __init init_lubbock(void)
+{
+	int flashboot = (CONF_SWITCHES & 1);
+	int ret = 0, i;
+
+	lubbock_maps[0].buswidth = lubbock_maps[1].buswidth = 
+		(BOOT_DEF & 1) ? 2 : 4;
+
+	/* Compensate for the nROMBT switch which swaps the flash banks */
+	printk(KERN_NOTICE "Lubbock configured to boot from %s (bank %d)\n",
+	       flashboot?"Flash":"ROM", flashboot);
+
+	lubbock_maps[flashboot^1].name = "Lubbock Application Flash";
+	lubbock_maps[flashboot].name = "Lubbock Boot ROM";
+
+	for (i = 0; i < 2; i++) {
+		lubbock_maps[i].virt = (unsigned long)__ioremap(lubbock_maps[i].phys, WINDOW_SIZE, 0);
+		if (!lubbock_maps[i].virt) {
+			printk(KERN_WARNING "Failed to ioremap %s\n", lubbock_maps[i].name);
+			if (!ret)
+				ret = -ENOMEM;
+			continue;
+		}
+		simple_map_init(&lubbock_maps[i]);
+
+		printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit buswidth)\n",
+		       lubbock_maps[i].name, lubbock_maps[i].phys, 
+		       lubbock_maps[i].buswidth * 8);
+
+		mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]);
+		
+		if (!mymtds[i]) {
+			iounmap((void *)lubbock_maps[i].virt);
+			if (!ret)
+				ret = -EIO;
+			continue;
+		}
+		mymtds[i]->owner = THIS_MODULE;
+
+		int ret = parse_mtd_partitions(mymtds[i], probes,
+					       &parsed_parts[i], 0);
+
+		if (ret > 0)
+			nr_parsed_parts[i] = ret;
+	}
+
+	if (!mymtds[0] && !mymtds[1])
+		return ret;
+	
+	for (i = 0; i < 2; i++) {
+		if (!mymtds[i]) {
+			printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name);
+		} else if (nr_parsed_parts[i]) {
+			add_mtd_partitions(mymtds[i], parsed_parts[i], nr_parsed_parts[i]);
+		} else if (!i) {
+			printk("Using static partitions on %s\n", lubbock_maps[i].name);
+			add_mtd_partitions(mymtds[i], lubbock_partitions, NB_OF(lubbock_partitions));
+		} else {
+			printk("Registering %s as whole device\n", lubbock_maps[i].name);
+			add_mtd_device(mymtds[i]);
+		}
+	}
+	return 0;
+}
+
+static void __exit cleanup_lubbock(void)
+{
+	int i;
+	for (i = 0; i < 2; i++) {
+		if (!mymtds[i])
+			continue;
+
+		if (nr_parsed_parts[i] || !i)
+			del_mtd_partitions(mymtds[i]);
+		else
+			del_mtd_device(mymtds[i]);			
+
+		map_destroy(mymtds[i]);
+		iounmap((void *)lubbock_maps[i].virt);
+
+		if (parsed_parts[i])
+			kfree(parsed_parts[i]);
+	}
+}
+
+module_init(init_lubbock);
+module_exit(cleanup_lubbock);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
+MODULE_DESCRIPTION("MTD map driver for Intel Lubbock");
diff -Nru a/drivers/mtd/maps/map_funcs.c b/drivers/mtd/maps/map_funcs.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/map_funcs.c	Wed May 28 08:01:18 2003
@@ -0,0 +1,94 @@
+/*
+ * $Id: map_funcs.c,v 1.2 2003/05/21 15:15:07 dwmw2 Exp $
+ *
+ * Out-of-line map I/O functions for simple maps when CONFIG_COMPLEX_MAPPINGS
+ * is enabled.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/io.h>
+
+#include <linux/mtd/map.h>
+
+static u8 simple_map_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->virt + ofs);
+}
+
+static u16 simple_map_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->virt + ofs);
+}
+
+static u32 simple_map_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->virt + ofs);
+}
+
+static u64 simple_map_read64(struct map_info *map, unsigned long ofs)
+{
+#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
+	BUG();
+	return 0;
+#else
+	return __raw_readll(map->virt + ofs);
+#endif
+}
+
+static void simple_map_write8(struct map_info *map, u8 datum, unsigned long ofs)
+{
+	__raw_writeb(datum, map->virt + ofs);
+	mb();
+}
+
+static void simple_map_write16(struct map_info *map, u16 datum, unsigned long ofs)
+{
+	__raw_writew(datum, map->virt + ofs);
+	mb();
+}
+
+static void simple_map_write32(struct map_info *map, u32 datum, unsigned long ofs)
+{
+	__raw_writel(datum, map->virt + ofs);
+	mb();
+}
+
+static void simple_map_write64(struct map_info *map, u64 datum, unsigned long ofs)
+{
+#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
+	BUG();
+#else
+	__raw_writell(datum, map->virt + ofs);
+	mb();
+#endif /* CFI_B8 */
+}
+
+static void simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->virt + from, len);
+}
+
+static void simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->virt + to, from, len);
+}
+
+void simple_map_init(struct map_info *map)
+{
+	map->read8 = simple_map_read8;
+	map->read16 = simple_map_read16;
+	map->read32 = simple_map_read32;
+	map->read64 = simple_map_read64;
+	map->write8 = simple_map_write8;
+	map->write16 = simple_map_write16;
+	map->write32 = simple_map_write32;
+	map->write64 = simple_map_write64;
+	map->copy_from = simple_map_copy_from;
+	map->copy_to = simple_map_copy_to;
+}
+
+EXPORT_SYMBOL(simple_map_init);
diff -Nru a/drivers/mtd/maps/mbx860.c b/drivers/mtd/maps/mbx860.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/mbx860.c	Wed May 28 08:01:19 2003
@@ -0,0 +1,100 @@
+/*
+ * $Id: mbx860.c,v 1.5 2003/05/21 12:45:19 dwmw2 Exp $
+ *
+ * Handle mapping of the flash on MBX860 boards
+ *
+ * Author:	Anton Todorov
+ * Copyright:	(C) 2001 Emness Technology
+ * 
+ * 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/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+
+#define WINDOW_ADDR 0xfe000000
+#define WINDOW_SIZE 0x00200000
+
+/* Flash / Partition sizing */
+#define MAX_SIZE_KiB              8192
+#define BOOT_PARTITION_SIZE_KiB    512
+#define KERNEL_PARTITION_SIZE_KiB 5632
+#define APP_PARTITION_SIZE_KiB    2048
+
+#define NUM_PARTITIONS 3
+
+/* partition_info gives details on the logical partitions that the split the
+ * single flash device into. If the size if zero we use up to the end of the
+ * device. */
+static struct mtd_partition partition_info[]={
+	{ .name = "MBX flash BOOT partition",
+	.offset = 0,
+	.size =   BOOT_PARTITION_SIZE_KiB*1024 },
+	{ .name = "MBX flash DATA partition",
+	.offset = BOOT_PARTITION_SIZE_KiB*1024,
+	.size = (KERNEL_PARTITION_SIZE_KiB)*1024 },
+	{ .name = "MBX flash APPLICATION partition",
+	.offset = (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 }
+};
+				   
+
+static struct mtd_info *mymtd;
+
+struct map_info mbx_map = {
+	.name = "MBX flash",
+	.size = WINDOW_SIZE,
+	.phys = WINDOW_ADDR,
+	.buswidth = 4,
+};
+
+int __init init_mbx(void)
+{
+	printk(KERN_NOTICE "Motorola MBX flash device: 0x%x at 0x%x\n", WINDOW_SIZE*4, WINDOW_ADDR);
+	mbx_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
+
+	if (!mbx_map.virt) {
+		printk("Failed to ioremap\n");
+		return -EIO;
+	}
+	simple_map_init(&mbx_map);
+
+	mymtd = do_map_probe("jedec_probe", &mbx_map);
+	if (mymtd) {
+		mymtd->owner = THIS_MODULE;
+		add_mtd_device(mymtd);
+                add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
+		return 0;
+	}
+
+	iounmap((void *)mbx_map.virt);
+	return -ENXIO;
+}
+
+static void __exit cleanup_mbx(void)
+{
+	if (mymtd) {
+		del_mtd_device(mymtd);
+		map_destroy(mymtd);
+	}
+	if (mbx_map.virt) {
+		iounmap((void *)mbx_map.virt);
+		mbx_map.virt = 0;
+	}
+}
+
+module_init(init_mbx);
+module_exit(cleanup_mbx);
+
+MODULE_AUTHOR("Anton Todorov <a.todorov@emness.com>");
+MODULE_DESCRIPTION("MTD map driver for Motorola MBX860 board");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c
--- a/drivers/mtd/maps/netsc520.c	Wed Feb 26 04:50:13 2003
+++ b/drivers/mtd/maps/netsc520.c	Wed May 28 08:01:03 2003
@@ -3,7 +3,7 @@
  * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com)
  *	based on sc520cdp.c by Sysgo Real-Time Solutions GmbH
  *
- * $Id: netsc520.c,v 1.5 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: netsc520.c,v 1.9 2003/05/21 12:45:19 dwmw2 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
@@ -27,6 +27,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -50,94 +51,41 @@
 ** recoverable afterwards.
 */
 
-static __u8 netsc520_read8(struct map_info *map, unsigned long ofs)
-{
-	return readb(map->map_priv_1 + ofs);
-}
-
-static __u16 netsc520_read16(struct map_info *map, unsigned long ofs)
-{
-	return readw(map->map_priv_1 + ofs);
-}
-
-static __u32 netsc520_read32(struct map_info *map, unsigned long ofs)
-{
-	return readl(map->map_priv_1 + ofs);
-}
-
-static void netsc520_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
-}
-
-static void netsc520_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	writeb(d, map->map_priv_1 + adr);
-}
-
-static void netsc520_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	writew(d, map->map_priv_1 + adr);
-}
-
-static void netsc520_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	writel(d, map->map_priv_1 + adr);
-}
-
-static void netsc520_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy_toio((void *)(map->map_priv_1 + to), from, len);
-}
-
 /* partition_info gives details on the logical partitions that the split the 
  * single flash device into. If the size if zero we use up to the end of the
  * device. */
-static struct mtd_partition partition_info[] = {
-	{ 
-		.name	= "NetSc520 boot kernel", 
-		.size	= 0xc0000
-	},
-	{ 
-		.name	= "NetSc520 Low BIOS", 
-		.offset	= 0xc0000, 
-		.size	= 0x40000
-	},
-	{ 
-		.name	= "NetSc520 file system", 
-		.offset	= 0x100000, 
-		.size	= 0xe80000
-	},
-	{ 
-		.name	= "NetSc520 High BIOS", 
-		.offset	= 0xf80000, 
-		.size	= 0x80000
-	},
+static struct mtd_partition partition_info[]={
+    { 
+	    .name = "NetSc520 boot kernel", 
+	    .offset = 0, 
+	    .size = 0xc0000
+    },
+    { 
+	    .name = "NetSc520 Low BIOS", 
+	    .offset = 0xc0000, 
+	    .size = 0x40000
+    },
+    { 
+	    .name = "NetSc520 file system", 
+	    .offset = 0x100000, 
+	    .size = 0xe80000
+    },
+    { 
+	    .name = "NetSc520 High BIOS", 
+	    .offset = 0xf80000, 
+	    .size = 0x80000
+    },
 };
 #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
 
-/*
- * If no idea what is going on here.  This is taken from the FlashFX stuff.
- */
-#define ROMCS 1
-
-
 #define WINDOW_SIZE	0x00100000
 #define WINDOW_ADDR	0x00200000
 
 static struct map_info netsc520_map = {
-	.name		= "netsc520 Flash Bank",
-	.size		= WINDOW_SIZE,
-	.buswidth	= 4,
-	.read8		= netsc520_read8,
-	.read16		= netsc520_read16,
-	.read32		= netsc520_read32,
-	.copy_from	= netsc520_copy_from,
-	.write8		= netsc520_write8,
-	.write16	= netsc520_write16,
-	.write32	= netsc520_write32,
-	.copy_to	= netsc520_copy_to,
-	.map_priv_2	= WINDOW_ADDR
+	.name = "netsc520 Flash Bank",
+	.size = WINDOW_SIZE,
+	.buswidth = 4,
+	.phys = WINDOW_ADDR,
 };
 
 #define NUM_FLASH_BANKS	(sizeof(netsc520_map)/sizeof(struct map_info))
@@ -146,13 +94,16 @@
 
 static int __init init_netsc520(void)
 {
-	printk(KERN_NOTICE "NetSc520 flash device: %lx at %lx\n", netsc520_map.size, netsc520_map.map_priv_2);
-	netsc520_map.map_priv_1 = (unsigned long)ioremap_nocache(netsc520_map.map_priv_2, netsc520_map.size);
+	printk(KERN_NOTICE "NetSc520 flash device: 0x%lx at 0x%lx\n", netsc520_map.size, netsc520_map.phys);
+	netsc520_map.virt = (unsigned long)ioremap_nocache(netsc520_map.phys, netsc520_map.size);
 
-	if (!netsc520_map.map_priv_1) {
+	if (!netsc520_map.virt) {
 		printk("Failed to ioremap_nocache\n");
 		return -EIO;
 	}
+
+	simple_map_init(&netsc520_map);
+
 	mymtd = do_map_probe("cfi_probe", &netsc520_map);
 	if(!mymtd)
 		mymtd = do_map_probe("map_ram", &netsc520_map);
@@ -160,11 +111,11 @@
 		mymtd = do_map_probe("map_rom", &netsc520_map);
 
 	if (!mymtd) {
-		iounmap((void *)netsc520_map.map_priv_1);
+		iounmap((void *)netsc520_map.virt);
 		return -ENXIO;
 	}
 		
-	mymtd->module = THIS_MODULE;
+	mymtd->owner = THIS_MODULE;
 	add_mtd_partitions( mymtd, partition_info, NUM_PARTITIONS );
 	return 0;
 }
@@ -175,9 +126,9 @@
 		del_mtd_partitions(mymtd);
 		map_destroy(mymtd);
 	}
-	if (netsc520_map.map_priv_1) {
-		iounmap((void *)netsc520_map.map_priv_1);
-		netsc520_map.map_priv_1 = 0;
+	if (netsc520_map.virt) {
+		iounmap((void *)netsc520_map.virt);
+		netsc520_map.virt = 0;
 	}
 }
 
diff -Nru a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/nettel.c	Wed May 28 08:01:20 2003
@@ -0,0 +1,499 @@
+/****************************************************************************/
+
+/*
+ *      nettel.c -- mappings for NETtel/SecureEdge/SnapGear (x86) boards.
+ *
+ *      (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com)
+ *      (C) Copyright 2001-2002, SnapGear (www.snapgear.com)
+ *
+ *	$Id: nettel.c,v 1.4 2003/05/20 20:59:30 dwmw2 Exp $
+ */
+
+/****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/cfi.h>
+#include <linux/reboot.h>
+#include <asm/io.h>
+
+/****************************************************************************/
+
+#define INTEL_BUSWIDTH		1
+#define AMD_WINDOW_MAXSIZE	0x00200000
+#define AMD_BUSWIDTH	 	1
+
+/*
+ *	PAR masks and shifts, assuming 64K pages.
+ */
+#define SC520_PAR_ADDR_MASK	0x00003fff
+#define SC520_PAR_ADDR_SHIFT	16
+#define SC520_PAR_TO_ADDR(par) \
+	(((par)&SC520_PAR_ADDR_MASK) << SC520_PAR_ADDR_SHIFT)
+
+#define SC520_PAR_SIZE_MASK	0x01ffc000
+#define SC520_PAR_SIZE_SHIFT	2
+#define SC520_PAR_TO_SIZE(par) \
+	((((par)&SC520_PAR_SIZE_MASK) << SC520_PAR_SIZE_SHIFT) + (64*1024))
+
+#define SC520_PAR(cs, addr, size) \
+	((cs) | \
+	((((size)-(64*1024)) >> SC520_PAR_SIZE_SHIFT) & SC520_PAR_SIZE_MASK) | \
+	(((addr) >> SC520_PAR_ADDR_SHIFT) & SC520_PAR_ADDR_MASK))
+
+#define SC520_PAR_BOOTCS	0x8a000000
+#define	SC520_PAR_ROMCS1	0xaa000000
+#define SC520_PAR_ROMCS2	0xca000000	/* Cache disabled, 64K page */
+
+static void *nettel_mmcrp = NULL;
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+static struct mtd_info *intel_mtd;
+#endif
+static struct mtd_info *amd_mtd;
+
+/****************************************************************************/
+
+/****************************************************************************/
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+static struct map_info nettel_intel_map = {
+	.name = "SnapGear Intel",
+	.size = 0,
+	.buswidth = INTEL_BUSWIDTH,
+};
+
+static struct mtd_partition nettel_intel_partitions[] = {
+	{
+		.name = "SnapGear kernel",
+		.offset = 0,
+		.size = 0x000e0000
+	},
+	{
+		.name = "SnapGear filesystem",
+		.offset = 0x00100000,
+	},
+	{
+		.name = "SnapGear config",
+		.offset = 0x000e0000,
+		.size = 0x00020000
+	},
+	{
+		.name = "SnapGear Intel",
+		.offset = 0
+	},
+	{
+		.name = "SnapGear BIOS Config",
+		.offset = 0x007e0000,
+		.size = 0x00020000
+	},
+	{
+		.name = "SnapGear BIOS",
+		.offset = 0x007e0000,
+		.size = 0x00020000
+	},
+};
+#endif
+
+static struct map_info nettel_amd_map = {
+	.name = "SnapGear AMD",
+	.size = AMD_WINDOW_MAXSIZE,
+	.buswidth = AMD_BUSWIDTH,
+};
+
+static struct mtd_partition nettel_amd_partitions[] = {
+	{
+		.name = "SnapGear BIOS config",
+		.offset = 0x000e0000,
+		.size = 0x00010000
+	},
+	{
+		.name = "SnapGear BIOS",
+		.offset = 0x000f0000,
+		.size = 0x00010000
+	},
+	{
+		.name = "SnapGear AMD",
+		.offset = 0
+	},
+	{
+		.name = "SnapGear high BIOS",
+		.offset = 0x001f0000,
+		.size = 0x00010000
+	}
+};
+
+#define NUM_AMD_PARTITIONS \
+	(sizeof(nettel_amd_partitions)/sizeof(nettel_amd_partitions[0]))
+
+/****************************************************************************/
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+
+/*
+ *	Set the Intel flash back to read mode since some old boot
+ *	loaders don't.
+ */
+static int nettel_reboot_notifier(struct notifier_block *nb, unsigned long val, void *v)
+{
+	struct cfi_private *cfi = nettel_intel_map.fldrv_priv;
+	unsigned long b;
+	
+	/* Make sure all FLASH chips are put back into read mode */
+	for (b = 0; (b < nettel_intel_partitions[3].size); b += 0x100000) {
+		cfi_send_gen_cmd(0xff, 0x55, b, &nettel_intel_map, cfi,
+			cfi->device_type, NULL);
+	}
+	return(NOTIFY_OK);
+}
+
+static struct notifier_block nettel_notifier_block = {
+	nettel_reboot_notifier, NULL, 0
+};
+
+/*
+ *	Erase the configuration file system.
+ *	Used to support the software reset button.
+ */
+static void nettel_erasecallback(struct erase_info *done)
+{
+	wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
+	wake_up(wait_q);
+}
+
+static struct erase_info nettel_erase;
+
+int nettel_eraseconfig(void)
+{
+	struct mtd_info *mtd;
+	DECLARE_WAITQUEUE(wait, current);
+	wait_queue_head_t wait_q;
+	int ret;
+
+	init_waitqueue_head(&wait_q);
+	mtd = get_mtd_device(NULL, 2);
+	if (mtd) {
+		nettel_erase.mtd = mtd;
+		nettel_erase.callback = nettel_erasecallback;
+		nettel_erase.callback = 0;
+		nettel_erase.addr = 0;
+		nettel_erase.len = mtd->size;
+		nettel_erase.priv = (u_long) &wait_q;
+		nettel_erase.priv = 0;
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&wait_q, &wait);
+
+		ret = MTD_ERASE(mtd, &nettel_erase);
+		if (ret) {
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&wait_q, &wait);
+			put_mtd_device(mtd);
+			return(ret);
+		}
+
+		schedule();  /* Wait for erase to finish. */
+		remove_wait_queue(&wait_q, &wait);
+		
+		put_mtd_device(mtd);
+	}
+
+	return(0);
+}
+
+#else
+
+int nettel_eraseconfig(void)
+{
+	return(0);
+}
+
+#endif
+
+/****************************************************************************/
+
+int __init nettel_init(void)
+{
+	volatile unsigned long *amdpar;
+	unsigned long amdaddr, maxsize;
+	int num_amd_partitions=0;
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	volatile unsigned long *intel0par, *intel1par;
+	unsigned long orig_bootcspar, orig_romcs1par;
+	unsigned long intel0addr, intel0size;
+	unsigned long intel1addr, intel1size;
+	int intelboot, intel0cs, intel1cs;
+	int num_intel_partitions;
+#endif
+	int rc = 0;
+
+	nettel_mmcrp = (void *) ioremap_nocache(0xfffef000, 4096);
+	if (nettel_mmcrp == NULL) {
+		printk("SNAPGEAR: failed to disable MMCR cache??\n");
+		return(-EIO);
+	}
+
+	/* Set CPU clock to be 33.000MHz */
+	*((unsigned char *) (nettel_mmcrp + 0xc64)) = 0x01;
+
+	amdpar = (volatile unsigned long *) (nettel_mmcrp + 0xc4);
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	intelboot = 0;
+	intel0cs = SC520_PAR_ROMCS1;
+	intel0par = (volatile unsigned long *) (nettel_mmcrp + 0xc0);
+	intel1cs = SC520_PAR_ROMCS2;
+	intel1par = (volatile unsigned long *) (nettel_mmcrp + 0xbc);
+
+	/*
+	 *	Save the CS settings then ensure ROMCS1 and ROMCS2 are off,
+	 *	otherwise they might clash with where we try to map BOOTCS.
+	 */
+	orig_bootcspar = *amdpar;
+	orig_romcs1par = *intel0par;
+	*intel0par = 0;
+	*intel1par = 0;
+#endif
+
+	/*
+	 *	The first thing to do is determine if we have a separate
+	 *	boot FLASH device. Typically this is a small (1 to 2MB)
+	 *	AMD FLASH part. It seems that device size is about the
+	 *	only way to tell if this is the case...
+	 */
+	amdaddr = 0x20000000;
+	maxsize = AMD_WINDOW_MAXSIZE;
+
+	*amdpar = SC520_PAR(SC520_PAR_BOOTCS, amdaddr, maxsize);
+	__asm__ ("wbinvd");
+
+	nettel_amd_map.phys = amdaddr;
+	nettel_amd_map.virt = (unsigned long)
+		ioremap_nocache(amdaddr, maxsize);
+	if (!nettel_amd_map.virt) {
+		printk("SNAPGEAR: failed to ioremap() BOOTCS\n");
+		return(-EIO);
+	}
+	simple_map_init(&nettel_amd_map);
+
+	if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) {
+		printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n",
+			amd_mtd->size>>10);
+
+		amd_mtd->owner = THIS_MODULE;
+
+		/* The high BIOS partition is only present for 2MB units */
+		num_amd_partitions = NUM_AMD_PARTITIONS;
+		if (amd_mtd->size < AMD_WINDOW_MAXSIZE)
+			num_amd_partitions--;
+		/* Don't add the partition until after the primary INTEL's */
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+		/*
+		 *	Map the Intel flash into memory after the AMD
+		 *	It has to start on a multiple of maxsize.
+		 */
+		maxsize = SC520_PAR_TO_SIZE(orig_romcs1par);
+		if (maxsize < (32 * 1024 * 1024))
+			maxsize = (32 * 1024 * 1024);
+		intel0addr = amdaddr + maxsize;
+#endif
+	} else {
+#ifdef CONFIG_MTD_CFI_INTELEXT
+		/* INTEL boot FLASH */
+		intelboot++;
+
+		if (!orig_romcs1par) {
+			intel0cs = SC520_PAR_BOOTCS;
+			intel0par = (volatile unsigned long *)
+				(nettel_mmcrp + 0xc4);
+			intel1cs = SC520_PAR_ROMCS1;
+			intel1par = (volatile unsigned long *)
+				(nettel_mmcrp + 0xc0);
+
+			intel0addr = SC520_PAR_TO_ADDR(orig_bootcspar);
+			maxsize = SC520_PAR_TO_SIZE(orig_bootcspar);
+		} else {
+			/* Kernel base is on ROMCS1, not BOOTCS */
+			intel0cs = SC520_PAR_ROMCS1;
+			intel0par = (volatile unsigned long *)
+				(nettel_mmcrp + 0xc0);
+			intel1cs = SC520_PAR_BOOTCS;
+			intel1par = (volatile unsigned long *)
+				(nettel_mmcrp + 0xc4);
+
+			intel0addr = SC520_PAR_TO_ADDR(orig_romcs1par);
+			maxsize = SC520_PAR_TO_SIZE(orig_romcs1par);
+		}
+
+		/* Destroy useless AMD MTD mapping */
+		amd_mtd = NULL;
+		iounmap((void *) nettel_amd_map.virt);
+		nettel_amd_map.virt = (unsigned long) NULL;
+#else
+		/* Only AMD flash supported */
+		return(-ENXIO);
+#endif
+	}
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	/*
+	 *	We have determined the INTEL FLASH configuration, so lets
+	 *	go ahead and probe for them now.
+	 */
+
+	/* Set PAR to the maximum size */
+	if (maxsize < (32 * 1024 * 1024))
+		maxsize = (32 * 1024 * 1024);
+	*intel0par = SC520_PAR(intel0cs, intel0addr, maxsize);
+
+	/* Turn other PAR off so the first probe doesn't find it */
+	*intel1par = 0;
+
+	/* Probe for the the size of the first Intel flash */
+	nettel_intel_map.size = maxsize;
+	nettel_intel_map.phys = intel0addr;
+	nettel_intel_map.virt = (unsigned long)
+		ioremap_nocache(intel0addr, maxsize);
+	if (!nettel_intel_map.virt) {
+		printk("SNAPGEAR: failed to ioremap() ROMCS1\n");
+		return(-EIO);
+	}
+	simple_map_init(&nettel_intel_map);
+
+	intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
+	if (! intel_mtd) {
+		iounmap((void *) nettel_intel_map.virt);
+		return(-ENXIO);
+	}
+
+	/* Set PAR to the detected size */
+	intel0size = intel_mtd->size;
+	*intel0par = SC520_PAR(intel0cs, intel0addr, intel0size);
+
+	/*
+	 *	Map second Intel FLASH right after first. Set its size to the
+	 *	same maxsize used for the first Intel FLASH.
+	 */
+	intel1addr = intel0addr + intel0size;
+	*intel1par = SC520_PAR(intel1cs, intel1addr, maxsize);
+	__asm__ ("wbinvd");
+
+	maxsize += intel0size;
+
+	/* Delete the old map and probe again to do both chips */
+	map_destroy(intel_mtd);
+	intel_mtd = NULL;
+	iounmap((void *) nettel_intel_map.virt);
+
+	nettel_intel_map.size = maxsize;
+	nettel_intel_map.virt = (unsigned long)
+		ioremap_nocache(intel0addr, maxsize);
+	if (!nettel_intel_map.virt) {
+		printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n");
+		return(-EIO);
+	}
+
+	intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
+	if (! intel_mtd) {
+		iounmap((void *) nettel_intel_map.virt);
+		return(-ENXIO);
+	}
+
+	intel1size = intel_mtd->size - intel0size;
+	if (intel1size > 0) {
+		*intel1par = SC520_PAR(intel1cs, intel1addr, intel1size);
+		__asm__ ("wbinvd");
+	} else {
+		*intel1par = 0;
+	}
+
+	printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %dK\n",
+		(intel_mtd->size >> 10));
+
+	intel_mtd->owner = THIS_MODULE;
+
+#ifndef CONFIG_BLK_DEV_INITRD
+	ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1);
+#endif
+
+	num_intel_partitions = sizeof(nettel_intel_partitions) /
+		sizeof(nettel_intel_partitions[0]);
+
+	if (intelboot) {
+		/*
+		 *	Adjust offset and size of last boot partition.
+		 *	Must allow for BIOS region at end of FLASH.
+		 */
+		nettel_intel_partitions[1].size = (intel0size + intel1size) -
+			(1024*1024 + intel_mtd->erasesize);
+		nettel_intel_partitions[3].size = intel0size + intel1size;
+		nettel_intel_partitions[4].offset = 
+			(intel0size + intel1size) - intel_mtd->erasesize;
+		nettel_intel_partitions[4].size = intel_mtd->erasesize;
+		nettel_intel_partitions[5].offset =
+			nettel_intel_partitions[4].offset;
+		nettel_intel_partitions[5].size =
+			nettel_intel_partitions[4].size;
+	} else {
+		/* No BIOS regions when AMD boot */
+		num_intel_partitions -= 2;
+	}
+	rc = add_mtd_partitions(intel_mtd, nettel_intel_partitions,
+		num_intel_partitions);
+#endif
+
+	if (amd_mtd) {
+		rc = add_mtd_partitions(amd_mtd, nettel_amd_partitions,
+			num_amd_partitions);
+	}
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	register_reboot_notifier(&nettel_notifier_block);
+#endif
+
+	return(rc);
+}
+
+/****************************************************************************/
+
+void __exit nettel_cleanup(void)
+{
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	unregister_reboot_notifier(&nettel_notifier_block);
+#endif
+	if (amd_mtd) {
+		del_mtd_partitions(amd_mtd);
+		map_destroy(amd_mtd);
+	}
+	if (nettel_amd_map.virt) {
+		iounmap((void *)nettel_amd_map.virt);
+		nettel_amd_map.virt = 0;
+	}
+#ifdef CONFIG_MTD_CFI_INTELEXT
+	if (intel_mtd) {
+		del_mtd_partitions(intel_mtd);
+		map_destroy(intel_mtd);
+	}
+	if (nettel_intel_map.virt) {
+		iounmap((void *)nettel_intel_map.virt);
+		nettel_intel_map.virt = 0;
+	}
+#endif
+}
+
+/****************************************************************************/
+
+module_init(nettel_init);
+module_exit(nettel_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
+MODULE_DESCRIPTION("SnapGear/SecureEdge FLASH support");
+
+/****************************************************************************/
diff -Nru a/drivers/mtd/maps/nora.c b/drivers/mtd/maps/nora.c
--- a/drivers/mtd/maps/nora.c	Wed Feb 26 04:53:17 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,203 +0,0 @@
-/*
- * $Id: nora.c,v 1.21 2001/10/02 15:05:14 dwmw2 Exp $
- *
- * This is so simple I love it.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-
-
-#define WINDOW_ADDR 0xd0000000
-#define WINDOW_SIZE 0x04000000
-
-static struct mtd_info *mymtd;
-
-__u8 nora_read8(struct map_info *map, unsigned long ofs)
-{
-  return *(__u8 *)(WINDOW_ADDR + ofs);
-}
-
-__u16 nora_read16(struct map_info *map, unsigned long ofs)
-{
-  return *(__u16 *)(WINDOW_ADDR + ofs);
-}
-
-__u32 nora_read32(struct map_info *map, unsigned long ofs)
-{
-  return *(__u32 *)(WINDOW_ADDR + ofs);
-}
-
-void nora_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-  memcpy(to, (void *)(WINDOW_ADDR + from), len);
-}
-
-void nora_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-  *(__u8 *)(WINDOW_ADDR + adr) = d;
-}
-
-void nora_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-  *(__u16 *)(WINDOW_ADDR + adr) = d;
-}
-
-void nora_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-  *(__u32 *)(WINDOW_ADDR + adr) = d;
-}
-
-void nora_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-  memcpy((void *)(WINDOW_ADDR + to), from, len);
-}
-
-struct map_info nora_map = {
-	.name		= "NORA",
-	.size		= WINDOW_SIZE,
-	.buswidth	= 2,
-	.read8		= nora_read8,
-	.read16		= nora_read16,
-	.read32		= nora_read32,
-	.copy_from	= nora_copy_from,
-	.write8		= nora_write8,
-	.write16	= nora_write16,
-	.write32	= nora_write32,
-	.copy_to	= nora_copy_to
-};
-
-
-static int nora_mtd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-{
-	return mymtd->read(mymtd, from + (unsigned long)mtd->priv, len, retlen, buf);
-}
-
-static int nora_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
-{
-	return mymtd->write(mymtd, to + (unsigned long)mtd->priv, len, retlen, buf);
-}
-
-static int nora_mtd_erase (struct mtd_info *mtd, struct erase_info *instr)
-{
-	instr->addr += (unsigned long)mtd->priv;
-	return mymtd->erase(mymtd, instr);
-}
-
-static void nora_mtd_sync (struct mtd_info *mtd)
-{
-	mymtd->sync(mymtd);
-}
-
-static int nora_mtd_suspend (struct mtd_info *mtd)
-{
-	return mymtd->suspend(mymtd);
-}
-
-static void nora_mtd_resume (struct mtd_info *mtd)
-{
-	mymtd->resume(mymtd);
-}
-
-
-static struct mtd_info nora_mtds[4] = {  /* boot, kernel, ramdisk, fs */
-	{
-		.type		= MTD_NORFLASH,
-		.flags		= MTD_CAP_NORFLASH,
-		.size		= 0x60000,
-		.erasesize	= 0x20000,
-		.name		= "NORA boot firmware",
-		.module		= THIS_MODULE,
-		.erase		= nora_mtd_erase,
-		.read		= nora_mtd_read,
-		.write		= nora_mtd_write,
-		.suspend	= nora_mtd_suspend,
-		.resume		= nora_mtd_resume,
-		.sync		= nora_mtd_sync,
-	},
-	{
-		.type		= MTD_NORFLASH,
-		.flags		= MTD_CAP_NORFLASH,
-		.size		= 0x0a0000,
-		.erasesize	= 0x20000,
-		.name		= "NORA kernel",
-		.module		= THIS_MODULE,
-		.erase		= nora_mtd_erase,
-		.read		= nora_mtd_read,
-		.write		= nora_mtd_write,
-		.suspend	= nora_mtd_suspend,
-		.resume		= nora_mtd_resume,
-		.sync		= nora_mtd_sync,
-		.priv		= (void *)0x60000
-	},
-	{
-		.type		= MTD_NORFLASH,
-		.flags		= MTD_CAP_NORFLASH,
-		.size		= 0x900000,
-		.erasesize	= 0x20000,
-		.name		= "NORA root filesystem",
-		.module		= THIS_MODULE,
-		.erase		= nora_mtd_erase,
-		.read		= nora_mtd_read,
-		.write		= nora_mtd_write,
-		.suspend	= nora_mtd_suspend,
-		.resume		= nora_mtd_resume,
-		.sync		= nora_mtd_sync,
-		.priv		= (void *)0x100000
-	},
-	{
-		.type		= MTD_NORFLASH,
-		.flags		= MTD_CAP_NORFLASH,
-		.size		= 0x1600000,
-		.erasesize	= 0x20000,
-		.name		= "NORA second filesystem",
-		.module		= THIS_MODULE,
-		.erase		= nora_mtd_erase,
-		.read		= nora_mtd_read,
-		.write		= nora_mtd_write,
-		.suspend	= nora_mtd_suspend,
-		.resume		= nora_mtd_resume,
-		.sync		= nora_mtd_sync,
-		.priv		= (void *)0xa00000
-	}
-};
-
-int __init init_nora(void)
-{
-       	printk(KERN_NOTICE "nora flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
-
-	mymtd = do_map_probe("cfi_probe", &nora_map);
-	if (mymtd) {
-		mymtd->module = THIS_MODULE;
-		
-		add_mtd_device(&nora_mtds[2]);
-		add_mtd_device(&nora_mtds[0]);
-		add_mtd_device(&nora_mtds[1]);
-		add_mtd_device(&nora_mtds[3]);
-		return 0;
-	}
-
-	return -ENXIO;
-}
-
-static void __exit cleanup_nora(void)
-{
-	if (mymtd) {
-		del_mtd_device(&nora_mtds[3]);
-		del_mtd_device(&nora_mtds[1]);
-		del_mtd_device(&nora_mtds[0]);
-		del_mtd_device(&nora_mtds[2]);
-		map_destroy(mymtd);
-	}
-}
-
-module_init(init_nora);
-module_exit(cleanup_nora);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>");
-MODULE_DESCRIPTION("MTD map driver for Nora board");
diff -Nru a/drivers/mtd/maps/ocelot.c b/drivers/mtd/maps/ocelot.c
--- a/drivers/mtd/maps/ocelot.c	Wed Feb 26 04:54:00 2003
+++ b/drivers/mtd/maps/ocelot.c	Wed May 28 08:01:04 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: ocelot.c,v 1.6 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: ocelot.c,v 1.12 2003/05/21 12:45:19 dwmw2 Exp $
  *
  * Flash on Momenco Ocelot
  */
@@ -7,6 +7,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -20,47 +21,23 @@
 #define NVRAM_WINDOW_SIZE 0x00007FF0
 #define NVRAM_BUSWIDTH 1
 
-extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
-
 static unsigned int cacheflush = 0;
 
 static struct mtd_info *flash_mtd;
 static struct mtd_info *nvram_mtd;
 
-__u8 ocelot_read8(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readb(map->map_priv_1 + ofs);
-}
-
-void ocelot_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	cacheflush = 1;
-	__raw_writeb(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void ocelot_copy_from_cache(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	if (cacheflush) {
-		dma_cache_inv(map->map_priv_2, map->size);
-		cacheflush = 0;
-	}
-	memcpy_fromio(to, map->map_priv_1 + from, len);
-}
-
-void ocelot_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
 {
-	memcpy_fromio(to, map->map_priv_1 + from, len);
-}
+        struct map_info *map = (struct map_info *)mtd->priv;
+	size_t done = 0;
 
-void ocelot_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
 	/* If we use memcpy, it does word-wide writes. Even though we told the 
 	   GT64120A that it's an 8-bit wide region, word-wide writes don't work.
 	   We end up just writing the first byte of the four to all four bytes.
 	   So we have this loop instead */
+	*retlen = len;
 	while(len) {
-		__raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
+		__raw_writeb(*(unsigned char *) from, map->virt + to);
 		from++;
 		to++;
 		len--;
@@ -70,24 +47,21 @@
 static struct mtd_partition *parsed_parts;
 
 struct map_info ocelot_flash_map = {
-	.name		= "Ocelot boot flash",
-	.size		= FLASH_WINDOW_SIZE,
-	.buswidth	= FLASH_BUSWIDTH,
-	.read8		= ocelot_read8,
-	.copy_from	= ocelot_copy_from_cache,
-	.write8		= ocelot_write8,
+	.name = "Ocelot boot flash",
+	.size = FLASH_WINDOW_SIZE,
+	.buswidth = FLASH_BUSWIDTH,
+	.phys = FLASH_WINDOW_ADDR,
 };
 
 struct map_info ocelot_nvram_map = {
-	.name		= "Ocelot NVRAM",
-	.size		= NVRAM_WINDOW_SIZE,
-	.buswidth	= NVRAM_BUSWIDTH,
-	.read8		= ocelot_read8,
-	.copy_from	= ocelot_copy_from,
-	.write8		= ocelot_write8,
-	.copy_to	= ocelot_copy_to
+	.name = "Ocelot NVRAM",
+	.size = NVRAM_WINDOW_SIZE,
+	.buswidth = NVRAM_BUSWIDTH,
+	.phys = NVRAM_WINDOW_ADDR,
 };
 
+static const char *probes[] = { "RedBoot", NULL };
+
 static int __init init_ocelot_maps(void)
 {
 	void *pld;
@@ -107,12 +81,13 @@
 	iounmap(pld);
 
 	/* Now ioremap the NVRAM space */
-	ocelot_nvram_map.map_priv_1 = (unsigned long)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE);
-	if (!ocelot_nvram_map.map_priv_1) {
+	ocelot_nvram_map.virt = (unsigned long)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE);
+	if (!ocelot_nvram_map.virt) {
 		printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n");
 		return -EIO;
 	}
-	//	ocelot_nvram_map.map_priv_2 = ocelot_nvram_map.map_priv_1;
+
+	simple_map_init(&ocelot_nvram_map);
 
 	/* And do the RAM probe on it to get an MTD device */
 	nvram_mtd = do_map_probe("map_ram", &ocelot_nvram_map);
@@ -120,22 +95,21 @@
 		printk("NVRAM probe failed\n");
 		goto fail_1;
 	}
-	nvram_mtd->module = THIS_MODULE;
+	nvram_mtd->owner = THIS_MODULE;
 	nvram_mtd->erasesize = 16;
+	/* Override the write() method */
+	nvram_mtd->write = ocelot_ram_write;
 
 	/* Now map the flash space */
-	ocelot_flash_map.map_priv_1 = (unsigned long)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE);
-	if (!ocelot_flash_map.map_priv_1) {
+	ocelot_flash_map.virt = (unsigned long)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE);
+	if (!ocelot_flash_map.virt) {
 		printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n");
 		goto fail_2;
 	}
 	/* Now the cached version */
-	ocelot_flash_map.map_priv_2 = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0);
+	ocelot_flash_map.cached = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0);
 
-	if (!ocelot_flash_map.map_priv_2) {
-		/* Doesn't matter if it failed. Just use the uncached version */
-		ocelot_flash_map.map_priv_2 = ocelot_flash_map.map_priv_1;
-	}
+	simple_map_init(&ocelot_flash_map);
 
 	/* Only probe for flash if the write jumper is present */
 	if (brd_status & 0x40) {
@@ -155,10 +129,10 @@
 
 	add_mtd_device(nvram_mtd);
 
-	flash_mtd->module = THIS_MODULE;
-	nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts);
+	flash_mtd->owner = THIS_MODULE;
+	nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0);
 
-	if (nr_parts)
+	if (nr_parts > 0)
 		add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
 	else
 		add_mtd_device(flash_mtd);
@@ -166,14 +140,13 @@
 	return 0;
 	
  fail3:	
-	iounmap((void *)ocelot_flash_map.map_priv_1);
-	if (ocelot_flash_map.map_priv_2 &&
-	    ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1)
-			iounmap((void *)ocelot_flash_map.map_priv_2);
+	iounmap((void *)ocelot_flash_map.virt);
+	if (ocelot_flash_map.cached)
+			iounmap((void *)ocelot_flash_map.cached);
  fail_2:
 	map_destroy(nvram_mtd);
  fail_1:
-	iounmap((void *)ocelot_nvram_map.map_priv_1);
+	iounmap((void *)ocelot_nvram_map.virt);
 
 	return -ENXIO;
 }
@@ -182,16 +155,16 @@
 {
 	del_mtd_device(nvram_mtd);
 	map_destroy(nvram_mtd);
-	iounmap((void *)ocelot_nvram_map.map_priv_1);
+	iounmap((void *)ocelot_nvram_map.virt);
 
 	if (parsed_parts)
 		del_mtd_partitions(flash_mtd);
 	else
 		del_mtd_device(flash_mtd);
 	map_destroy(flash_mtd);
-	iounmap((void *)ocelot_flash_map.map_priv_1);
-	if (ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1)
-		iounmap((void *)ocelot_flash_map.map_priv_2);
+	iounmap((void *)ocelot_flash_map.virt);
+	if (ocelot_flash_map.cached)
+		iounmap((void *)ocelot_flash_map.cached);
 }
 
 module_init(init_ocelot_maps);
diff -Nru a/drivers/mtd/maps/octagon-5066.c b/drivers/mtd/maps/octagon-5066.c
--- a/drivers/mtd/maps/octagon-5066.c	Wed Feb 26 04:55:28 2003
+++ b/drivers/mtd/maps/octagon-5066.c	Wed May 28 08:01:04 2003
@@ -1,4 +1,4 @@
-// $Id: octagon-5066.c,v 1.19 2001/10/02 15:05:14 dwmw2 Exp $
+// $Id: octagon-5066.c,v 1.24 2003/05/21 15:15:07 dwmw2 Exp $
 /* ######################################################################
 
    Octagon 5066 MTD Driver. 
@@ -31,6 +31,7 @@
 #include <asm/io.h>
 
 #include <linux/mtd/map.h>
+#include <linux/mtd/mtd.h>
 
 #define WINDOW_START 0xe8000
 #define WINDOW_LENGTH 0x8000
@@ -151,32 +152,34 @@
 
 static struct map_info oct5066_map[2] = {
 	{
-		.name		= "Octagon 5066 Socket",
-		.size		= 512 * 1024,
-		.buswidth	= 1,
-		.read8		= oct5066_read8,
-		.read16		= oct5066_read16,
-		.read32		= oct5066_read32,
-		.copy_from	= oct5066_copy_from,
-		.write8		= oct5066_write8,
-		.write16	= oct5066_write16,
-		.write32	= oct5066_write32,
-		.copy_to	= oct5066_copy_to,
-		.map_priv_1	= 1<<6
+		.name = "Octagon 5066 Socket",
+		.phys = NO_XIP,
+		.size = 512 * 1024,
+		.buswidth = 1,
+		.read8 = oct5066_read8,
+		.read16 = oct5066_read16,
+		.read32 = oct5066_read32,
+		.copy_from = oct5066_copy_from,
+		.write8 = oct5066_write8,
+		.write16 = oct5066_write16,
+		.write32 = oct5066_write32,
+		.copy_to = oct5066_copy_to,
+		.map_priv_1 = 1<<6
 	},
 	{
-		.name		= "Octagon 5066 Internal Flash",
-		.size		= 2 * 1024 * 1024,
-		.buswidth	= 1,
-		.read8		= oct5066_read8,
-		.read16		= oct5066_read16,
-		.read32		= oct5066_read32,
-		.copy_from	= oct5066_copy_from,
-		.write8		= oct5066_write8,
-		.write16	= oct5066_write16,
-		.write32	= oct5066_write32,
-		.copy_to	= oct5066_copy_to,
-		.map_priv_1	= 2<<6
+		.name = "Octagon 5066 Internal Flash",
+		.phys = NO_XIP,
+		.size = 2 * 1024 * 1024,
+		.buswidth = 1,
+		.read8 = oct5066_read8,
+		.read16 = oct5066_read16,
+		.read32 = oct5066_read32,
+		.copy_from = oct5066_copy_from,
+		.write8 = oct5066_write8,
+		.write16 = oct5066_write16,
+		.write32 = oct5066_write32,
+		.copy_to = oct5066_copy_to,
+		.map_priv_1 = 2<<6
 	}
 };
 
@@ -223,33 +226,32 @@
 		}
 	}
 	iounmap((void *)iomapadr);
-	release_region(PAGE_IO,1);
+	release_region(PAGE_IO, 1);
 }
 
 int __init init_oct5066(void)
 {
 	int i;
-	
+	int ret = 0;
+
 	// Do an autoprobe sequence
-	if (check_region(PAGE_IO,1) != 0)
-		{
-			printk("5066: Page Register in Use\n");
-			return -EAGAIN;
-		}
+	if (!request_region(PAGE_IO,1,"Octagon SSD")) {
+		printk(KERN_NOTICE "5066: Page Register in Use\n");
+		return -EAGAIN;
+	}
 	iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
 	if (!iomapadr) {
-		printk("Failed to ioremap memory region\n");
-		return -EIO;
+		printk(KERN_NOTICE "Failed to ioremap memory region\n");
+		ret = -EIO;
+		goto out_rel;
 	}
-	if (OctProbe() != 0)
-		{
-			printk("5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
-			iounmap((void *)iomapadr);
-			return -EAGAIN;
-		}
-	
-	request_region(PAGE_IO,1,"Octagon SSD");
-	
+	if (OctProbe() != 0) {
+		printk(KERN_NOTICE "5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
+		iounmap((void *)iomapadr);
+		ret = -EAGAIN;
+		goto out_unmap;
+	}
+      	
 	// Print out our little header..
 	printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START,
 	       WINDOW_START+WINDOW_LENGTH);
@@ -263,7 +265,7 @@
 		if (!oct5066_mtd[i])
 			oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]);
 		if (oct5066_mtd[i]) {
-			oct5066_mtd[i]->module = THIS_MODULE;
+			oct5066_mtd[i]->owner = THIS_MODULE;
 			add_mtd_device(oct5066_mtd[i]);
 		}
 	}
@@ -272,8 +274,14 @@
 		cleanup_oct5066();
 		return -ENXIO;
 	}	  
-	
+
 	return 0;
+
+ out_unmap:
+	iounmap((void *)iomapadr);
+ out_rel:
+	release_region(PAGE_IO, 1);
+	return ret;
 }
 
 module_init(init_oct5066);
diff -Nru a/drivers/mtd/maps/pb1xxx-flash.c b/drivers/mtd/maps/pb1xxx-flash.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/pb1xxx-flash.c	Wed May 28 08:01:20 2003
@@ -0,0 +1,196 @@
+/*
+ * Flash memory access on Alchemy Pb1xxx boards
+ * 
+ * (C) 2001 Pete Popov <ppopov@mvista.com>
+ * 
+ * $Id: pb1xxx-flash.c,v 1.8 2003/05/21 12:45:19 dwmw2 Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/au1000.h>
+
+#ifdef 	DEBUG_RW
+#define	DBG(x...)	printk(x)
+#else
+#define	DBG(x...)	
+#endif
+
+#ifdef CONFIG_MIPS_PB1000
+#define WINDOW_ADDR 0x1F800000
+#define WINDOW_SIZE 0x800000
+#endif
+
+
+static struct map_info pb1xxx_map = {
+	.name =	"Pb1xxx flash",
+};
+
+
+#ifdef CONFIG_MIPS_PB1000
+
+static unsigned long flash_size = 0x00800000;
+static unsigned char flash_buswidth = 4;
+static struct mtd_partition pb1xxx_partitions[] = {
+        {
+                .name = "yamon env",
+                .size = 0x00020000,
+                .offset = 0,
+                .mask_flags = MTD_WRITEABLE
+        },{
+                .name = "User FS",
+                .size = 0x003e0000,
+                .offset = 0x20000,
+        },{
+                .name = "boot code",
+                .size = 0x100000,
+                .offset = 0x400000,
+                .mask_flags = MTD_WRITEABLE
+        },{
+                .name = "raw/kernel",
+                .size = 0x300000,
+                .offset = 0x500000
+        }
+};
+
+#elif defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
+
+static unsigned char flash_buswidth = 4;
+#if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
+/* both 32MiB banks will be used. Combine the first 32MiB bank and the
+ * first 28MiB of the second bank together into a single jffs/jffs2
+ * partition.
+ */
+static unsigned long flash_size = 0x04000000;
+#define WINDOW_ADDR 0x1C000000
+#define WINDOW_SIZE 0x4000000
+static struct mtd_partition pb1xxx_partitions[] = {
+        {
+                .name = "User FS",
+                .size =   0x3c00000,
+                .offset = 0x0000000
+        },{
+                .name = "yamon",
+                .size = 0x0100000,
+                .offset = 0x3c00000,
+                .mask_flags = MTD_WRITEABLE
+        },{
+                .name = "raw kernel",
+                .size = 0x02c0000,
+                .offset = 0x3d00000
+        }
+};
+#elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER)
+static unsigned long flash_size = 0x02000000;
+#define WINDOW_ADDR 0x1E000000
+#define WINDOW_SIZE 0x2000000
+static struct mtd_partition pb1xxx_partitions[] = {
+        {
+                .name = "User FS",
+                .size =   0x1c00000,
+                .offset = 0x0000000
+        },{
+                .name = "yamon",
+                .size = 0x0100000,
+                .offset = 0x1c00000,
+                .mask_flags = MTD_WRITEABLE
+        },{
+                .name = "raw kernel",
+                .size = 0x02c0000,
+                .offset = 0x1d00000
+        }
+};
+#elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
+static unsigned long flash_size = 0x02000000;
+#define WINDOW_ADDR 0x1C000000
+#define WINDOW_SIZE 0x2000000
+static struct mtd_partition pb1xxx_partitions[] = {
+        {
+                .name = "User FS",
+                .size =   0x1e00000,
+                .offset = 0x0000000
+        },{
+                .name = "raw kernel",
+                .size = 0x0200000,
+                .offset = 0x1e00000,
+        }
+};
+#else
+#error MTD_PB1500 define combo error /* should never happen */
+#endif
+#else
+#error Unsupported board
+#endif
+
+
+#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
+
+static struct mtd_partition *parsed_parts;
+static struct mtd_info *mymtd;
+
+int __init pb1xxx_mtd_init(void)
+{
+	struct mtd_partition *parts;
+	int nb_parts = 0;
+	char *part_type;
+	
+	/* Default flash buswidth */
+	pb1xxx_map.buswidth = flash_buswidth;
+
+	/*
+	 * Static partition definition selection
+	 */
+	part_type = "static";
+	parts = pb1xxx_partitions;
+	nb_parts = NB_OF(pb1xxx_partitions);
+	pb1xxx_map.size = flash_size;
+
+	/*
+	 * Now let's probe for the actual flash.  Do it here since
+	 * specific machine settings might have been set above.
+	 */
+	printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n", 
+			pb1xxx_map.buswidth*8);
+	pb1xxx_map.phys = WINDOW_ADDR;
+	pb1xxx_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
+
+	simple_map_init(&pb1xxx_map);
+
+	mymtd = do_map_probe("cfi_probe", &pb1xxx_map);
+	if (!mymtd) {
+		iounmap(pb1xxx_map.virt);
+		return -ENXIO;
+	}
+	mymtd->owner = THIS_MODULE;
+
+	add_mtd_partitions(mymtd, parts, nb_parts);
+	return 0;
+}
+
+static void __exit pb1xxx_mtd_cleanup(void)
+{
+	if (mymtd) {
+		del_mtd_partitions(mymtd);
+		map_destroy(mymtd);
+		if (parsed_parts)
+			kfree(parsed_parts);
+	}
+	if (pb1xxx_map.virt)
+		iounmap(pb1xxx_map.virt);
+}
+
+module_init(pb1xxx_mtd_init);
+module_exit(pb1xxx_mtd_cleanup);
+
+MODULE_AUTHOR("Pete Popov");
+MODULE_DESCRIPTION("Pb1xxx CFI map driver");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c
--- a/drivers/mtd/maps/pci.c	Wed Feb 26 05:15:32 2003
+++ b/drivers/mtd/maps/pci.c	Wed May 28 08:01:04 2003
@@ -7,7 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- *  $Id: pci.c,v 1.1 2001/09/27 20:28:45 rmk Exp $
+ *  $Id: pci.c,v 1.5 2003/05/20 20:59:31 dwmw2 Exp $
  * 
  * Generic PCI memory map driver.  We support the following boards:
  *  - Intel IQ80310 ATU.
@@ -98,10 +98,10 @@
 }
 
 static struct mtd_pci_info intel_iq80310_info = {
-	.init		= intel_iq80310_init,
-	.exit		= intel_iq80310_exit,
-	.translate	= intel_iq80310_translate,
-	.map_name	= "cfi_probe",
+	.init =		intel_iq80310_init,
+	.exit =		intel_iq80310_exit,
+	.translate =	intel_iq80310_translate,
+	.map_name =	"cfi_probe",
 };
 
 /*
@@ -181,10 +181,10 @@
 }
 
 static struct mtd_pci_info intel_dc21285_info = {
-	.init		= intel_dc21285_init,
-	.exit		= intel_dc21285_exit,
-	.translate	= intel_dc21285_translate,
-	.map_name	= "jedec_probe",
+	.init =		intel_dc21285_init,
+	.exit =		intel_dc21285_exit,
+	.translate =	intel_dc21285_translate,
+	.map_name =	"jedec_probe",
 };
 
 /*
@@ -193,22 +193,22 @@
 
 static struct pci_device_id mtd_pci_ids[] __devinitdata = {
 	{
-		.vendor		= PCI_VENDOR_ID_INTEL,
-		.device		= 0x530d,
-		.subvendor	= PCI_ANY_ID,
-		.subdevice	= PCI_ANY_ID,
-		.class		= PCI_CLASS_MEMORY_OTHER << 8,
-		.class_mask	= 0xffff00,
-		.driver_data	= (unsigned long)&intel_iq80310_info,
+		.vendor =	PCI_VENDOR_ID_INTEL,
+		.device =	0x530d,
+		.subvendor =	PCI_ANY_ID,
+		.subdevice =	PCI_ANY_ID,
+		.class =	PCI_CLASS_MEMORY_OTHER << 8,
+		.class_mask =	0xffff00,
+		.driver_data =	(unsigned long)&intel_iq80310_info,
 	},
 	{
-		.vendor		= PCI_VENDOR_ID_DEC,
-		.device		= PCI_DEVICE_ID_DEC_21285,
-		.subvendor	= 0,	/* DC21285 defaults to 0 on reset */
-		.subdevice	= 0,	/* DC21285 defaults to 0 on reset */
-		.driver_data	= (unsigned long)&intel_dc21285_info,
+		.vendor =	PCI_VENDOR_ID_DEC,
+		.device =	PCI_DEVICE_ID_DEC_21285,
+		.subvendor =	0,	/* DC21285 defaults to 0 on reset */
+		.subdevice =	0,	/* DC21285 defaults to 0 on reset */
+		.driver_data =	(unsigned long)&intel_dc21285_info,
 	},
-	{ .vendor = 0, }
+	{ 0, }
 };
 
 /*
@@ -273,14 +273,15 @@
 }
 
 static struct map_info mtd_pci_map = {
-	.read8		= mtd_pci_read8,
-	.read16		= mtd_pci_read16,
-	.read32		= mtd_pci_read32,
-	.copy_from	= mtd_pci_copyfrom,
-	.write8		= mtd_pci_write8,
-	.write16	= mtd_pci_write16,
-	.write32	= mtd_pci_write32,
-	.copy_to	= mtd_pci_copyto,
+	.phys =		NO_XIP,
+	.read8 =	mtd_pci_read8,
+	.read16 =	mtd_pci_read16,
+	.read32 =	mtd_pci_read32,
+	.copy_from =	mtd_pci_copyfrom,
+	.write8 =	mtd_pci_write8,
+	.write16 =	mtd_pci_write16,
+	.write32 =	mtd_pci_write32,
+	.copy_to =	mtd_pci_copyto,
 };
 
 static int __devinit
@@ -320,7 +321,7 @@
 	if (!mtd)
 		goto release;
 
-	mtd->module = THIS_MODULE;
+	mtd->owner = THIS_MODULE;
 	add_mtd_device(mtd);
 
 	pci_set_drvdata(dev, mtd);
@@ -357,10 +358,10 @@
 }
 
 static struct pci_driver mtd_pci_driver = {
-	.name		= "MTD PCI",
-	.probe		= mtd_pci_probe,
-	.remove		= mtd_pci_remove,
-	.id_table	= mtd_pci_ids,
+	.name =		"MTD PCI",
+	.probe =	mtd_pci_probe,
+	.remove =	__devexit_p(mtd_pci_remove),
+	.id_table =	mtd_pci_ids,
 };
 
 static int __init mtd_pci_maps_init(void)
diff -Nru a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
--- a/drivers/mtd/maps/pcmciamtd.c	Sat Apr 26 09:16:20 2003
+++ b/drivers/mtd/maps/pcmciamtd.c	Wed May 28 09:48:12 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: pcmciamtd.c,v 1.36 2002/10/14 18:49:12 rmk Exp $
+ * $Id: pcmciamtd.c,v 1.47 2003/05/28 13:36:14 dwmw2 Exp $
  *
  * pcmciamtd.c - MTD driver for PCMCIA flash memory cards
  *
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/timer.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <asm/system.h>
 
@@ -24,6 +25,7 @@
 #include <pcmcia/ds.h>
 
 #include <linux/mtd/map.h>
+#include <linux/mtd/mtd.h>
 
 #ifdef CONFIG_MTD_DEBUG
 static int debug = CONFIG_MTD_DEBUG_VERBOSE;
@@ -47,7 +49,7 @@
 
 
 #define DRIVER_DESC	"PCMCIA Flash memory card driver"
-#define DRIVER_VERSION	"$Revision: 1.36 $"
+#define DRIVER_VERSION	"$Revision: 1.47 $"
 
 /* Size of the PCMCIA address space: 26 bits = 64 MB */
 #define MAX_PCMCIA_ADDR	0x4000000
@@ -519,6 +521,7 @@
 
 	card_settings(dev, link, &new_name);
 
+	dev->pcmcia_map.phys = NO_XIP;
 	dev->pcmcia_map.read8 = pcmcia_read8_remap;
 	dev->pcmcia_map.read16 = pcmcia_read16_remap;
 	dev->pcmcia_map.copy_from = pcmcia_copy_from_remap;
@@ -529,7 +532,7 @@
 		dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp;
 
 	/* Request a memory window for PCMCIA. Some architeures can map windows upto the maximum
-	   that PCMCIA can support (64Mb) - this is ideal and we aim for a window the size of the
+	   that PCMCIA can support (64MiB) - this is ideal and we aim for a window the size of the
 	   whole card - otherwise we try smaller windows until we succeed */
 
 	req.Attributes =  WIN_MEMORY_TYPE_CM | WIN_ENABLE;
@@ -542,7 +545,7 @@
 
 	do {
 		int ret;
-		DEBUG(2, "requesting window with size = %dKB memspeed = %d",
+		DEBUG(2, "requesting window with size = %dKiB memspeed = %d",
 		      req.Size >> 10, req.AccessSpeed);
 		link->win = (window_handle_t)link->handle;
 		ret = CardServices(RequestWindow, &link->win, &req);
@@ -550,7 +553,7 @@
 		if(ret) {
 			req.Size >>= 1;
 		} else {
-			DEBUG(2, "Got window of size %dKB", req.Size >> 10);
+			DEBUG(2, "Got window of size %dKiB", req.Size >> 10);
 			dev->win_size = req.Size;
 			break;
 		}
@@ -563,7 +566,7 @@
 		pcmciamtd_release((u_long)link);
 		return;
 	}
-	DEBUG(1, "Allocated a window of %dKB", dev->win_size >> 10);
+	DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10);
 		
 	/* Get write protect status */
 	CS_CHECK(GetStatus, link->handle, &status);
@@ -636,7 +639,7 @@
 	}
 
 	dev->mtd_info = mtd;
-	mtd->module = THIS_MODULE;
+	mtd->owner = THIS_MODULE;
 	dev->cardsize = mtd->size;
 
 	if(new_name) {
@@ -644,14 +647,14 @@
 		char unit = ' ';
 		/* Since we are using a default name, make it better by adding in the
 		   size */
-		if(mtd->size < 1048576) { /* <1MB in size, show size in K */
+		if(mtd->size < 1048576) { /* <1MiB in size, show size in KiB */
 			size = mtd->size >> 10;
 			unit = 'K'; 
 		} else {
 			size = mtd->size >> 20;
 			unit = 'M';
 		}
-		sprintf(mtd->name, "%d%cB %s", size, unit, "PCMCIA Memory card");
+		sprintf(mtd->name, "%d%ciB %s", size, unit, "PCMCIA Memory card");
 	}
 
 	/* If the memory found is fits completely into the mapped PCMCIA window,
@@ -836,17 +839,18 @@
 	return link;
 }
 
+static struct pcmcia_driver pcmciamtd_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "pcmciamtd",
+	},
+	.attach		= pcmciamtd_attach,
+	.detach		= pcmciamtd_detach,
+};
 
 static int __init init_pcmciamtd(void)
 {
-	servinfo_t serv;
-
 	info(DRIVER_DESC " " DRIVER_VERSION);
-	CardServices(GetCardServicesInfo, &serv);
-	if (serv.Revision != CS_RELEASE_CODE) {
-		err("Card Services release does not match!");
-		return -1;
-	}
 
 	if(buswidth && buswidth != 1 && buswidth != 2) {
 		info("bad buswidth (%d), using default", buswidth);
@@ -860,8 +864,8 @@
 		info("bad mem_type (%d), using default", mem_type);
 		mem_type = 0;
 	}
-	register_pccard_driver(&dev_info, &pcmciamtd_attach, &pcmciamtd_detach);
-	return 0;
+
+	return pcmcia_register_driver(&pcmciamtd_driver);
 }
 
 
@@ -870,7 +874,10 @@
 	struct list_head *temp1, *temp2;
 
 	DEBUG(1, DRIVER_DESC " unloading");
-	unregister_pccard_driver(&dev_info);
+
+	pcmcia_unregister_driver(&pcmciamtd_driver);
+
+	/* XXX: this really needs to move into generic code.. */
 	list_for_each_safe(temp1, temp2, &dev_list) {
 		dev_link_t *link = &list_entry(temp1, struct pcmciamtd_dev, list)->link;
 		if (link && (link->state & DEV_CONFIG)) {
diff -Nru a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
--- a/drivers/mtd/maps/physmap.c	Wed Feb 26 04:57:14 2003
+++ b/drivers/mtd/maps/physmap.c	Thu May 29 03:42:14 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: physmap.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: physmap.c,v 1.29 2003/05/29 09:24:10 dwmw2 Exp $
  *
  * Normal mappings of chips in physical memory
  */
@@ -7,11 +7,13 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/config.h>
-
+#include <linux/mtd/partitions.h>
 
 #define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START
 #define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN
@@ -19,94 +21,118 @@
 
 static struct mtd_info *mymtd;
 
-__u8 physmap_read8(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readb(map->map_priv_1 + ofs);
-}
-
-__u16 physmap_read16(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readw(map->map_priv_1 + ofs);
-}
-
-__u32 physmap_read32(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readl(map->map_priv_1 + ofs);
-}
-
-void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, map->map_priv_1 + from, len);
-}
 
-void physmap_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	__raw_writeb(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	__raw_writew(d, map->map_priv_1 + adr);
-	mb();
-}
+struct map_info physmap_map = {
+	.name = "Physically mapped flash",
+	.size = WINDOW_SIZE,
+	.buswidth = BUSWIDTH,
+	.phys = WINDOW_ADDR,
+};
 
-void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	__raw_writel(d, map->map_priv_1 + adr);
-	mb();
-}
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition *mtd_parts;
+static int                   mtd_parts_nb;
+
+static struct mtd_partition physmap_partitions[] = {
+#if 0
+/* Put your own partition definitions here */
+	{
+		.name =		"bootROM",
+		.size =		0x80000,
+		.offset =	0,
+		.mask_flags =	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		.name =		"zImage",
+		.size =		0x100000,
+		.offset =	MTDPART_OFS_APPEND,
+		.mask_flags =	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		.name =		"ramdisk.gz",
+		.size =		0x300000,
+		.offset =	MTDPART_OFS_APPEND,
+		.mask_flags =	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		.name =		"User FS",
+		.size =		MTDPART_SIZ_FULL,
+		.offset =	MTDPART_OFS_APPEND,
+	}
+#endif
+};
 
-void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy_toio(map->map_priv_1 + to, from, len);
-}
+#define NUM_PARTITIONS	(sizeof(physmap_partitions)/sizeof(struct mtd_partition))
+const char *part_probes[] = {"cmdlinepart", "RedBoot", NULL};
 
-struct map_info physmap_map = {
-	.name		= "Physically mapped flash",
-	.size		= WINDOW_SIZE,
-	.buswidth	= BUSWIDTH,
-	.read8		= physmap_read8,
-	.read16		= physmap_read16,
-	.read32		= physmap_read32,
-	.copy_from	= physmap_copy_from,
-	.write8		= physmap_write8,
-	.write16	= physmap_write16,
-	.write32	= physmap_write32,
-	.copy_to	= physmap_copy_to
-};
+#endif /* CONFIG_MTD_PARTITIONS */
 
 int __init init_physmap(void)
 {
+	static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 };
+	const char **type;
+
        	printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
-	physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
+	physmap_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
 
-	if (!physmap_map.map_priv_1) {
+	if (!physmap_map.virt) {
 		printk("Failed to ioremap\n");
 		return -EIO;
 	}
-	mymtd = do_map_probe("cfi_probe", &physmap_map);
+
+	simple_map_init(&physmap_map);
+
+	mymtd = 0;
+	type = rom_probe_types;
+	for(; !mymtd && *type; type++) {
+		mymtd = do_map_probe(*type, &physmap_map);
+	}
 	if (mymtd) {
-		mymtd->module = THIS_MODULE;
+		mymtd->owner = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+		mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes, 
+						    &mtd_parts, 0);
+
+		if (mtd_parts_nb > 0)
+		{
+			add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb);
+			return 0;
+		}
+
+		if (NUM_PARTITIONS != 0) 
+		{
+			printk(KERN_NOTICE 
+			       "Using physmap partition definition\n");
+			add_mtd_partitions (mymtd, physmap_partitions, NUM_PARTITIONS);
+			return 0;
+		}
 
+#endif
 		add_mtd_device(mymtd);
+
 		return 0;
 	}
 
-	iounmap((void *)physmap_map.map_priv_1);
+	iounmap((void *)physmap_map.virt);
 	return -ENXIO;
 }
 
 static void __exit cleanup_physmap(void)
 {
-	if (mymtd) {
+#ifdef CONFIG_MTD_PARTITIONS
+	if (mtd_parts_nb) {
+		del_mtd_partitions(mymtd);
+		kfree(mtd_parts);
+	} else if (NUM_PARTITIONS) {
+		del_mtd_partitions(mymtd);
+	} else {
 		del_mtd_device(mymtd);
-		map_destroy(mymtd);
-	}
-	if (physmap_map.map_priv_1) {
-		iounmap((void *)physmap_map.map_priv_1);
-		physmap_map.map_priv_1 = 0;
 	}
+#else
+	del_mtd_device(mymtd);
+#endif
+	map_destroy(mymtd);
+
+	iounmap((void *)physmap_map.virt);
+	physmap_map.virt = 0;
 }
 
 module_init(init_physmap);
diff -Nru a/drivers/mtd/maps/pnc2000.c b/drivers/mtd/maps/pnc2000.c
--- a/drivers/mtd/maps/pnc2000.c	Wed Feb 26 04:58:13 2003
+++ b/drivers/mtd/maps/pnc2000.c	Wed May 28 08:01:04 2003
@@ -5,12 +5,13 @@
  *
  * This code is GPL
  *
- * $Id: pnc2000.c,v 1.10 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: pnc2000.c,v 1.14 2003/05/21 12:45:19 dwmw2 Exp $
  */
 
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -24,58 +25,13 @@
  * MAP DRIVER STUFF
  */
 
-__u8 pnc_read8(struct map_info *map, unsigned long ofs)
-{
-  return *(__u8 *)(WINDOW_ADDR + ofs);
-}
-
-__u16 pnc_read16(struct map_info *map, unsigned long ofs)
-{
-  return *(__u16 *)(WINDOW_ADDR + ofs);
-}
-
-__u32 pnc_read32(struct map_info *map, unsigned long ofs)
-{
-  return *(volatile unsigned int *)(WINDOW_ADDR + ofs);
-}
-
-void pnc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-  memcpy(to, (void *)(WINDOW_ADDR + from), len);
-}
-
-void pnc_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-  *(__u8 *)(WINDOW_ADDR + adr) = d;
-}
-
-void pnc_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-  *(__u16 *)(WINDOW_ADDR + adr) = d;
-}
-
-void pnc_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-  *(__u32 *)(WINDOW_ADDR + adr) = d;
-}
-
-void pnc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-  memcpy((void *)(WINDOW_ADDR + to), from, len);
-}
 
 struct map_info pnc_map = {
-	.name		= "PNC-2000",
-	.size		= WINDOW_SIZE,
-	.buswidth	= 4,
-	.read8		= pnc_read8,
-	.read16		= pnc_read16,
-	.read32		= pnc_read32,
-	.copy_from	= pnc_copy_from,
-	.write8		= pnc_write8,
-	.write16	= pnc_write16,
-	.write32	= pnc_write32,
-	.copy_to	= pnc_copy_to
+	.name = "PNC-2000",
+	.size = WINDOW_SIZE,
+	.buswidth = 4,
+	.phys = 0xFFFFFFFF,
+	.virt = WINDOW_ADDR,
 };
 
 
@@ -84,18 +40,19 @@
  */
 static struct mtd_partition pnc_partitions[3] = {
 	{
-		.name	= "PNC-2000 boot firmware",
-		.size	= 0x20000,
+		.name = "PNC-2000 boot firmware",
+		.size = 0x20000,
+		.offset = 0
 	},
 	{
-		.name	= "PNC-2000 kernel",
-		.size	= 0x1a0000,
-		.offset	= 0x20000
+		.name = "PNC-2000 kernel",
+		.size = 0x1a0000,
+		.offset = 0x20000
 	},
 	{
-		.name	= "PNC-2000 filesystem",
-		.size	= 0x240000,
-		.offset	= 0x1c0000
+		.name = "PNC-2000 filesystem",
+		.size = 0x240000,
+		.offset = 0x1c0000
 	}
 };
 
@@ -109,9 +66,11 @@
 {
 	printk(KERN_NOTICE "Photron PNC-2000 flash mapping: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
 
+	simple_map_init(&pnc_map);
+
 	mymtd = do_map_probe("cfi_probe", &pnc_map);
 	if (mymtd) {
-		mymtd->module = THIS_MODULE;
+		mymtd->owner = THIS_MODULE;
 		return add_mtd_partitions(mymtd, pnc_partitions, 3);
 	}
 
diff -Nru a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/redwood.c	Wed May 28 08:01:21 2003
@@ -0,0 +1,171 @@
+/*
+ * $Id: redwood.c,v 1.6 2003/05/21 12:45:19 dwmw2 Exp $
+ *
+ * drivers/mtd/maps/redwood.c
+ *
+ * FLASH map for the IBM Redwood 4/5/6 boards.
+ *
+ *
+ * Author: Armin Kuster <akuster@mvista.com>
+ *
+ * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+
+#if !defined (CONFIG_REDWOOD_6)
+
+#define WINDOW_ADDR 0xffc00000
+#define WINDOW_SIZE 0x00400000
+
+#define RW_PART0_OF	0
+#define RW_PART0_SZ	0x10000
+#define RW_PART1_OF	RW_PART0_SZ
+#define RW_PART1_SZ	0x200000 - 0x10000
+#define RW_PART2_OF	0x200000
+#define RW_PART2_SZ	0x10000
+#define RW_PART3_OF	0x210000
+#define RW_PART3_SZ	0x200000 - (0x10000 + 0x20000)
+#define RW_PART4_OF	0x3e0000
+#define RW_PART4_SZ	0x20000
+
+static struct mtd_partition redwood_flash_partitions[] = {
+	{
+		.name = "Redwood OpenBIOS Vital Product Data",
+		.offset = RW_PART0_OF,
+		.size = RW_PART0_SZ,
+		.mask_flags = MTD_WRITEABLE	/* force read-only */
+	},
+	{
+		.name = "Redwood kernel",
+		.offset = RW_PART1_OF,
+		.size = RW_PART1_SZ
+	},
+	{
+		.name = "Redwood OpenBIOS non-volatile storage",
+		.offset = RW_PART2_OF,
+		.size = RW_PART2_SZ,
+		.mask_flags = MTD_WRITEABLE	/* force read-only */
+	},
+	{
+		.name = "Redwood filesystem",
+		.offset = RW_PART3_OF,
+		.size = RW_PART3_SZ
+	},
+	{
+		.name = "Redwood OpenBIOS",
+		.offset = RW_PART4_OF,
+		.size = RW_PART4_SZ,
+		.mask_flags = MTD_WRITEABLE	/* force read-only */
+	}
+};
+
+#else /* CONFIG_REDWOOD_6 */
+/* FIXME: the window is bigger - armin */
+#define WINDOW_ADDR 0xff800000
+#define WINDOW_SIZE 0x00800000
+
+#define RW_PART0_OF	0
+#define RW_PART0_SZ	0x400000	/* 4 MiB data */
+#define RW_PART1_OF	RW_PART0_OF + RW_PART0_SZ 
+#define RW_PART1_SZ	0x10000		/* 64K VPD */
+#define RW_PART2_OF	RW_PART1_OF + RW_PART1_SZ
+#define RW_PART2_SZ	0x400000 - (0x10000 + 0x20000)
+#define RW_PART3_OF	RW_PART2_OF + RW_PART2_SZ
+#define RW_PART3_SZ	0x20000
+
+static struct mtd_partition redwood_flash_partitions[] = {
+	{
+		.name = "Redwood kernel",
+		.offset = RW_PART0_OF,
+		.size = RW_PART0_SZ
+	},
+	{
+		.name = "Redwood OpenBIOS Vital Product Data",
+		.offset = RW_PART1_OF,
+		.size = RW_PART1_SZ,
+		.mask_flags = MTD_WRITEABLE	/* force read-only */
+	},
+	{
+		.name = "Redwood filesystem",
+		.offset = RW_PART2_OF,
+		.size = RW_PART2_SZ
+	},
+	{
+		.name = "Redwood OpenBIOS",
+		.offset = RW_PART3_OF,
+		.size = RW_PART3_SZ,
+		.mask_flags = MTD_WRITEABLE	/* force read-only */
+	}
+};
+
+#endif /* CONFIG_REDWOOD_6 */
+
+struct map_info redwood_flash_map = {
+	.name = "IBM Redwood",
+	.size = WINDOW_SIZE,
+	.buswidth = 2,
+	.phys = WINDOW_ADDR,
+};
+
+
+#define NUM_REDWOOD_FLASH_PARTITIONS \
+	(sizeof(redwood_flash_partitions)/sizeof(redwood_flash_partitions[0]))
+
+static struct mtd_info *redwood_mtd;
+
+int __init init_redwood_flash(void)
+{
+	printk(KERN_NOTICE "redwood: flash mapping: %x at %x\n",
+			WINDOW_SIZE, WINDOW_ADDR);
+
+	redwood_flash_map.virt =
+		(unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
+
+	if (!redwood_flash_map.virt) {
+		printk("init_redwood_flash: failed to ioremap\n");
+		return -EIO;
+	}
+	simple_map_init(&redwood_flash_map);
+
+	redwood_mtd = do_map_probe("cfi_probe",&redwood_flash_map);
+
+	if (redwood_mtd) {
+		redwood_mtd->owner = THIS_MODULE;
+		return add_mtd_partitions(redwood_mtd,
+				redwood_flash_partitions,
+				NUM_REDWOOD_FLASH_PARTITIONS);
+	}
+
+	return -ENXIO;
+}
+
+static void __exit cleanup_redwood_flash(void)
+{
+	if (redwood_mtd) {
+		del_mtd_partitions(redwood_mtd);
+		/* moved iounmap after map_destroy - armin */
+		map_destroy(redwood_mtd);
+		iounmap((void *)redwood_flash_map.virt);
+	}
+}
+
+module_init(init_redwood_flash);
+module_exit(cleanup_redwood_flash);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Armin Kuster <akuster@mvista.com>");
+MODULE_DESCRIPTION("MTD map driver for the IBM Redwood reference boards");
diff -Nru a/drivers/mtd/maps/rpxlite.c b/drivers/mtd/maps/rpxlite.c
--- a/drivers/mtd/maps/rpxlite.c	Wed Feb 26 04:58:44 2003
+++ b/drivers/mtd/maps/rpxlite.c	Wed May 28 08:01:04 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: rpxlite.c,v 1.19 2003/05/21 12:45:19 dwmw2 Exp $
  *
  * Handle mapping of the flash on the RPX Lite and CLLF boards
  */
@@ -7,6 +7,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -17,80 +18,31 @@
 
 static struct mtd_info *mymtd;
 
-__u8 rpxlite_read8(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readb(map->map_priv_1 + ofs);
-}
-
-__u16 rpxlite_read16(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readw(map->map_priv_1 + ofs);
-}
-
-__u32 rpxlite_read32(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readl(map->map_priv_1 + ofs);
-}
-
-void rpxlite_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
-}
-
-void rpxlite_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	__raw_writeb(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void rpxlite_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	__raw_writew(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void rpxlite_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	__raw_writel(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void rpxlite_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy_toio((void *)(map->map_priv_1 + to), from, len);
-}
-
-struct map_info rpxlite_map = {
-	.name		= "RPX",
-	.size		= WINDOW_SIZE,
-	.buswidth	= 4,
-	.read8		= rpxlite_read8,
-	.read16		= rpxlite_read16,
-	.read32		= rpxlite_read32,
-	.copy_from	= rpxlite_copy_from,
-	.write8		= rpxlite_write8,
-	.write16	= rpxlite_write16,
-	.write32	= rpxlite_write32,
-	.copy_to	= rpxlite_copy_to
+static struct map_info rpxlite_map = {
+	.name = "RPX",
+	.size = WINDOW_SIZE,
+	.buswidth = 4,
+	.phys = WINDOW_ADDR,
 };
 
 int __init init_rpxlite(void)
 {
 	printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR);
-	rpxlite_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
+	rpxlite_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
 
-	if (!rpxlite_map.map_priv_1) {
+	if (!rpxlite_map.virt) {
 		printk("Failed to ioremap\n");
 		return -EIO;
 	}
+	simple_map_init(&rpxlite_map);
 	mymtd = do_map_probe("cfi_probe", &rpxlite_map);
 	if (mymtd) {
-		mymtd->module = THIS_MODULE;
+		mymtd->owner = THIS_MODULE;
 		add_mtd_device(mymtd);
 		return 0;
 	}
 
-	iounmap((void *)rpxlite_map.map_priv_1);
+	iounmap((void *)rpxlite_map.virt);
 	return -ENXIO;
 }
 
@@ -100,9 +52,9 @@
 		del_mtd_device(mymtd);
 		map_destroy(mymtd);
 	}
-	if (rpxlite_map.map_priv_1) {
-		iounmap((void *)rpxlite_map.map_priv_1);
-		rpxlite_map.map_priv_1 = 0;
+	if (rpxlite_map.virt) {
+		iounmap((void *)rpxlite_map.virt);
+		rpxlite_map.virt = 0;
 	}
 }
 
diff -Nru a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
--- a/drivers/mtd/maps/sa1100-flash.c	Mon May 12 18:59:22 2003
+++ b/drivers/mtd/maps/sa1100-flash.c	Thu May 29 03:42:14 2003
@@ -3,7 +3,7 @@
  * 
  * (C) 2000 Nicolas Pitre <nico@cam.org>
  * 
- * $Id: sa1100-flash.c,v 1.28 2002/05/07 13:48:38 abz Exp $
+ * $Id: sa1100-flash.c,v 1.36 2003/05/29 08:59:35 dwmw2 Exp $
  */
 
 #include <linux/config.h>
@@ -11,6 +11,9 @@
 #include <linux/types.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -33,59 +36,6 @@
  */
 #define CONFIG_MTD_SA1100_STATICMAP 1
 
-static __u8 sa1100_read8(struct map_info *map, unsigned long ofs)
-{
-	return readb(map->map_priv_1 + ofs);
-}
-
-static __u16 sa1100_read16(struct map_info *map, unsigned long ofs)
-{
-	return readw(map->map_priv_1 + ofs);
-}
-
-static __u32 sa1100_read32(struct map_info *map, unsigned long ofs)
-{
-	return readl(map->map_priv_1 + ofs);
-}
-
-static void sa1100_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy(to, (void *)(map->map_priv_1 + from), len);
-}
-
-static void sa1100_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	writeb(d, map->map_priv_1 + adr);
-}
-
-static void sa1100_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	writew(d, map->map_priv_1 + adr);
-}
-
-static void sa1100_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	writel(d, map->map_priv_1 + adr);
-}
-
-static void sa1100_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy((void *)(map->map_priv_1 + to), from, len);
-}
-
-static struct map_info sa1100_map __initdata = {
-	.name		= "SA1100 flash",
-	.read8		= sa1100_read8,
-	.read16		= sa1100_read16,
-	.read32		= sa1100_read32,
-	.copy_from	= sa1100_copy_from,
-	.write8		= sa1100_write8,
-	.write16	= sa1100_write16,
-	.write32	= sa1100_write32,
-	.copy_to	= sa1100_copy_to,
-};
-
-
 #ifdef CONFIG_MTD_SA1100_STATICMAP
 /*
  * Here are partition information for all known SA1100-based devices.
@@ -959,6 +909,7 @@
 	unsigned long size;
 	int width;
 	void *vbase;
+        void (*set_vpp)(struct map_info *, int);
 	struct map_info *map;
 	struct mtd_info *mtd;
 	struct resource *res;
@@ -981,6 +932,8 @@
 	if (!maps)
 		return -ENOMEM;
 
+	memset(maps, 0, sizeof(struct map_info) * nr);
+
 	/*
 	 * Claim and then map the memory regions.
 	 */
@@ -995,7 +948,6 @@
 		}
 
 		sa[i].map = maps + i;
-		memcpy(sa[i].map, &sa1100_map, sizeof(struct map_info));
 
 		sa[i].vbase = ioremap(sa[i].base, sa[i].size);
 		if (!sa[i].vbase) {
@@ -1003,10 +955,14 @@
 			break;
 		}
 
-		sa[i].map->map_priv_1 = (unsigned long)sa[i].vbase;
+		sa[i].map->virt = (unsigned long)sa[i].vbase;
+		sa[i].map->phys = sa[i].base;
+		sa[i].map->set_vpp = sa[i].set_vpp;
 		sa[i].map->buswidth = sa[i].width;
 		sa[i].map->size = sa[i].size;
 
+		simple_map_init(sa[i].map);
+
 		/*
 		 * Now let's probe for the actual flash.  Do it here since
 		 * specific machine settings might have been set above.
@@ -1016,7 +972,7 @@
 			ret = -ENXIO;
 			break;
 		}
-		sa[i].mtd->module = THIS_MODULE;
+		sa[i].mtd->owner = THIS_MODULE;
 		subdev[i] = sa[i].mtd;
 
 		printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
@@ -1105,10 +1061,76 @@
 	kfree(sa[0].map);
 }
 
+/*
+ * A Thought: can we automatically detect the flash?
+ *  - Check to see if the region is busy (yes -> failure)
+ *  - Is the MSC setup for flash (no -> failure)
+ *  - Probe for flash
+ */
+
+static struct map_info sa1100_probe_map __initdata = {
+	.name		= "SA1100-flash",
+};
+
+static void __init sa1100_probe_one_cs(unsigned int msc, unsigned long phys)
+{
+	struct mtd_info *mtd;
+
+	printk(KERN_INFO "* Probing 0x%08lx: MSC = 0x%04x %d bit ",
+		phys, msc & 0xffff, msc & MSC_RBW ? 16 : 32);
+
+	if (check_mem_region(phys, 0x08000000)) {
+		printk("busy\n");
+		return;
+	}
+
+	if ((msc & 3) == 1) {
+		printk("wrong type\n");
+		return;
+	}
+
+	sa1100_probe_map.buswidth = msc & MSC_RBW ? 2 : 4;
+	sa1100_probe_map.size = SZ_1M;
+	sa1100_probe_map.phys = phys;
+	sa1100_probe_map.virt = (unsigned long)ioremap(phys, SZ_1M);
+	if (sa1100_probe_map.virt == 0)
+		goto fail;
+	simple_map_init(&sa1100_probe_map);
+
+	/* Shame cfi_probe blurts out kernel messages... */
+	mtd = do_map_probe("cfi_probe", &sa1100_probe_map);
+	if (mtd)
+		map_destroy(mtd);
+	iounmap((void *)sa1100_probe_map.virt);
+
+	if (!mtd)
+		goto fail;
+
+	printk("pass\n");
+	return;
+
+ fail:
+	printk("failed\n");
+}
+
+static void __init sa1100_probe_flash(void)
+{
+	printk(KERN_INFO "-- SA11xx Flash probe.  Please report results.\n");
+	sa1100_probe_one_cs(MSC0, SA1100_CS0_PHYS);
+	sa1100_probe_one_cs(MSC0 >> 16, SA1100_CS1_PHYS);
+	sa1100_probe_one_cs(MSC1, SA1100_CS2_PHYS);
+	sa1100_probe_one_cs(MSC1 >> 16, SA1100_CS3_PHYS);
+	sa1100_probe_one_cs(MSC2, SA1100_CS4_PHYS);
+	sa1100_probe_one_cs(MSC2 >> 16, SA1100_CS5_PHYS);
+	printk(KERN_INFO "-- SA11xx Flash probe complete.\n");
+}
+
 static int __init sa1100_locate_flash(void)
 {
 	int i, nr = -ENODEV;
 
+	sa1100_probe_flash();
+
 	if (machine_is_adsbitsy()) {
 		info[0].base = SA1100_CS1_PHYS;
 		info[0].size = SZ_32M;
@@ -1162,7 +1184,7 @@
 		nr = 1;
 	}
 	if (machine_is_h3xxx()) {
-		sa1100_map.set_vpp = h3xxx_set_vpp;
+		info[0].set_vpp = h3xxx_set_vpp;
 		info[0].base = SA1100_CS0_PHYS;
 		info[0].size = SZ_32M;
 		nr = 1;
@@ -1178,7 +1200,7 @@
 		nr = 1;
 	}
 	if (machine_is_jornada720()) {
-		sa1100_map.set_vpp = jornada720_set_vpp;
+		info[0].set_vpp = jornada720_set_vpp;
 		info[0].base = SA1100_CS0_PHYS;
 		info[0].size = SZ_32M;
 		nr = 1;
@@ -1273,10 +1295,8 @@
 	return nr;
 }
 
-extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
-extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
-
 static struct mtd_partition *parsed_parts;
+const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
 
 static void __init sa1100_locate_partitions(struct mtd_info *mtd)
 {
@@ -1287,17 +1307,10 @@
 		/*
 		 * Partition selection stuff.
 		 */
-#ifdef CONFIG_MTD_CMDLINE_PARTS
-		nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "sa1100");
-		if (nr_parts > 0) {
-			part_type = "command line";
-			break;
-		}
-#endif
-#ifdef CONFIG_MTD_REDBOOT_PARTS
-		nr_parts = parse_redboot_partitions(mtd, &parsed_parts);
+#ifdef CONFIG_MTD_PARTITIONS
+		nr_parts = parse_mtd_partitions(mtd, part_probes, &parsed_parts, 0);
 		if (nr_parts > 0) {
-			part_type = "RedBoot";
+			part_type = "dynamic";
 			break;
 		}
 #endif
diff -Nru a/drivers/mtd/maps/sbc_gxx.c b/drivers/mtd/maps/sbc_gxx.c
--- a/drivers/mtd/maps/sbc_gxx.c	Wed Feb 26 05:01:56 2003
+++ b/drivers/mtd/maps/sbc_gxx.c	Wed May 28 08:01:04 2003
@@ -17,7 +17,7 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
-   $Id: sbc_gxx.c,v 1.19 2001/10/02 15:05:14 dwmw2 Exp $
+   $Id: sbc_gxx.c,v 1.26 2003/05/26 08:50:36 dwmw2 Exp $
 
 The SBC-MediaGX / SBC-GXx has up to 16 MiB of 
 Intel StrataFlash (28F320/28F640) in x8 mode.  
@@ -26,7 +26,7 @@
 
 The flash is accessed as follows:
 
-   16 kbyte memory window at 0xdc000-0xdffff
+   16 KiB memory window at 0xdc000-0xdffff
    
    Two IO address locations for paging
    
@@ -90,20 +90,15 @@
 /* partition_info gives details on the logical partitions that the split the 
  * single flash device into. If the size if zero we use up to the end of the
  * device. */
-static struct mtd_partition partition_info[] = {
-	{
-		.name	= "SBC-GXx flash boot partition", 
-		.size	= BOOT_PARTITION_SIZE_KiB*1024
-	},
-	{
-		.name	= "SBC-GXx flash data partition", 
-		.offset	= BOOT_PARTITION_SIZE_KiB*1024, 
-		.size	= (DATA_PARTITION_SIZE_KiB)*1024
-	},
-	{
-		.name	= "SBC-GXx flash application partition", 
-		.offset	= (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024
-	}
+static struct mtd_partition partition_info[]={
+    { .name = "SBC-GXx flash boot partition", 
+      .offset = 0, 
+      .size =   BOOT_PARTITION_SIZE_KiB*1024 },
+    { .name = "SBC-GXx flash data partition", 
+      .offset = BOOT_PARTITION_SIZE_KiB*1024, 
+      .size = (DATA_PARTITION_SIZE_KiB)*1024 },
+    { .name = "SBC-GXx flash application partition", 
+      .offset = (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 }
 };
 
 #define NUM_PARTITIONS 3
@@ -208,20 +203,20 @@
 }
 
 static struct map_info sbc_gxx_map = {
-	.name		= "SBC-GXx flash",
-	.size		= MAX_SIZE_KiB*1024, /* this must be set to a maximum
-						possible amount of flash so
-						the cfi probe routines find
-						all the chips */
-	.buswidth	= 1,
-	.read8		= sbc_gxx_read8,
-	.read16		= sbc_gxx_read16,
-	.read32		= sbc_gxx_read32,
-	.copy_from	= sbc_gxx_copy_from,
-	.write8		= sbc_gxx_write8,
-	.write16	= sbc_gxx_write16,
-	.write32	= sbc_gxx_write32,
-	.copy_to	= sbc_gxx_copy_to
+	.name = "SBC-GXx flash",
+	.phys = NO_XIP,
+	.size = MAX_SIZE_KiB*1024, /* this must be set to a maximum possible amount
+			 of flash so the cfi probe routines find all
+			 the chips */
+	.buswidth = 1,
+	.read8 = sbc_gxx_read8,
+	.read16 = sbc_gxx_read16,
+	.read32 = sbc_gxx_read32,
+	.copy_from = sbc_gxx_copy_from,
+	.write8 = sbc_gxx_write8,
+	.write16 = sbc_gxx_write16,
+	.write32 = sbc_gxx_write32,
+	.copy_to = sbc_gxx_copy_to
 };
 
 /* MTD device for all of the flash. */
@@ -240,12 +235,6 @@
 
 int __init init_sbc_gxx(void)
 {
-	if (check_region(PAGE_IO,PAGE_IO_SIZE) != 0) {
-		printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n",
-			sbc_gxx_map.name,
-			PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 );
-		return -EAGAIN;
-	}
   	iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
 	if (!iomapadr) {
 		printk( KERN_ERR"%s: failed to ioremap memory region\n",
@@ -253,7 +242,14 @@
 		return -EIO;
 	}
 	
-	request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash" );
+	if (!request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash")) {
+		printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n",
+			sbc_gxx_map.name,
+			PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 );
+		iounmap((void *)iomapadr);
+		return -EAGAIN;
+	}
+		
 	
 	printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n",
 		sbc_gxx_map.name,
@@ -267,7 +263,7 @@
 		return -ENXIO;
 	}
 	
-	all_mtd->module=THIS_MODULE;
+	all_mtd->owner = THIS_MODULE;
 
 	/* Create MTD devices for each partition. */
 	add_mtd_partitions(all_mtd, partition_info, NUM_PARTITIONS );
diff -Nru a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c
--- a/drivers/mtd/maps/sc520cdp.c	Wed Feb 26 05:03:40 2003
+++ b/drivers/mtd/maps/sc520cdp.c	Wed May 28 08:01:04 2003
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  *
- * $Id: sc520cdp.c,v 1.9 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: sc520cdp.c,v 1.15 2003/05/21 12:45:20 dwmw2 Exp $
  *
  *
  * The SC520CDP is an evaluation board for the Elan SC520 processor available
@@ -25,13 +25,15 @@
  * For details see http://www.amd.com/products/epd/desiging/evalboards/18.elansc520/520_cdp_brief/index.html
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
-
+#include <linux/mtd/concat.h>
 
 /*
 ** The Embedded Systems BIOS decodes the first FLASH starting at
@@ -83,94 +85,32 @@
 #define WINDOW_SIZE_1	0x00800000
 #define WINDOW_SIZE_2	0x00080000
 
-static __u8 sc520cdp_read8(struct map_info *map, unsigned long ofs)
-{
-	return readb(map->map_priv_1 + ofs);
-}
-
-static __u16 sc520cdp_read16(struct map_info *map, unsigned long ofs)
-{
-	return readw(map->map_priv_1 + ofs);
-}
-
-static __u32 sc520cdp_read32(struct map_info *map, unsigned long ofs)
-{
-	return readl(map->map_priv_1 + ofs);
-}
-
-static void sc520cdp_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
-}
-
-static void sc520cdp_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	writeb(d, map->map_priv_1 + adr);
-}
-
-static void sc520cdp_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	writew(d, map->map_priv_1 + adr);
-}
-
-static void sc520cdp_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	writel(d, map->map_priv_1 + adr);
-}
-
-static void sc520cdp_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy_toio((void *)(map->map_priv_1 + to), from, len);
-}
 
 static struct map_info sc520cdp_map[] = {
 	{
-		.name		= "SC520CDP Flash Bank #0",
-		.size		= WINDOW_SIZE_0,
-		.buswidth	= 4,
-		.read8		= sc520cdp_read8,
-		.read16		= sc520cdp_read16,
-		.read32		= sc520cdp_read32,
-		.copy_from	= sc520cdp_copy_from,
-		.write8		= sc520cdp_write8,
-		.write16	= sc520cdp_write16,
-		.write32	= sc520cdp_write32,
-		.copy_to	= sc520cdp_copy_to,
-		.map_priv_2	= WINDOW_ADDR_0
+		.name = "SC520CDP Flash Bank #0",
+		.size = WINDOW_SIZE_0,
+		.buswidth = 4,
+		.phys = WINDOW_ADDR_0
 	},
 	{
-		.name		= "SC520CDP Flash Bank #1",
-		.size		= WINDOW_SIZE_1,
-		.buswidth	= 4,
-		.read8		= sc520cdp_read8,
-		.read16		= sc520cdp_read16,
-		.read32		= sc520cdp_read32,
-		.copy_from	= sc520cdp_copy_from,
-		.write8		= sc520cdp_write8,
-		.write16	= sc520cdp_write16,
-		.write32	= sc520cdp_write32,
-		.copy_to	= sc520cdp_copy_to,
-		.map_priv_2	= WINDOW_ADDR_1
+		.name = "SC520CDP Flash Bank #1",
+		.size = WINDOW_SIZE_1,
+		.buswidth = 4,
+		.phys = WINDOW_ADDR_1
 	},
 	{
-		.name		= "SC520CDP DIL Flash",
-		.size		= WINDOW_SIZE_2,
-		.buswidth	= 1,
-		.read8		= sc520cdp_read8,
-		.read16		= sc520cdp_read16,
-		.read32		= sc520cdp_read32,
-		.copy_from	= sc520cdp_copy_from,
-		.write8		= sc520cdp_write8,
-		.write16	= sc520cdp_write16,
-		.write32	= sc520cdp_write32,
-		.copy_to	= sc520cdp_copy_to,
-		.map_priv_2	= WINDOW_ADDR_2
+		.name = "SC520CDP DIL Flash",
+		.size = WINDOW_SIZE_2,
+		.buswidth = 1,
+		.phys = WINDOW_ADDR_2
 	},
 };
 
 #define NUM_FLASH_BANKS	(sizeof(sc520cdp_map)/sizeof(struct map_info))
 
 static struct mtd_info *mymtd[NUM_FLASH_BANKS];
+static struct mtd_info *merged_mtd;
 
 #ifdef REPROGRAM_PAR
 
@@ -253,9 +193,9 @@
 	/* map in SC520's MMCR area */
 	mmcr = (unsigned long *)ioremap_nocache(SC520_MMCR_BASE, SC520_MMCR_EXTENT);
 	if(!mmcr) { /* ioremap_nocache failed: skip the PAR reprogramming */
-		/* force map_priv_2 fields to BIOS defaults: */
+		/* force physical address fields to BIOS defaults: */
 		for(i = 0; i < NUM_FLASH_BANKS; i++)
-			sc520cdp_map[i].map_priv_2 = par_table[i].default_address;
+			sc520cdp_map[i].phys = par_table[i].default_address;
 		return;
 	}
 
@@ -280,7 +220,7 @@
 				sc520cdp_map[i].name);
 			printk(KERN_NOTICE "Trying default address 0x%lx\n",
 				par_table[i].default_address);
-			sc520cdp_map[i].map_priv_2 = par_table[i].default_address;
+			sc520cdp_map[i].phys = par_table[i].default_address;
 		}
 	}
 	iounmap((void *)mmcr);
@@ -298,28 +238,40 @@
 #endif
 
 	for (i = 0; i < NUM_FLASH_BANKS; i++) {
-		printk(KERN_NOTICE "SC520 CDP flash device: %lx at %lx\n", sc520cdp_map[i].size, sc520cdp_map[i].map_priv_2);
-		sc520cdp_map[i].map_priv_1 = (unsigned long)ioremap_nocache(sc520cdp_map[i].map_priv_2, sc520cdp_map[i].size);
+		printk(KERN_NOTICE "SC520 CDP flash device: 0x%lx at 0x%lx\n",
+		       sc520cdp_map[i].size, sc520cdp_map[i].phys);
 
-		if (!sc520cdp_map[i].map_priv_1) {
+		sc520cdp_map[i].virt = (unsigned long)ioremap_nocache(sc520cdp_map[i].phys, sc520cdp_map[i].size);
+
+		if (!sc520cdp_map[i].virt) {
 			printk("Failed to ioremap_nocache\n");
 			return -EIO;
 		}
+
+		simple_map_init(&sc520cdp_map[i]);
+
 		mymtd[i] = do_map_probe("cfi_probe", &sc520cdp_map[i]);
 		if(!mymtd[i])
-			mymtd[i] = do_map_probe("jedec", &sc520cdp_map[i]);
+			mymtd[i] = do_map_probe("jedec_probe", &sc520cdp_map[i]);
 		if(!mymtd[i])
 			mymtd[i] = do_map_probe("map_rom", &sc520cdp_map[i]);
 
 		if (mymtd[i]) {
-			mymtd[i]->module = THIS_MODULE;
-			add_mtd_device(mymtd[i]);
+			mymtd[i]->owner = THIS_MODULE;
 			++devices_found;
 		}
 		else {
-			iounmap((void *)sc520cdp_map[i].map_priv_1);
+			iounmap((void *)sc520cdp_map[i].virt);
 		}
 	}
+	if(devices_found >= 2) {
+		/* Combine the two flash banks into a single MTD device & register it: */
+		merged_mtd = mtd_concat_create(mymtd, 2, "SC520CDP Flash Banks #0 and #1");
+		if(merged_mtd)
+			add_mtd_device(merged_mtd);
+	}
+	if(devices_found == 3) /* register the third (DIL-Flash) device */
+		add_mtd_device(mymtd[2]);
 	return(devices_found ? 0 : -ENXIO);
 }
 
@@ -327,14 +279,19 @@
 {
 	int i;
 	
+	if (merged_mtd) {
+		del_mtd_device(merged_mtd);
+		mtd_concat_destroy(merged_mtd);
+	}
+	if (mymtd[2])
+		del_mtd_device(mymtd[2]);
+
 	for (i = 0; i < NUM_FLASH_BANKS; i++) {
-		if (mymtd[i]) {
-			del_mtd_device(mymtd[i]);
+		if (mymtd[i])
 			map_destroy(mymtd[i]);
-		}
-		if (sc520cdp_map[i].map_priv_1) {
-			iounmap((void *)sc520cdp_map[i].map_priv_1);
-			sc520cdp_map[i].map_priv_1 = 0;
+		if (sc520cdp_map[i].virt) {
+			iounmap((void *)sc520cdp_map[i].virt);
+			sc520cdp_map[i].virt = 0;
 		}
 	}
 }
diff -Nru a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/scb2_flash.c	Wed May 28 08:01:22 2003
@@ -0,0 +1,256 @@
+/*
+ * MTD map driver for BIOS Flash on Intel SCB2 boards
+ * $Id: scb2_flash.c,v 1.6 2003/05/21 12:45:20 dwmw2 Exp $
+ * Copyright (C) 2002 Sun Microsystems, Inc.
+ * Tim Hockin <thockin@sun.com>
+ *
+ * A few notes on this MTD map:
+ *
+ * This was developed with a small number of SCB2 boards to test on.
+ * Hopefully, Intel has not introducted too many unaccounted variables in the
+ * making of this board.
+ *
+ * The BIOS marks its own memory region as 'reserved' in the e820 map.  We
+ * try to request it here, but if it fails, we carry on anyway.
+ *
+ * This is how the chip is attached, so said the schematic:
+ * * a 4 MiB (32 Mib) 16 bit chip
+ * * a 1 MiB memory region
+ * * A20 and A21 pulled up
+ * * D8-D15 ignored
+ * What this means is that, while we are addressing bytes linearly, we are
+ * really addressing words, and discarding the other byte.  This means that
+ * the chip MUST BE at least 2 MiB.  This also means that every block is
+ * actually half as big as the chip reports.  It also means that accesses of
+ * logical address 0 hit higher-address sections of the chip, not physical 0.
+ * One can only hope that these 4MiB x16 chips were a lot cheaper than 1MiB x8
+ * chips.
+ *
+ * This driver assumes the chip is not write-protected by an external signal.
+ * As of the this writing, that is true, but may change, just to spite me.
+ *
+ * The actual BIOS layout has been mostly reverse engineered.  Intel BIOS
+ * updates for this board include 10 related (*.bio - &.bi9) binary files and
+ * another seperate (*.bbo) binary file.  The 10 files are 64k of data + a
+ * small header.  If the headers are stripped off, the 10 64k files can be
+ * concatenated into a 640k image.  This is your BIOS image, proper.  The
+ * seperate .bbo file also has a small header.  It is the 'Boot Block'
+ * recovery BIOS.  Once the header is stripped, no further prep is needed.
+ * As best I can tell, the BIOS is arranged as such:
+ * offset 0x00000 to 0x4ffff (320k):  unknown - SCSI BIOS, etc?
+ * offset 0x50000 to 0xeffff (640k):  BIOS proper
+ * offset 0xf0000 ty 0xfffff (64k):   Boot Block region
+ *
+ * Intel's BIOS update program flashes the BIOS and Boot Block in seperate
+ * steps.  Probably a wise thing to do.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#define MODNAME		"scb2_flash"
+#define SCB2_ADDR	0xfff00000
+#define SCB2_WINDOW	0x00100000
+
+
+static void *scb2_ioaddr;
+static struct mtd_info *scb2_mtd;
+struct map_info scb2_map = {
+	.name =      "SCB2 BIOS Flash",
+	.size =      0,
+	.buswidth =  1,
+};
+static int region_fail;
+
+static int __devinit
+scb2_fixup_mtd(struct mtd_info *mtd)
+{
+	int i;
+	int done = 0;
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+
+	/* barf if this doesn't look right */
+	if (cfi->cfiq->InterfaceDesc != 1) {
+		printk(KERN_ERR MODNAME ": unsupported InterfaceDesc: %#x\n",
+		    cfi->cfiq->InterfaceDesc);
+		return -1;
+	}
+
+	/* I wasn't here. I didn't see. dwmw2. */
+
+	/* the chip is sometimes bigger than the map - what a waste */
+	mtd->size = map->size;
+
+	/*
+	 * We only REALLY get half the chip, due to the way it is
+	 * wired up - D8-D15 are tossed away.  We read linear bytes,
+	 * but in reality we are getting 1/2 of each 16-bit read,
+	 * which LOOKS linear to us.  Because CFI code accounts for
+	 * things like lock/unlock/erase by eraseregions, we need to
+	 * fudge them to reflect this.  Erases go like this:
+	 *   * send an erase to an address
+	 *   * the chip samples the address and erases the block
+	 *   * add the block erasesize to the address and repeat
+	 *   -- the problem is that addresses are 16-bit addressable
+	 *   -- we end up erasing every-other block
+	 */
+	mtd->erasesize /= 2;
+	for (i = 0; i < mtd->numeraseregions; i++) {
+		struct mtd_erase_region_info *region = &mtd->eraseregions[i];
+		region->erasesize /= 2;
+	}
+
+	/*
+	 * If the chip is bigger than the map, it is wired with the high
+	 * address lines pulled up.  This makes us access the top portion of
+	 * the chip, so all our erase-region info is wrong.  Start cutting from
+	 * the bottom.
+	 */
+	for (i = 0; !done && i < mtd->numeraseregions; i++) {
+		struct mtd_erase_region_info *region = &mtd->eraseregions[i];
+
+		if (region->numblocks * region->erasesize > mtd->size) {
+			region->numblocks = (mtd->size / region->erasesize);
+			done = 1;
+		} else {
+			region->numblocks = 0;
+		}
+		region->offset = 0;
+	}
+
+	return 0;
+}
+
+/* CSB5's 'Function Control Register' has bits for decoding @ >= 0xffc00000 */
+#define CSB5_FCR	0x41
+#define CSB5_FCR_DECODE_ALL 0x0e
+static int __devinit
+scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+	u8 reg;
+
+	/* enable decoding of the flash region in the south bridge */
+	pci_read_config_byte(dev, CSB5_FCR, &reg);
+	pci_write_config_byte(dev, CSB5_FCR, reg | CSB5_FCR_DECODE_ALL);
+
+	if (!request_mem_region(SCB2_ADDR, SCB2_WINDOW, scb2_map.name)) {
+		/*
+		 * The BIOS seems to mark the flash region as 'reserved'
+		 * in the e820 map.  Warn and go about our business.
+		 */
+		printk(KERN_WARNING MODNAME
+		    ": warning - can't reserve rom window, continuing\n");
+		region_fail = 1;
+	}
+
+	/* remap the IO window (w/o caching) */
+	scb2_ioaddr = ioremap_nocache(SCB2_ADDR, SCB2_WINDOW);
+	if (!scb2_ioaddr) {
+		printk(KERN_ERR MODNAME ": Failed to ioremap window!\n");
+		if (!region_fail)
+			release_mem_region(SCB2_ADDR, SCB2_WINDOW);
+		return -ENOMEM;
+	}
+
+	scb2_map.phys = SCB2_ADDR;
+	scb2_map.virt = (unsigned long)scb2_ioaddr;
+	scb2_map.size = SCB2_WINDOW;
+
+	simple_map_init(&scb2_map);
+
+	/* try to find a chip */
+	scb2_mtd = do_map_probe("cfi_probe", &scb2_map);
+
+	if (!scb2_mtd) {
+		printk(KERN_ERR MODNAME ": flash probe failed!\n");
+		iounmap(scb2_ioaddr);
+		if (!region_fail)
+			release_mem_region(SCB2_ADDR, SCB2_WINDOW);
+		return -ENODEV;
+	}
+
+	scb2_mtd->owner = THIS_MODULE;
+	if (scb2_fixup_mtd(scb2_mtd) < 0) {
+		del_mtd_device(scb2_mtd);
+		map_destroy(scb2_mtd);
+		iounmap(scb2_ioaddr);
+		if (!region_fail)
+			release_mem_region(SCB2_ADDR, SCB2_WINDOW);
+		return -ENODEV;
+	}
+
+	printk(KERN_NOTICE MODNAME ": chip size 0x%x at offset 0x%x\n",
+	       scb2_mtd->size, SCB2_WINDOW - scb2_mtd->size);
+
+	add_mtd_device(scb2_mtd);
+
+	return 0;
+}
+
+static void __devexit
+scb2_flash_remove(struct pci_dev *dev)
+{
+	if (!scb2_mtd)
+		return;
+
+	/* disable flash writes */
+	if (scb2_mtd->lock)
+		scb2_mtd->lock(scb2_mtd, 0, scb2_mtd->size);
+
+	del_mtd_device(scb2_mtd);
+	map_destroy(scb2_mtd);
+
+	iounmap(scb2_ioaddr);
+	scb2_ioaddr = NULL;
+
+	if (!region_fail)
+		release_mem_region(SCB2_ADDR, SCB2_WINDOW);
+	pci_set_drvdata(dev, NULL);
+}
+
+static struct pci_device_id scb2_flash_pci_ids[] __devinitdata = {
+	{
+	  .vendor = PCI_VENDOR_ID_SERVERWORKS,
+	  .device = PCI_DEVICE_ID_SERVERWORKS_CSB5,
+	  .subvendor = PCI_ANY_ID,
+	  .subdevice = PCI_ANY_ID
+	},
+	{ 0, }
+};
+
+static struct pci_driver scb2_flash_driver = {
+	.name =     "Intel SCB2 BIOS Flash",
+	.id_table = scb2_flash_pci_ids,
+	.probe =    scb2_flash_probe,
+	.remove =   __devexit_p(scb2_flash_remove),
+};
+
+static int __init
+scb2_flash_init(void)
+{
+	return pci_module_init(&scb2_flash_driver);
+}
+
+static void __exit
+scb2_flash_exit(void)
+{
+	pci_unregister_driver(&scb2_flash_driver);
+}
+
+module_init(scb2_flash_init);
+module_exit(scb2_flash_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Hockin <thockin@sun.com>");
+MODULE_DESCRIPTION("MTD map driver for Intel SCB2 BIOS Flash");
+MODULE_DEVICE_TABLE(pci, scb2_flash_pci_ids);
diff -Nru a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c
--- a/drivers/mtd/maps/scx200_docflash.c	Sat Oct  5 10:35:20 2002
+++ b/drivers/mtd/maps/scx200_docflash.c	Wed May 28 08:01:04 2003
@@ -2,6 +2,8 @@
 
    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
 
+   $Id: scx200_docflash.c,v 1.5 2003/05/21 12:45:20 dwmw2 Exp $ 
+
    National Semiconductor SCx200 flash mapped with DOCCS
 */
 
@@ -9,6 +11,7 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -36,7 +39,7 @@
 MODULE_PARM_DESC(flashtype, "Type of MTD probe to do");
 
 static int probe = 0;		/* Don't autoprobe */
-static unsigned size = 0x1000000; /* 16 MB the whole ISA address space */
+static unsigned size = 0x1000000; /* 16 MiB the whole ISA address space */
 static unsigned width = 8;	/* Default to 8 bits wide */
 static char *flashtype = "cfi_probe";
 
@@ -73,46 +76,9 @@
 #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
 #endif
 
-static __u8 scx200_docflash_read8(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readb(map->map_priv_1 + ofs);
-}
-
-static __u16 scx200_docflash_read16(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readw(map->map_priv_1 + ofs);
-}
-
-static void scx200_docflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, map->map_priv_1 + from, len);
-}
-
-static void scx200_docflash_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	__raw_writeb(d, map->map_priv_1 + adr);
-	mb();
-}
-
-static void scx200_docflash_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	__raw_writew(d, map->map_priv_1 + adr);
-	mb();
-}
-
-static void scx200_docflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy_toio(map->map_priv_1 + to, from, len);
-}
 
 static struct map_info scx200_docflash_map = {
 	.name      = "NatSemi SCx200 DOCCS Flash",
-	.read8     = scx200_docflash_read8,
-	.read16    = scx200_docflash_read16,
-	.copy_from = scx200_docflash_copy_from,
-	.write8    = scx200_docflash_write8,
-	.write16   = scx200_docflash_write16,
-	.copy_to   = scx200_docflash_copy_to
 };
 
 int __init init_scx200_docflash(void)
@@ -211,8 +177,11 @@
 	else
 		scx200_docflash_map.buswidth = 2;
 
-	scx200_docflash_map.map_priv_1 = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size);
-	if (!scx200_docflash_map.map_priv_1) {
+	simple_map_init(&scx200_docflash_map);
+
+	scx200_docflash_map.phys = docmem.start;
+	scx200_docflash_map.virt = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size);
+	if (!scx200_docflash_map.virt) {
 		printk(KERN_ERR NAME ": failed to ioremap the flash\n");
 		release_resource(&docmem);
 		return -EIO;
@@ -221,7 +190,7 @@
 	mymtd = do_map_probe(flashtype, &scx200_docflash_map);
 	if (!mymtd) {
 		printk(KERN_ERR NAME ": unable to detect flash\n");
-		iounmap((void *)scx200_docflash_map.map_priv_1);
+		iounmap((void *)scx200_docflash_map.virt);
 		release_resource(&docmem);
 		return -ENXIO;
 	}
@@ -229,7 +198,7 @@
 	if (size < mymtd->size)
 		printk(KERN_WARNING NAME ": warning, flash mapping is smaller than flash size\n");
 
-	mymtd->module = THIS_MODULE;
+	mymtd->owner = THIS_MODULE;
 
 #if PARTITION
 	partition_info[3].offset = mymtd->size-partition_info[3].size;
@@ -251,8 +220,8 @@
 #endif
 		map_destroy(mymtd);
 	}
-	if (scx200_docflash_map.map_priv_1) {
-		iounmap((void *)scx200_docflash_map.map_priv_1);
+	if (scx200_docflash_map.virt) {
+		iounmap((void *)scx200_docflash_map.virt);
 		release_resource(&docmem);
 	}
 }
diff -Nru a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c
--- a/drivers/mtd/maps/solutionengine.c	Wed Feb 26 05:04:15 2003
+++ b/drivers/mtd/maps/solutionengine.c	Wed May 28 08:01:04 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: solutionengine.c,v 1.3 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: solutionengine.c,v 1.10 2003/05/21 12:45:20 dwmw2 Exp $
  *
  * Flash and EPROM on Hitachi Solution Engine and similar boards.
  *
@@ -11,29 +11,12 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
-
-
-extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
-
-__u32 soleng_read32(struct map_info *map, unsigned long ofs)
-{
-	return __raw_readl(map->map_priv_1 + ofs);
-}
-
-void soleng_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	__raw_writel(d, map->map_priv_1 + adr);
-	mb();
-}
-
-void soleng_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, map->map_priv_1 + from, len);
-}
+#include <linux/config.h>
 
 
 static struct mtd_info *flash_mtd;
@@ -42,36 +25,58 @@
 static struct mtd_partition *parsed_parts;
 
 struct map_info soleng_eprom_map = {
-	.name		= "Solution Engine EPROM",
-	.size		= 0x400000,
-	.buswidth	= 4,
-	.copy_from	= soleng_copy_from,
+	.name = "Solution Engine EPROM",
+	.size = 0x400000,
+	.buswidth = 4,
 };
 
 struct map_info soleng_flash_map = {
-	.name		= "Solution Engine FLASH",
-	.size		= 0x400000,
-	.buswidth	= 4,
-	.read32		= soleng_read32,
-	.copy_from	= soleng_copy_from,
-	.write32	= soleng_write32,
+	.name = "Solution Engine FLASH",
+	.size = 0x400000,
+	.buswidth = 4,
 };
 
+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
+
+#ifdef CONFIG_MTD_SUPERH_RESERVE
+static struct mtd_partition superh_se_partitions[] = {
+	/* Reserved for boot code, read-only */
+	{
+		.name = "flash_boot",
+		.offset = 0x00000000,
+		.size = CONFIG_MTD_SUPERH_RESERVE,
+		.mask_flags = MTD_WRITEABLE,
+	},
+	/* All else is writable (e.g. JFFS) */
+	{
+		.name = "Flash FS",
+		.offset = MTDPART_OFS_NXTBLK,
+		.size = MTDPART_SIZ_FULL,
+	}
+};
+#endif /* CONFIG_MTD_SUPERH_RESERVE */
+
 static int __init init_soleng_maps(void)
 {
-	int nr_parts;
+	int nr_parts = 0;
 
 	/* First probe at offset 0 */
-	soleng_flash_map.map_priv_1 = P2SEGADDR(0);
-	soleng_eprom_map.map_priv_1 = P1SEGADDR(0x400000);
-
-	printk(KERN_NOTICE "Probing for flash chips at 0x000000:\n");
+	soleng_flash_map.phys = 0;
+	soleng_flash_map.virt = P2SEGADDR(0);
+	soleng_eprom_map.phys = 0x01000000;
+	soleng_eprom_map.virt = P1SEGADDR(0x01000000);
+	simple_map_init(&soleng_eprom_map);
+	simple_map_init(&soleng_flash_map);
+	
+	printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n");
 	flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map);
 	if (!flash_mtd) {
 		/* Not there. Try swapping */
-		printk(KERN_NOTICE "Probing for flash chips at 0x400000:\n");
-		soleng_flash_map.map_priv_1 = P2SEGADDR(0x400000);
-		soleng_eprom_map.map_priv_1 = P1SEGADDR(0);
+		printk(KERN_NOTICE "Probing for flash chips at 0x01000000:\n");
+		soleng_flash_map.phys = 0x01000000;
+		soleng_flash_map.virt = P2SEGADDR(0x01000000);
+		soleng_eprom_map.phys = 0;
+		soleng_eprom_map.virt = P1SEGADDR(0);
 		flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map);
 		if (!flash_mtd) {
 			/* Eep. */
@@ -80,19 +85,28 @@
 		}
 	}
 	printk(KERN_NOTICE "Solution Engine: Flash at 0x%08lx, EPROM at 0x%08lx\n",
-	       soleng_flash_map.map_priv_1 & 0x1fffffff,
-	       soleng_eprom_map.map_priv_1 & 0x1fffffff);
-	flash_mtd->module = THIS_MODULE;
+	       soleng_flash_map.phys & 0x1fffffff,
+	       soleng_eprom_map.phys & 0x1fffffff);
+	flash_mtd->owner = THIS_MODULE;
 
 	eprom_mtd = do_map_probe("map_rom", &soleng_eprom_map);
 	if (eprom_mtd) {
-		eprom_mtd->module = THIS_MODULE;
+		eprom_mtd->owner = THIS_MODULE;
 		add_mtd_device(eprom_mtd);
 	}
 
-	nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts);
+	nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0);
+
+#if CONFIG_MTD_SUPERH_RESERVE
+	if (nr_parts <= 0) {
+		printk(KERN_NOTICE "Using configured partition at 0x%08x.\n",
+		       CONFIG_MTD_SUPERH_RESERVE);
+		parsed_parts = superh_se_partitions;
+		nr_parts = sizeof(superh_se_partitions)/sizeof(*parsed_parts);
+	}
+#endif /* CONFIG_MTD_SUPERH_RESERVE */
 
-	if (nr_parts)
+	if (nr_parts > 0)
 		add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
 	else
 		add_mtd_device(flash_mtd);
diff -Nru a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c
--- a/drivers/mtd/maps/sun_uflash.c	Wed Feb 26 05:04:41 2003
+++ b/drivers/mtd/maps/sun_uflash.c	Wed May 28 08:01:04 2003
@@ -1,4 +1,4 @@
-/* $Id: sun_uflash.c,v 1.4 2001/10/02 15:05:14 dwmw2 Exp $
+/* $Id: sun_uflash.c,v 1.7 2003/05/20 20:59:32 dwmw2 Exp $
  *
  * sun_uflash - Driver implementation for user-programmable flash
  * present on many Sun Microsystems SME boardsets.
@@ -48,60 +48,11 @@
 	struct list_head	list;
 };
 
-__u8 uflash_read8(struct map_info *map, unsigned long ofs)
-{
-	return(__raw_readb(map->map_priv_1 + ofs));
-}
-
-__u16 uflash_read16(struct map_info *map, unsigned long ofs)
-{
-	return(__raw_readw(map->map_priv_1 + ofs));
-}
-
-__u32 uflash_read32(struct map_info *map, unsigned long ofs)
-{
-	return(__raw_readl(map->map_priv_1 + ofs));
-}
-
-void uflash_copy_from(struct map_info *map, void *to, unsigned long from, 
-		      ssize_t len)
-{
-	memcpy_fromio(to, map->map_priv_1 + from, len);
-}
-
-void uflash_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	__raw_writeb(d, map->map_priv_1 + adr);
-}
-
-void uflash_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	__raw_writew(d, map->map_priv_1 + adr);
-}
-
-void uflash_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	__raw_writel(d, map->map_priv_1 + adr);
-}
-
-void uflash_copy_to(struct map_info *map, unsigned long to, const void *from,
-		    ssize_t len)
-{
-	memcpy_toio(map->map_priv_1 + to, from, len);
-}
 
 struct map_info uflash_map_templ = {
-	.name		= "SUNW,???-????",
-	.size		= UFLASH_WINDOW_SIZE,
-	.buswidth	= UFLASH_BUSWIDTH,
-	.read8		= uflash_read8,
-	.read16		= uflash_read16,
-	.read32		= uflash_read32,
-	.copy_from	= uflash_copy_from,
-	.write8		= uflash_write8,
-	.write16	= uflash_write16,
-	.write32	= uflash_write32,
-	.copy_to	= uflash_copy_to
+		.name =		"SUNW,???-????",
+		.size =		UFLASH_WINDOW_SIZE,
+		.buswidth =	UFLASH_BUSWIDTH,
 };
 
 int uflash_devinit(struct linux_ebus_device* edev)
@@ -145,20 +96,22 @@
 	if(0 != pdev->name && 0 < strlen(pdev->name)) {
 		pdev->map.name = pdev->name;
 	}
-
-	pdev->map.map_priv_1 = 
+	pdev->phys = edev->resource[0].start;
+	pdev->virt = 
 		(unsigned long)ioremap_nocache(edev->resource[0].start, pdev->map.size);
-	if(0 == pdev->map.map_priv_1) {
+	if(0 == pdev->map.virt) {
 		printk("%s: failed to map device\n", __FUNCTION__);
 		kfree(pdev->name);
 		kfree(pdev);
 		return(-1);
 	}
 
+	simple_map_init(&pdev->map);
+
 	/* MTD registration */
 	pdev->mtd = do_map_probe("cfi_probe", &pdev->map);
 	if(0 == pdev->mtd) {
-		iounmap((void *)pdev->map.map_priv_1);
+		iounmap((void *)pdev->map.virt);
 		kfree(pdev->name);
 		kfree(pdev);
 		return(-ENXIO);
@@ -166,7 +119,7 @@
 
 	list_add(&pdev->list, &device_list);
 
-	pdev->mtd->module = THIS_MODULE;
+	pdev->mtd->owner = THIS_MODULE;
 
 	add_mtd_device(pdev->mtd);
 	return(0);
@@ -211,9 +164,9 @@
 			del_mtd_device(udev->mtd);
 			map_destroy(udev->mtd);
 		}
-		if(0 != udev->map.map_priv_1) {
-			iounmap((void*)udev->map.map_priv_1);
-			udev->map.map_priv_1 = 0;
+		if(0 != udev->map.virt) {
+			iounmap((void*)udev->map.virt);
+			udev->map.virt = 0;
 		}
 		if(0 != udev->name) {
 			kfree(udev->name);
diff -Nru a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c
--- a/drivers/mtd/maps/tqm8xxl.c	Wed Feb 26 05:08:39 2003
+++ b/drivers/mtd/maps/tqm8xxl.c	Wed May 28 08:01:04 2003
@@ -2,7 +2,7 @@
  * Handle mapping of the flash memory access routines 
  * on TQM8xxL based devices.
  *
- * $Id: tqm8xxl.c,v 1.3 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: tqm8xxl.c,v 1.8 2003/05/21 12:45:20 dwmw2 Exp $
  *
  * based on rpxlite.c
  *
@@ -26,6 +26,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <asm/io.h>
 
 #include <linux/mtd/mtd.h>
@@ -51,59 +52,6 @@
 static unsigned long num_banks;
 static unsigned long start_scan_addr;
 
-__u8 tqm8xxl_read8(struct map_info *map, unsigned long ofs)
-{
-	return *((__u8 *)(map->map_priv_1 + ofs));
-}
-
-__u16 tqm8xxl_read16(struct map_info *map, unsigned long ofs)
-{
-	return *((__u16 *)(map->map_priv_1 + ofs));
-}
-
-__u32 tqm8xxl_read32(struct map_info *map, unsigned long ofs)
-{
-	return *((__u32 *)(map->map_priv_1 + ofs));
-}
-
-void tqm8xxl_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
-}
-
-void tqm8xxl_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	*((__u8 *)(map->map_priv_1 + adr)) = d;
-}
-
-void tqm8xxl_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	*((__u16 *)( map->map_priv_1 + adr)) = d;
-}
-
-void tqm8xxl_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	*((__u32 *)(map->map_priv_1 + adr)) = d;
-}
-
-void tqm8xxl_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy_toio((void *)(map->map_priv_1 + to), from, len);
-}
-
-struct map_info tqm8xxl_map = {
-	.name		= "TQM8xxL",
-	.buswidth	= 4,
-	.read8		= tqm8xxl_read8,
-	.read16		= tqm8xxl_read16,
-	.read32		= tqm8xxl_read32,
-	.copy_from	= tqm8xxl_copy_from,
-	.write8		= tqm8xxl_write8,
-	.write16	= tqm8xxl_write16,
-	.write32	= tqm8xxl_write32,
-	.copy_to	= tqm8xxl_copy_to
-};
-
 /*
  * Here are partition information for all known TQM8xxL series devices.
  * See include/linux/mtd/partitions.h for definition of the mtd_partition
@@ -120,43 +68,44 @@
 static unsigned long tqm8xxl_max_flash_size = 0x00800000;
 
 /* partition definition for first flash bank
- * also ref. to "drivers\char\flash_config.c" 
+ * (cf. "drivers/char/flash_config.c")
  */
 static struct mtd_partition tqm8xxl_partitions[] = {
 	{
-		.name		= "ppcboot",
-		.offset		= 0x00000000,
-		.size 		= 0x00020000,	/* 128KB */
-		.mask_flags	= MTD_WRITEABLE, /* force read-only */
+	  .name = "ppcboot",
+	  .offset = 0x00000000,
+	  .size = 0x00020000,           /* 128KB           */
+	  .mask_flags = MTD_WRITEABLE,  /* force read-only */
 	},
 	{
-		.name		= "kernel",	/* default kernel image */
-		.offset		= 0x00020000,
-		.size		= 0x000e0000,
-		.mask_flags	= MTD_WRITEABLE, /* force read-only */
+	  .name = "kernel",             /* default kernel image */
+	  .offset = 0x00020000,
+	  .size = 0x000e0000,
+	  .mask_flags = MTD_WRITEABLE,  /* force read-only */
 	},
 	{
-		.name		= "user",
-		.offset		= 0x00100000,
-		.size		= 0x00100000,
+	  .name = "user",
+	  .offset = 0x00100000,
+	  .size = 0x00100000,
 	},
 	{
-		.name		= "initrd",
-		.offset		= 0x00200000,
-		.size		= 0x00200000,
+	  .name = "initrd",
+	  .offset = 0x00200000,
+	  .size = 0x00200000,
 	}
 };
-/* partition definition for second flahs bank */
+/* partition definition for second flash bank */
 static struct mtd_partition tqm8xxl_fs_partitions[] = {
 	{
-		.name	= "cramfs",
-		.offset	= 0x00000000,
-		.size	= 0x00200000,
+	  .name = "cramfs",
+	  .offset = 0x00000000,
+	  .size = 0x00200000,
 	},
 	{
-		.name	= "jffs",
-		.offset	= 0x00200000,
-		.size	= 0x00200000,
+	  .name = "jffs",
+	  .offset = 0x00200000,
+	  .size = 0x00200000,
+	  .//size = MTDPART_SIZ_FULL,
 	}
 };
 #endif
@@ -172,66 +121,73 @@
 
 	flash_addr = bd->bi_flashstart;
 	flash_size = bd->bi_flashsize;
-	//request maximum flash size address spzce
+
+	//request maximum flash size address space
 	start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size);
 	if (!start_scan_addr) {
-		//printk("%s:Failed to ioremap address:0x%x\n", __FUNCTION__, FLASH_ADDR);
-		printk("%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr);
+		printk(KERN_WARNING "%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr);
 		return -EIO;
 	}
-	for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++)
-	{
+
+	for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
 		if(mtd_size >= flash_size)
 			break;
 		
-		printk("%s: chip probing count %d\n", __FUNCTION__, idx);
+		printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx);
 		
 		map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL);
-		if(map_banks[idx] == NULL)
-		{
-			//return -ENOMEM;
+		if(map_banks[idx] == NULL) {
 			ret = -ENOMEM;
+			/* FIXME: What if some MTD devices were probed already? */
 			goto error_mem;
 		}
+
 		memset((void *)map_banks[idx], 0, sizeof(struct map_info));
 		map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL);
-		if(map_banks[idx]->name == NULL)
-		{
-			//return -ENOMEM;
+
+		if (!map_banks[idx]->name) {
 			ret = -ENOMEM;
+			/* FIXME: What if some MTD devices were probed already? */
 			goto error_mem;
 		}
-		memset((void *)map_banks[idx]->name, 0, 16);
-		
 		sprintf(map_banks[idx]->name, "TQM8xxL%d", idx);
+
+		map_banks[idx]->size = flash_size;
 		map_banks[idx]->buswidth = 4;
-		map_banks[idx]->read8 = tqm8xxl_read8;
-		map_banks[idx]->read16 = tqm8xxl_read16;
-		map_banks[idx]->read32 = tqm8xxl_read32;
-		map_banks[idx]->copy_from = tqm8xxl_copy_from;
-		map_banks[idx]->write8 = tqm8xxl_write8;
-		map_banks[idx]->write16 = tqm8xxl_write16;
-		map_banks[idx]->write32 = tqm8xxl_write32;
-		map_banks[idx]->copy_to = tqm8xxl_copy_to;
-		map_banks[idx]->map_priv_1 = 
-		start_scan_addr + ((idx > 0) ? 
+
+		simple_map_init(map_banks[idx]);
+
+		map_banks[idx]->virt = start_scan_addr;
+		map_banks[idx]->phys = flash_addr;
+		/* FIXME: This looks utterly bogus, but I'm trying to
+		   preserve the behaviour of the original (shown here)...
+
+		map_banks[idx]->map_priv_1 =
+		start_scan_addr + ((idx > 0) ?
 		(mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0);
+		*/
+
+		if (idx && mtd_banks[idx-1]) {
+			map_banks[idx]->virt += mtd_banks[idx-1]->size;
+			map_banks[idx]->phys += mtd_banks[idx-1]->size;
+		}
+
 		//start to probe flash chips
 		mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]);
-		if(mtd_banks[idx])
-		{
-			mtd_banks[idx]->module = THIS_MODULE;
+
+		if (mtd_banks[idx]) {
+			mtd_banks[idx]->owner = THIS_MODULE;
 			mtd_size += mtd_banks[idx]->size;
 			num_banks++;
-			printk("%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, 
+
+			printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, 
 			mtd_banks[idx]->name, mtd_banks[idx]->size);
 		}
 	}
 
 	/* no supported flash chips found */
-	if(!num_banks)
-	{
-		printk("TQM8xxL: No support flash chips found!\n");
+	if (!num_banks) {
+		printk(KERN_NOTICE "TQM8xxL: No support flash chips found!\n");
 		ret = -ENXIO;
 		goto error_mem;
 	}
@@ -243,11 +199,12 @@
 	part_banks[0].mtd_part = tqm8xxl_partitions;
 	part_banks[0].type = "Static image";
 	part_banks[0].nums = NB_OF(tqm8xxl_partitions);
+
 	part_banks[1].mtd_part = tqm8xxl_fs_partitions;
 	part_banks[1].type = "Static file system";
 	part_banks[1].nums = NB_OF(tqm8xxl_fs_partitions);
-	for(idx = 0; idx < num_banks ; idx++)
-	{
+
+	for(idx = 0; idx < num_banks ; idx++) {
 		if (part_banks[idx].nums == 0) {
 			printk(KERN_NOTICE "TQM flash%d: no partition info available, registering whole flash at once\n", idx);
 			add_mtd_device(mtd_banks[idx]);
@@ -265,12 +222,9 @@
 #endif
 	return 0;
 error_mem:
-	for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++)
-	{
-		if(map_banks[idx] != NULL)
-		{
-			if(map_banks[idx]->name != NULL)
-			{
+	for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
+		if(map_banks[idx] != NULL) {
+			if(map_banks[idx]->name != NULL) {
 				kfree(map_banks[idx]->name);
 				map_banks[idx]->name = NULL;
 			}
@@ -278,18 +232,15 @@
 			map_banks[idx] = NULL;
 		}
 	}
-	//return -ENOMEM;
 error:
 	iounmap((void *)start_scan_addr);
-	//return -ENXIO;
 	return ret;
 }
 
 static void __exit cleanup_tqm_mtd(void)
 {
 	unsigned int idx = 0;
-	for(idx = 0 ; idx < num_banks ; idx++)
-	{
+	for(idx = 0 ; idx < num_banks ; idx++) {
 		/* destroy mtd_info previously allocated */
 		if (mtd_banks[idx]) {
 			del_mtd_partitions(mtd_banks[idx]);
@@ -299,6 +250,7 @@
 		kfree(map_banks[idx]->name);
 		kfree(map_banks[idx]);
 	}
+
 	if (start_scan_addr) {
 		iounmap((void *)start_scan_addr);
 		start_scan_addr = 0;
diff -Nru a/drivers/mtd/maps/tsunami_flash.c b/drivers/mtd/maps/tsunami_flash.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/tsunami_flash.c	Wed May 28 08:01:22 2003
@@ -0,0 +1,106 @@
+/*
+ * tsunami_flash.c
+ *
+ * flash chip on alpha ds10...
+ * $Id: tsunami_flash.c,v 1.6 2003/05/21 15:15:08 dwmw2 Exp $
+ */
+#include <asm/io.h>
+#include <asm/core_tsunami.h>
+#include <linux/init.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/mtd.h>
+
+#define FLASH_ENABLE_PORT 0x00C00001
+#define FLASH_ENABLE_BYTE 0x01
+#define FLASH_DISABLE_BYTE 0x00
+
+#define MAX_TIG_FLASH_SIZE (12*1024*1024)
+static inline  __u8 tsunami_flash_read8(struct map_info *map, unsigned long offset)
+{
+	return tsunami_tig_readb(offset);
+}
+
+static void tsunami_flash_write8(struct map_info *map, __u8 value, unsigned long offset)
+{
+	tsunami_tig_writeb(value, offset);
+}
+
+static void tsunami_flash_copy_from(
+	struct map_info *map, void *addr, unsigned long offset, ssize_t len)
+{
+	unsigned char *dest;
+	dest = addr;
+	while(len && (offset < MAX_TIG_FLASH_SIZE)) {
+		*dest = tsunami_tig_readb(offset);
+		offset++;
+		dest++;
+		len--;
+	}
+}
+
+static void tsunami_flash_copy_to(
+	struct map_info *map, unsigned long offset, 
+	const void *addr, ssize_t len)
+{
+	const unsigned char *src;
+	src = addr;
+	while(len && (offset < MAX_TIG_FLASH_SIZE)) {
+		tsunami_tig_writeb(*src, offset);
+		offset++;
+		src++;
+		len--;
+	}
+}
+
+/*
+ * Deliberately don't provide operations wider than 8 bits.  I don't
+ * have then and it scares me to think how you could mess up if
+ * you tried to use them.   Buswidth is correctly so I'm safe.
+ */
+static struct map_info tsunami_flash_map = {
+	.name = "flash chip on the Tsunami TIG bus",
+	.size = MAX_TIG_FLASH_SIZE,
+	.phys = NO_XIP;
+	.buswidth = 1,
+	.read8 = tsunami_flash_read8,
+	.copy_from = tsunami_flash_copy_from,
+	.write8 = tsunami_flash_write8,
+	.copy_to = tsunami_flash_copy_to,
+};
+
+static struct mtd_info *tsunami_flash_mtd;
+
+static void __exit  cleanup_tsunami_flash(void)
+{
+	struct mtd_info *mtd;
+	mtd = tsunami_flash_mtd;
+	if (mtd) {
+		del_mtd_device(mtd);
+		map_destroy(mtd);
+	}
+	tsunami_flash_mtd = 0;
+}
+
+
+static int __init init_tsunami_flash(void)
+{
+	static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 };
+	char **type;
+
+	tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT);
+	
+	tsunami_flash_mtd = 0;
+	type = rom_probe_types;
+	for(; !tsunami_flash_mtd && *type; type++) {
+		tsunami_flash_mtd = do_map_probe(*type, &tsunami_flash_map);
+	}
+	if (tsunami_flash_mtd) {
+		tsunami_flash_mtd->owner = THIS_MODULE;
+		add_mtd_device(tsunami_flash_mtd);
+		return 0;
+	}
+	return -ENXIO;
+}
+
+module_init(init_tsunami_flash);
+module_exit(cleanup_tsunami_flash);
diff -Nru a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c
--- a/drivers/mtd/maps/uclinux.c	Wed Feb 26 05:08:58 2003
+++ b/drivers/mtd/maps/uclinux.c	Wed May 28 08:01:04 2003
@@ -4,6 +4,8 @@
  *	uclinux.c -- generic memory mapped MTD driver for uclinux
  *
  *	(C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
+ *
+ * 	$Id: uclinux.c,v 1.5 2003/05/20 20:59:32 dwmw2 Exp $
  */
 
 /****************************************************************************/
@@ -15,7 +17,6 @@
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/major.h>
-#include <linux/root_dev.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
@@ -23,58 +24,11 @@
 
 /****************************************************************************/
 
-__u8 uclinux_read8(struct map_info *map, unsigned long ofs)
-{
-	return(*((__u8 *) (map->map_priv_1 + ofs)));
-}
-
-__u16 uclinux_read16(struct map_info *map, unsigned long ofs)
-{
-	return(*((__u16 *) (map->map_priv_1 + ofs)));
-}
-
-__u32 uclinux_read32(struct map_info *map, unsigned long ofs)
-{
-	return(*((__u32 *) (map->map_priv_1 + ofs)));
-}
-
-void uclinux_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-	memcpy(to, (void *)(map->map_priv_1 + from), len);
-}
-
-void uclinux_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-	*((__u8 *) (map->map_priv_1 + adr)) = d;
-}
-
-void uclinux_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-	*((__u16 *) (map->map_priv_1 + adr)) = d;
-}
-
-void uclinux_write32(struct map_info *map, __u32 d, unsigned long adr)
-{
-	*((__u32 *) (map->map_priv_1 + adr)) = d;
-}
-
-void uclinux_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-	memcpy((void *) (map->map_priv_1 + to), from, len);
-}
 
 /****************************************************************************/
 
 struct map_info uclinux_ram_map = {
-	.name		= "RAM",
-	.read8		= uclinux_read8,
-	.read16		= uclinux_read16,
-	.read32		= uclinux_read32,
-	.copy_from	= uclinux_copy_from,
-	.write8		= uclinux_write8,
-	.write16	= uclinux_write16,
-	.write32	= uclinux_write32,
-	.copy_to	= uclinux_copy_to,
+	.name = "RAM",
 };
 
 struct mtd_info *uclinux_ram_mtdinfo;
@@ -82,7 +36,7 @@
 /****************************************************************************/
 
 struct mtd_partition uclinux_romfs[] = {
-	{ .name = "ROMfs", .offset = 0 }
+	{ .name = "ROMfs" }
 };
 
 #define	NUM_PARTITIONS	(sizeof(uclinux_romfs) / sizeof(uclinux_romfs[0]))
@@ -93,7 +47,7 @@
 	size_t *retlen, u_char **mtdbuf)
 {
 	struct map_info *map = (struct map_info *) mtd->priv;
-	*mtdbuf = (u_char *) (map->map_priv_1 + ((int) from));
+	*mtdbuf = (u_char *) (map->virt + ((int) from));
 	*retlen = len;
 	return(0);
 }
@@ -107,29 +61,31 @@
 	extern char _ebss;
 
 	mapp = &uclinux_ram_map;
-	mapp->map_priv_2 = (unsigned long) &_ebss;
+	mapp->phys = (unsigned long) &_ebss;
 	mapp->size = PAGE_ALIGN(*((unsigned long *)((&_ebss) + 8)));
 	mapp->buswidth = 4;
 
 	printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n",
 	       	(int) mapp->map_priv_2, (int) mapp->size);
 
-	mapp->map_priv_1 = (unsigned long)
-		ioremap_nocache(mapp->map_priv_2, mapp->size);
+	mapp->virt = (unsigned long)
+		ioremap_nocache(mapp->phys, mapp->size);
 
-	if (mapp->map_priv_1 == 0) {
+	if (mapp->virt == 0) {
 		printk("uclinux[mtd]: ioremap_nocache() failed\n");
 		return(-EIO);
 	}
 
+	simple_map_init(mapp);
+
 	mtd = do_map_probe("map_ram", mapp);
 	if (!mtd) {
 		printk("uclinux[mtd]: failed to find a mapping?\n");
-		iounmap((void *) mapp->map_priv_1);
+		iounmap((void *) mapp->virt);
 		return(-ENXIO);
 	}
 		
-	mtd->module = THIS_MODULE;
+	mtd->owner = THIS_MODULE;
 	mtd->point = uclinux_point;
 	mtd->priv = mapp;
 
@@ -137,7 +93,7 @@
 	add_mtd_partitions(mtd, uclinux_romfs, NUM_PARTITIONS);
 
 	printk("uclinux[mtd]: set %s to be root filesystem\n",
-		uclinux_romfs[0].name);
+	     	uclinux_romfs[0].name);
 	ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 0);
 	put_mtd_device(mtd);
 
@@ -154,8 +110,8 @@
 		uclinux_ram_mtdinfo = NULL;
 	}
 	if (uclinux_ram_map.map_priv_1) {
-		iounmap((void *) uclinux_ram_map.map_priv_1);
-		uclinux_ram_map.map_priv_1 = 0;
+		iounmap((void *) uclinux_ram_map.virt);
+		uclinux_ram_map.virt = 0;
 	}
 }
 
diff -Nru a/drivers/mtd/maps/vmax301.c b/drivers/mtd/maps/vmax301.c
--- a/drivers/mtd/maps/vmax301.c	Wed Feb 26 05:16:11 2003
+++ b/drivers/mtd/maps/vmax301.c	Wed May 28 08:01:04 2003
@@ -1,4 +1,4 @@
-// $Id: vmax301.c,v 1.24 2001/10/02 15:05:14 dwmw2 Exp $
+// $Id: vmax301.c,v 1.28 2003/05/21 15:15:08 dwmw2 Exp $
 /* ######################################################################
 
    Tempustech VMAX SBC301 MTD Driver.
@@ -24,6 +24,7 @@
 #include <asm/io.h>
 
 #include <linux/mtd/map.h>
+#include <linux/mtd/mtd.h>
 
 
 #define WINDOW_START 0xd8000
@@ -142,33 +143,36 @@
 
 static struct map_info vmax_map[2] = {
 	{
-		.name		= "VMAX301 Internal Flash",
-		.size		= 3*2*1024*1024,
-		.buswidth	= 1,
-		.read8		= vmax301_read8,
-		.read16		= vmax301_read16,
-		.read32		= vmax301_read32,
-		.copy_from	= vmax301_copy_from,
-		.write8		= vmax301_write8,
-		.write16	= vmax301_write16,
-		.write32	= vmax301_write32,
-		.copy_to	= vmax301_copy_to,
-		.map_priv_1	= WINDOW_START + WINDOW_LENGTH,
-		.map_priv_2	= 0xFFFFFFFF
+		.name = "VMAX301 Internal Flash",
+		.phys = NO_XIP,
+		.size = 3*2*1024*1024,
+		.buswidth = 1,
+		.read8 = vmax301_read8,
+		.read16 = vmax301_read16,
+		.read32 = vmax301_read32,
+		.copy_from = vmax301_copy_from,
+		.write8 = vmax301_write8,
+		.write16 = vmax301_write16,
+		.write32 = vmax301_write32,
+		.copy_to = vmax301_copy_to,
+		.map_priv_1 = WINDOW_START + WINDOW_LENGTH,
+		.map_priv_2 = 0xFFFFFFFF
 	},
 	{
-		.name		= "VMAX301 Socket",
-		.buswidth	= 1,
-		.read8		= vmax301_read8,
-		.read16		= vmax301_read16,
-		.read32		= vmax301_read32,
-		.copy_from	= vmax301_copy_from,
-		.write8		= vmax301_write8,
-		.write16	= vmax301_write16,
-		.write32	= vmax301_write32,
-		.copy_to	= vmax301_copy_to,
-		.map_priv_1	= WINDOW_START + (3*WINDOW_LENGTH),
-		.map_priv_2	= 0xFFFFFFFF
+		.name = "VMAX301 Socket",
+		.phys = NO_XIP,
+		.size = 0,
+		.buswidth = 1,
+		.read8 = vmax301_read8,
+		.read16 = vmax301_read16,
+		.read32 = vmax301_read32,
+		.copy_from = vmax301_copy_from,
+		.write8 = vmax301_write8,
+		.write16 = vmax301_write16,
+		.write32 = vmax301_write32,
+		.copy_to = vmax301_copy_to,
+		.map_priv_1 = WINDOW_START + (3*WINDOW_LENGTH),
+		.map_priv_2 = 0xFFFFFFFF
 	}
 };
 
@@ -205,8 +209,8 @@
 	   address of the first half, because it's used more
 	   often. 
 	*/
-	vmax_map[0].map_priv_1 = iomapadr + WINDOW_START;
-	vmax_map[1].map_priv_1 = iomapadr + (3*WINDOW_START);
+	vmax_map[0].map_priv_2 = iomapadr + WINDOW_START;
+	vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START);
 	
 	for (i=0; i<2; i++) {
 		vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]);
@@ -217,7 +221,7 @@
 		if (!vmax_mtd[i])
 			vmax_mtd[i] = do_map_probe("map_rom", &vmax_map[i]);
 		if (vmax_mtd[i]) {
-			vmax_mtd[i]->module = THIS_MODULE;
+			vmax_mtd[i]->owner = THIS_MODULE;
 			add_mtd_device(vmax_mtd[i]);
 		}
 	}
diff -Nru a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/mtd_blkdevs.c	Wed May 28 08:01:23 2003
@@ -0,0 +1,456 @@
+/*
+ * $Id: mtd_blkdevs.c,v 1.12 2003/05/21 01:00:59 dwmw2 Exp $
+ *
+ * (C) 2003 David Woodhouse <dwmw2@infradead.org>
+ *
+ * Interface to Linux 2.5 block layer for MTD 'translation layers'.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/mtd/blktrans.h>
+#include <linux/mtd/mtd.h>
+#include <linux/blkdev.h>
+#include <linux/blk.h>
+#include <linux/blkpg.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <asm/semaphore.h>
+#include <linux/devfs_fs_kernel.h>
+
+static LIST_HEAD(blktrans_majors);
+
+extern struct semaphore mtd_table_mutex;
+extern struct mtd_info *mtd_table[];
+
+struct mtd_blkcore_priv {
+	struct completion thread_dead;
+	int exiting;
+	wait_queue_head_t thread_wq;
+	struct request_queue rq;
+	spinlock_t queue_lock;
+};
+
+static int do_blktrans_request(struct mtd_blktrans_ops *tr,
+			       struct mtd_blktrans_dev *dev,
+			       struct request *req)
+{
+	unsigned long block, nsect;
+	char *buf;
+
+	block = req->sector;
+	nsect = req->current_nr_sectors;
+	buf = req->buffer;
+
+	if (!req->flags & REQ_CMD)
+		return 0;
+
+	if (block + nsect > get_capacity(req->rq_disk))
+		return 0;
+
+	switch(rq_data_dir(req)) {
+	case READ:
+		for (; nsect > 0; nsect--, block++, buf += 512)
+			if (tr->readsect(dev, block, buf))
+				return 0;
+		return 1;
+
+	case WRITE:
+		if (!tr->writesect)
+			return 0;
+
+		for (; nsect > 0; nsect--, block++, buf += 512)
+			if (tr->writesect(dev, block, buf))
+				return 0;
+		return 1;
+
+	default:
+		printk(KERN_NOTICE "Unknown request %ld\n", rq_data_dir(req));
+		return 0;
+	}
+}
+
+static int mtd_blktrans_thread(void *arg)
+{
+	struct mtd_blktrans_ops *tr = arg;
+	struct request_queue *rq = &tr->blkcore_priv->rq;
+
+	/* we might get involved when memory gets low, so use PF_MEMALLOC */
+	current->flags |= PF_MEMALLOC;
+
+	daemonize("%sd", tr->name);
+
+	/* daemonize() doesn't do this for us since some kernel threads
+	   actually want to deal with signals. We can't just call 
+	   exit_sighand() since that'll cause an oops when we finally
+	   do exit. */
+	spin_lock_irq(&current->sighand->siglock);
+	sigfillset(&current->blocked);
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	while (!tr->blkcore_priv->exiting) {
+		struct request *req;
+		struct mtd_blktrans_dev *dev;
+		int res = 0;
+		DECLARE_WAITQUEUE(wait, current);
+
+		spin_lock_irq(rq->queue_lock);
+
+		req = elv_next_request(rq);
+
+		if (!req) {
+			add_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
+			set_current_state(TASK_INTERRUPTIBLE);
+
+			spin_unlock_irq(rq->queue_lock);
+
+			schedule();
+			remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
+
+			continue;
+		}
+
+		dev = req->rq_disk->private_data;
+		tr = dev->tr;
+
+		spin_unlock_irq(rq->queue_lock);
+
+		down(&dev->sem);
+		res = do_blktrans_request(tr, dev, req);
+		up(&dev->sem);
+
+		spin_lock_irq(rq->queue_lock);
+
+		end_request(req, res);
+	}
+	complete_and_exit(&tr->blkcore_priv->thread_dead, 0);
+}
+
+static void mtd_blktrans_request(struct request_queue *rq)
+{
+	struct mtd_blktrans_ops *tr = rq->queuedata;
+	wake_up(&tr->blkcore_priv->thread_wq);
+}
+
+
+int blktrans_open(struct inode *i, struct file *f)
+{
+	struct mtd_blktrans_dev *dev;
+	struct mtd_blktrans_ops *tr;
+	int ret = -ENODEV;
+
+	dev = i->i_bdev->bd_disk->private_data;
+	tr = dev->tr;
+
+	if (!try_module_get(dev->mtd->owner))
+		goto out;
+
+	if (!try_module_get(tr->owner))
+		goto out_tr;
+
+	/* FIXME: Locking. A hot pluggable device can go away 
+	   (del_mtd_device can be called for it) without its module
+	   being unloaded. */
+	dev->mtd->usecount++;
+
+	ret = 0;
+	if (tr->open && (ret = tr->open(dev, i, f))) {
+		dev->mtd->usecount--;
+		module_put(dev->mtd->owner);
+	out_tr:
+		module_put(tr->owner);
+	}
+ out:
+	return ret;
+}
+
+int blktrans_release(struct inode *i, struct file *f)
+{
+	struct mtd_blktrans_dev *dev;
+	struct mtd_blktrans_ops *tr;
+	int ret = 0;
+
+	dev = i->i_bdev->bd_disk->private_data;
+	tr = dev->tr;
+
+	if (tr->release)
+		ret = tr->release(dev, i, f);
+
+	if (!ret) {
+		dev->mtd->usecount--;
+		module_put(dev->mtd->owner);
+		module_put(tr->owner);
+	}
+
+	return ret;
+}
+
+
+static int blktrans_ioctl(struct inode *inode, struct file *file, 
+			      unsigned int cmd, unsigned long arg)
+{
+	struct mtd_blktrans_dev *dev;
+	struct mtd_blktrans_ops *tr;
+	int ret = -ENOTTY;
+
+	dev = inode->i_bdev->bd_disk->private_data;
+	tr = dev->tr;
+
+	if (tr->ioctl)
+		ret = tr->ioctl(dev, inode, file, cmd, arg);
+
+	if (ret == -ENOTTY && (cmd == BLKROSET || cmd == BLKFLSBUF)) {
+		/* The core code did the work, we had nothing to do. */
+		ret = 0;
+	}
+	return ret;
+}
+
+struct block_device_operations mtd_blktrans_ops = {
+	.owner		= THIS_MODULE,
+	.open		= blktrans_open,
+	.release	= blktrans_release,
+	.ioctl		= blktrans_ioctl,
+};
+
+int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
+{
+	struct mtd_blktrans_ops *tr = new->tr;
+	struct list_head *this;
+	int last_devnum = -1;
+	struct gendisk *gd;
+
+	if (!down_trylock(&mtd_table_mutex)) {
+		up(&mtd_table_mutex);
+		BUG();
+	}
+
+	list_for_each(this, &tr->devs) {
+		struct mtd_blktrans_dev *d = list_entry(this, struct mtd_blktrans_dev, list);
+		if (new->devnum == -1) {
+			/* Use first free number */
+			if (d->devnum != last_devnum+1) {
+				/* Found a free devnum. Plug it in here */
+				new->devnum = last_devnum+1;
+				list_add_tail(&new->list, &d->list);
+				goto added;
+			}
+		} else if (d->devnum == new->devnum) {
+			/* Required number taken */
+			return -EBUSY;
+		} else if (d->devnum > new->devnum) {
+			/* Required number was free */
+			list_add_tail(&new->list, &d->list);
+			goto added;
+		} 
+		last_devnum = d->devnum;
+	}
+	if (new->devnum == -1)
+		new->devnum = last_devnum+1;
+
+	if ((new->devnum << tr->part_bits) > 256) {
+		return -EBUSY;
+	}
+
+	init_MUTEX(&new->sem);
+	list_add_tail(&new->list, &tr->devs);
+ added:
+	if (!tr->writesect)
+		new->readonly = 1;
+
+	gd = alloc_disk(1 << tr->part_bits);
+	if (!gd) {
+		list_del(&new->list);
+		return -ENOMEM;
+	}
+	gd->major = tr->major;
+	gd->first_minor = (new->devnum) << tr->part_bits;
+	gd->fops = &mtd_blktrans_ops;
+	
+	snprintf(gd->disk_name, sizeof(gd->disk_name),
+		 "%s%c", tr->name, (tr->part_bits?'a':'0') + new->devnum);
+	snprintf(gd->devfs_name, sizeof(gd->devfs_name),
+		 "%s/%c", tr->name, (tr->part_bits?'a':'0') + new->devnum);
+
+	set_capacity(gd, new->size);
+	gd->private_data = new;
+	new->blkcore_priv = gd;
+	gd->queue = &tr->blkcore_priv->rq;
+
+	if (new->readonly)
+		set_disk_ro(gd, 1);
+
+	add_disk(gd);
+	
+	return 0;
+}
+
+int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
+{
+	if (!down_trylock(&mtd_table_mutex)) {
+		up(&mtd_table_mutex);
+		BUG();
+	}
+
+	list_del(&old->list);
+
+	del_gendisk(old->blkcore_priv);
+	put_disk(old->blkcore_priv);
+		
+	return 0;
+}
+
+void blktrans_notify_remove(struct mtd_info *mtd)
+{
+	struct list_head *this, *this2, *next;
+
+	list_for_each(this, &blktrans_majors) {
+		struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
+
+		list_for_each_safe(this2, next, &tr->devs) {
+			struct mtd_blktrans_dev *dev = list_entry(this2, struct mtd_blktrans_dev, list);
+
+			if (dev->mtd == mtd)
+				tr->remove_dev(dev);
+		}
+	}
+}
+
+void blktrans_notify_add(struct mtd_info *mtd)
+{
+	struct list_head *this;
+
+	if (mtd->type == MTD_ABSENT)
+		return;
+
+	printk("%s:%s %d: count %d\n", __FILE__, __func__, __LINE__, atomic_read(&mtd_table_mutex.count));
+
+	list_for_each(this, &blktrans_majors) {
+		struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
+
+		tr->add_mtd(tr, mtd);
+	}
+
+}
+
+static struct mtd_notifier blktrans_notifier = {
+	.add = blktrans_notify_add,
+	.remove = blktrans_notify_remove,
+};
+      
+int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
+{
+	int ret, i;
+
+	/* Register the notifier if/when the first device type is 
+	   registered, to prevent the link/init ordering from fucking
+	   us over. */
+	if (!blktrans_notifier.list.next)
+		register_mtd_user(&blktrans_notifier);
+
+	tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);
+	if (!tr->blkcore_priv)
+		return -ENOMEM;
+
+	memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv));
+
+	down(&mtd_table_mutex);
+
+	ret = register_blkdev(tr->major, tr->name);
+	if (ret) {
+		printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n",
+		       tr->name, tr->major, ret);
+		kfree(tr->blkcore_priv);
+		up(&mtd_table_mutex);
+		return ret;
+	}
+	spin_lock_init(&tr->blkcore_priv->queue_lock);
+	init_completion(&tr->blkcore_priv->thread_dead);
+	init_waitqueue_head(&tr->blkcore_priv->thread_wq);
+
+	blk_init_queue(&tr->blkcore_priv->rq, mtd_blktrans_request, 
+		       &tr->blkcore_priv->queue_lock);
+	tr->blkcore_priv->rq.queuedata = tr;
+
+	ret = kernel_thread(mtd_blktrans_thread, tr, 
+			    CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
+	if (ret < 0) {
+		blk_cleanup_queue(&tr->blkcore_priv->rq);
+		unregister_blkdev(tr->major, tr->name);
+		kfree(tr->blkcore_priv);
+		up(&mtd_table_mutex);
+		return ret;
+	} 
+
+	devfs_mk_dir(tr->name);
+
+	INIT_LIST_HEAD(&tr->devs);
+	list_add(&tr->list, &blktrans_majors);
+
+	printk("%s:%s %d: count %d\n", __FILE__, __func__, __LINE__, atomic_read(&mtd_table_mutex.count));
+
+	for (i=0; i<MAX_MTD_DEVICES; i++) {
+		if (mtd_table[i] && mtd_table[i]->type != MTD_ABSENT)
+			tr->add_mtd(tr, mtd_table[i]);
+	}
+
+	up(&mtd_table_mutex);
+
+	return 0;
+}
+
+int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr)
+{
+	struct list_head *this, *next;
+
+	down(&mtd_table_mutex);
+
+	/* Clean up the kernel thread */
+	tr->blkcore_priv->exiting = 1;
+	wake_up(&tr->blkcore_priv->thread_wq);
+	wait_for_completion(&tr->blkcore_priv->thread_dead);
+
+	/* Remove it from the list of active majors */
+	list_del(&tr->list);
+
+	list_for_each_safe(this, next, &tr->devs) {
+		struct mtd_blktrans_dev *dev = list_entry(this, struct mtd_blktrans_dev, list);
+		tr->remove_dev(dev);
+	}
+
+	devfs_remove(tr->name);
+	blk_cleanup_queue(&tr->blkcore_priv->rq);
+	unregister_blkdev(tr->major, tr->name);
+
+	up(&mtd_table_mutex);
+
+	kfree(tr->blkcore_priv);
+
+	if (!list_empty(&tr->devs))
+		BUG();
+	return 0;
+}
+
+static void __exit mtd_blktrans_exit(void)
+{
+	/* No race here -- if someone's currently in register_mtd_blktrans
+	   we're screwed anyway. */
+	if (blktrans_notifier.list.next)
+		unregister_mtd_user(&blktrans_notifier);
+}
+
+module_exit(mtd_blktrans_exit);
+
+EXPORT_SYMBOL_GPL(register_mtd_blktrans);
+EXPORT_SYMBOL_GPL(deregister_mtd_blktrans);
+EXPORT_SYMBOL_GPL(add_mtd_blktrans_dev);
+EXPORT_SYMBOL_GPL(del_mtd_blktrans_dev);
+
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Common interface to block layer for MTD 'translation layers'");
diff -Nru a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
--- a/drivers/mtd/mtdblock.c	Sun Apr 20 16:21:18 2003
+++ b/drivers/mtd/mtdblock.c	Wed May 28 08:01:04 2003
@@ -1,37 +1,25 @@
 /* 
  * Direct MTD block device access
  *
- * $Id: mtdblock.c,v 1.47 2001/10/02 15:05:11 dwmw2 Exp $
+ * $Id: mtdblock.c,v 1.61 2003/05/21 10:49:38 dwmw2 Exp $
  *
- * 02-nov-2000	Nicolas Pitre		Added read-modify-write with cache
+ * (C) 2000-2003 Nicolas Pitre <nico@cam.org>
+ * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
  */
 
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/buffer_head.h>
+#include <linux/vmalloc.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/compatmac.h>
-#include <linux/buffer_head.h>
-
-#define MAJOR_NR MTD_BLOCK_MAJOR
-#define DEVICE_NAME "mtdblock"
-#define DEVICE_NR(device) (device)
-#include <linux/blk.h>
-#include <linux/devfs_fs_kernel.h>
-
-static void mtd_notify_add(struct mtd_info* mtd);
-static void mtd_notify_remove(struct mtd_info* mtd);
-static struct mtd_notifier notifier = {
-        mtd_notify_add,
-        mtd_notify_remove,
-        NULL
-};
+#include <linux/mtd/blktrans.h>
 
 static struct mtdblk_dev {
-	struct mtd_info *mtd; /* Locked */
+	struct mtd_info *mtd;
 	int count;
 	struct semaphore cache_sem;
 	unsigned char *cache_data;
@@ -40,10 +28,6 @@
 	enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
 } *mtdblks[MAX_MTD_DEVICES];
 
-static struct gendisk *mtddisk[MAX_MTD_DEVICES];
-
-static spinlock_t mtdblks_lock;
-
 /*
  * Cache stuff...
  * 
@@ -127,7 +111,7 @@
 		return ret;
 
 	/*
-	 * Here we could argably set the cache state to STATE_CLEAN.
+	 * Here we could argubly set the cache state to STATE_CLEAN.
 	 * However this could lead to inconsistency since we will not 
 	 * be notified if this content is altered on the flash by other 
 	 * means.  Let's declare it empty and leave buffering tasks to
@@ -253,48 +237,39 @@
 	return 0;
 }
 
-static struct block_device_operations mtd_fops;
+static int mtdblock_readsect(struct mtd_blktrans_dev *dev,
+			      unsigned long block, char *buf)
+{
+	struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
+	return do_cached_read(mtdblk, block<<9, 512, buf);
+}
+
+static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
+			      unsigned long block, char *buf)
+{
+	struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
+	return do_cached_write(mtdblk, block<<9, 512, buf);
+}
 
-static int mtdblock_open(struct inode *inode, struct file *file)
+static int mtdblock_open(struct mtd_blktrans_dev *mbd, 
+			 struct inode *inode, struct file *file)
 {
 	struct mtdblk_dev *mtdblk;
-	struct mtd_info *mtd;
-	int dev = minor(inode->i_rdev);
-	struct gendisk *disk;
+	struct mtd_info *mtd = mbd->mtd;
+	int dev = mbd->devnum;
 
 	DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
-
-	if (dev >= MAX_MTD_DEVICES)
-		return -EINVAL;
-
-	mtd = get_mtd_device(NULL, dev);
-	if (!mtd)
-		return -ENODEV;
-	if (MTD_ABSENT == mtd->type) {
-		put_mtd_device(mtd);
-		return -ENODEV;
-	}
 	
-	spin_lock(&mtdblks_lock);
-
-	/* If it's already open, no need to piss about. */
 	if (mtdblks[dev]) {
 		mtdblks[dev]->count++;
-		spin_unlock(&mtdblks_lock);
 		return 0;
 	}
 	
-	/* OK, it's not open. Try to find it */
-
-	/* First we have to drop the lock, because we have to
-	   to things which might sleep.
-	*/
-	spin_unlock(&mtdblks_lock);
-
+	/* OK, it's not open. Create cache info for it */
 	mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
-	disk = mtddisk[dev];
-	if (!mtdblk || !disk)
-		goto Enomem;
+	if (!mtdblks)
+		return -ENOMEM;
+
 	memset(mtdblk, 0, sizeof(*mtdblk));
 	mtdblk->count = 1;
 	mtdblk->mtd = mtd;
@@ -305,46 +280,26 @@
 	    mtdblk->mtd->erasesize) {
 		mtdblk->cache_size = mtdblk->mtd->erasesize;
 		mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);
-		if (!mtdblk->cache_data)
-			goto Enomem;
-	}
-
-	/* OK, we've created a new one. Add it to the list. */
-
-	spin_lock(&mtdblks_lock);
-
-	if (mtdblks[dev]) {
-		/* Another CPU made one at the same time as us. */
-		mtdblks[dev]->count++;
-		spin_unlock(&mtdblks_lock);
-		put_mtd_device(mtdblk->mtd);
-		vfree(mtdblk->cache_data);
-		kfree(mtdblk);
-		return 0;
+		if (!mtdblk->cache_data) {
+			kfree(mtdblk);
+			return -ENOMEM;
+		}
 	}
 
 	mtdblks[dev] = mtdblk;
-	set_device_ro(inode->i_bdev, !(mtdblk->mtd->flags & MTD_WRITEABLE));
-
-	spin_unlock(&mtdblks_lock);
-
+	
 	DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
 
 	return 0;
-Enomem:
-	put_mtd_device(mtd);
-	kfree(mtdblk);
-	return -ENOMEM;
 }
 
-static release_t mtdblock_release(struct inode *inode, struct file *file)
+static int mtdblock_release(struct mtd_blktrans_dev *mbd,
+				  struct inode *inode, struct file *file)
 {
 	int dev;
 	struct mtdblk_dev *mtdblk;
-   	DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
 
-	if (inode == NULL)
-		release_return(-ENODEV);
+   	DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
 
 	dev = minor(inode->i_rdev);
 	mtdblk = mtdblks[dev];
@@ -353,149 +308,30 @@
 	write_cached_data(mtdblk);
 	up(&mtdblk->cache_sem);
 
-	spin_lock(&mtdblks_lock);
 	if (!--mtdblk->count) {
 		/* It was the last usage. Free the device */
 		mtdblks[dev] = NULL;
-		spin_unlock(&mtdblks_lock);
 		if (mtdblk->mtd->sync)
 			mtdblk->mtd->sync(mtdblk->mtd);
-		put_mtd_device(mtdblk->mtd);
 		vfree(mtdblk->cache_data);
 		kfree(mtdblk);
-	} else {
-		spin_unlock(&mtdblks_lock);
 	}
-
 	DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
 
-	release_return(0);
-}  
-
-
-/* 
- * This is a special request_fn because it is executed in a process context 
- * to be able to sleep independently of the caller.  The queue_lock 
- * is held upon entry and exit.
- * The head of our request queue is considered active so there is no need 
- * to dequeue requests before we are done.
- */
-static struct request_queue mtd_queue;
-static void handle_mtdblock_request(void)
-{
-	struct request *req;
-	struct mtdblk_dev *mtdblk;
-	unsigned int res;
-
-	while ((req = elv_next_request(&mtd_queue)) != NULL) {
-		struct mtdblk_dev **p = req->rq_disk->private_data;
-		spin_unlock_irq(mtd_queue.queue_lock);
-		mtdblk = *p;
-		res = 0;
-
-		if (! (req->flags & REQ_CMD))
-			goto end_req;
-
-		if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9))
-			goto end_req;
-
-		// Handle the request
-		switch (rq_data_dir(req))
-		{
-			int err;
-
-			case READ:
-			down(&mtdblk->cache_sem);
-			err = do_cached_read (mtdblk, req->sector << 9, 
-					req->current_nr_sectors << 9,
-					req->buffer);
-			up(&mtdblk->cache_sem);
-			if (!err)
-				res = 1;
-			break;
-
-			case WRITE:
-			// Read only device
-			if ( !(mtdblk->mtd->flags & MTD_WRITEABLE) ) 
-				break;
-
-			// Do the write
-			down(&mtdblk->cache_sem);
-			err = do_cached_write (mtdblk, req->sector << 9,
-					req->current_nr_sectors << 9, 
-					req->buffer);
-			up(&mtdblk->cache_sem);
-			if (!err)
-				res = 1;
-			break;
-		}
-
-end_req:
-		spin_lock_irq(mtd_queue.queue_lock);
-		if (!end_that_request_first(req, res, req->hard_cur_sectors)) {
-			blkdev_dequeue_request(req);
-			end_that_request_last(req);
-		}
-
-	}
-}
-
-static volatile int leaving = 0;
-static DECLARE_MUTEX_LOCKED(thread_sem);
-static DECLARE_WAIT_QUEUE_HEAD(thr_wq);
-
-int mtdblock_thread(void *dummy)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	/* we might get involved when memory gets low, so use PF_MEMALLOC */
-	tsk->flags |= PF_MEMALLOC;
-	daemonize("mtdblockd");
-
-	while (!leaving) {
-		add_wait_queue(&thr_wq, &wait);
-		set_current_state(TASK_INTERRUPTIBLE);
-		spin_lock_irq(mtd_queue.queue_lock);
-		if (!elv_next_request(&mtd_queue) || blk_queue_plugged(&mtd_queue)) {
-			spin_unlock_irq(mtd_queue.queue_lock);
-			schedule();
-			remove_wait_queue(&thr_wq, &wait); 
-		} else {
-			remove_wait_queue(&thr_wq, &wait); 
-			set_current_state(TASK_RUNNING);
-			handle_mtdblock_request();
-			spin_unlock_irq(mtd_queue.queue_lock);
-		}
-	}
-
-	up(&thread_sem);
 	return 0;
-}
-
-static void mtdblock_request(struct request_queue *q)
-{
-	/* Don't do anything, except wake the thread if necessary */
-	wake_up(&thr_wq);
-}
+}  
 
 
-static int mtdblock_ioctl(struct inode * inode, struct file * file,
-		      unsigned int cmd, unsigned long arg)
+static int mtdblock_ioctl(struct mtd_blktrans_dev *dev, 
+			  struct inode * inode, struct file * file,
+			  unsigned int cmd, unsigned long arg)
 {
 	struct mtdblk_dev *mtdblk;
 
 	mtdblk = mtdblks[minor(inode->i_rdev)];
 
-#ifdef PARANOIA
-	if (!mtdblk)
-		BUG();
-#endif
-
 	switch (cmd) {
 	case BLKFLSBUF:
-		fsync_bdev(inode->i_bdev);
-		invalidate_bdev(inode->i_bdev, 0);
 		down(&mtdblk->cache_sem);
 		write_cached_data(mtdblk);
 		up(&mtdblk->cache_sem);
@@ -504,90 +340,59 @@
 		return 0;
 
 	default:
-		return -EINVAL;
+		return -ENOTTY;
 	}
 }
 
-static struct block_device_operations mtd_fops = 
+static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 {
-	.owner		= THIS_MODULE,
-	.open		= mtdblock_open,
-	.release	= mtdblock_release,
-	.ioctl		= mtdblock_ioctl
-};
+	struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
 
-/* Notification that a new device has been added. Create the devfs entry for
- * it. */
+	if (!dev)
+		return;
 
-static void mtd_notify_add(struct mtd_info* mtd)
-{
-	struct gendisk *disk;
-        char name[16];
-
-        if (!mtd || mtd->type == MTD_ABSENT)
-                return;
+	memset(dev, 0, sizeof(*dev));
 
-	disk = alloc_disk(1);
-	if (disk) {
-		disk->major = MAJOR_NR;
-		disk->first_minor = mtd->index;
-		disk->fops = &mtd_fops;
+	dev->mtd = mtd;
+	dev->devnum = mtd->index;
+	dev->blksize = 512;
+	dev->size = mtd->size >> 9;
+	dev->tr = tr;
 
-		sprintf(disk->disk_name, "mtdblock%d", mtd->index);
-		sprintf(disk->devfs_name, "mtdblock/%d", mtd->index);
+	if (!(mtd->flags & MTD_WRITEABLE))
+		dev->readonly = 1;
 
-		mtddisk[mtd->index] = disk;
-		set_capacity(disk, mtd->size / 512);
-		disk->private_data = &mtdblks[mtd->index];
-		disk->queue = &mtd_queue;
-
-		add_disk(disk);
-	}
+	add_mtd_blktrans_dev(dev);
 }
 
-static void mtd_notify_remove(struct mtd_info* mtd)
+static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev)
 {
-        if (!mtd || mtd->type == MTD_ABSENT)
-                return;
-
-        if (mtddisk[mtd->index]) {
-		del_gendisk(mtddisk[mtd->index]);
-        	put_disk(mtddisk[mtd->index]);
-        	mtddisk[mtd->index] = NULL;
-        }
+	del_mtd_blktrans_dev(dev);
+	kfree(dev);
 }
 
-static spinlock_t mtddev_lock = SPIN_LOCK_UNLOCKED;
+struct mtd_blktrans_ops mtdblock_tr = {
+	.name		= "mtdblock",
+	.major		= 31,
+	.part_bits	= 0,
+	.open		= mtdblock_open,
+	.ioctl		= mtdblock_ioctl,
+	.release	= mtdblock_release,
+	.readsect	= mtdblock_readsect,
+	.writesect	= mtdblock_writesect,
+	.add_mtd	= mtdblock_add_mtd,
+	.remove_dev	= mtdblock_remove_dev,
+	.owner		= THIS_MODULE,
+};
 
 int __init init_mtdblock(void)
 {
-	spin_lock_init(&mtdblks_lock);
-
-	if (register_blkdev(MAJOR_NR, DEVICE_NAME))
-		return -EAGAIN;
-
-#ifdef CONFIG_DEVFS_FS
-	devfs_mk_dir(DEVICE_NAME);
-#endif
-	register_mtd_user(&notifier);
-	
-	init_waitqueue_head(&thr_wq);
-	blk_init_queue(&mtd_queue, &mtdblock_request, &mtddev_lock);
-	kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
-	return 0;
+	return register_mtd_blktrans(&mtdblock_tr);
 }
 
 static void __exit cleanup_mtdblock(void)
 {
-	leaving = 1;
-	wake_up(&thr_wq);
-	down(&thread_sem);
-	unregister_mtd_user(&notifier);
-#ifdef CONFIG_DEVFS_FS
-	devfs_remove(DEVICE_NAME);
-#endif
-	unregister_blkdev(MAJOR_NR,DEVICE_NAME);
-	blk_cleanup_queue(&mtd_queue);
+	deregister_mtd_blktrans(&mtdblock_tr);
 }
 
 module_init(init_mtdblock);
diff -Nru a/drivers/mtd/mtdblock.h b/drivers/mtd/mtdblock.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/mtdblock.h	Wed May 28 08:01:23 2003
@@ -0,0 +1,35 @@
+/*
+ * drivers/mtd/mtdblock.h
+ *
+ * common defines for mtdblock-core and mtdblock-2x
+ *
+ * $Id: mtdblock.h,v 1.1 2002/11/27 10:33:37 gleixner Exp $
+ *
+ */
+
+#ifndef __MTD_MTDBLOCK_H__
+#define __MTD_MTDBLOCK_H__
+
+#define MAJOR_NR MTD_BLOCK_MAJOR
+#define DEVICE_NAME "mtdblock"
+
+struct mtdblk_dev {
+	struct mtd_info *mtd; /* Locked */
+	int count;
+	struct semaphore cache_sem;
+	unsigned char *cache_data;
+	unsigned long cache_offset;
+	unsigned int cache_size;
+	enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
+}; 
+
+extern int write_cached_data (struct mtdblk_dev *mtdblk);
+extern int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, 
+			    int len, const char *buf);
+extern int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, 
+			   int len, char *buf);
+
+extern void __exit cleanup_mtdblock(void);
+extern int __init init_mtdblock(void);
+
+#endif
diff -Nru a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c
--- a/drivers/mtd/mtdblock_ro.c	Sun Apr 20 16:21:18 2003
+++ b/drivers/mtd/mtdblock_ro.c	Wed May 28 08:01:05 2003
@@ -1,265 +1,86 @@
 /*
- * $Id: mtdblock_ro.c,v 1.13 2002/03/11 16:03:29 sioux Exp $
+ * $Id: mtdblock_ro.c,v 1.17 2003/05/18 19:27:27 dwmw2 Exp $
  *
- * Read-only flash, read-write RAM version of the mtdblock device,
- * without caching.
+ * (C) 2003 David Woodhouse <dwmw2@infradead.org>
+ *
+ * Simple read-only (writable only for RAM) mtdblock driver
  */
 
-#ifdef MTDBLOCK_DEBUG
-#define DEBUGLVL debug
-#endif							       
-
-
-#include <linux/module.h>
-#include <linux/types.h>
-
+#include <linux/slab.h>
 #include <linux/mtd/mtd.h>
-#include <linux/mtd/compatmac.h>
-#include <linux/buffer_head.h>
-#include <linux/genhd.h>
-
-#define MAJOR_NR MTD_BLOCK_MAJOR
-#define DEVICE_NAME "mtdblock"
-#include <linux/blk.h>
-
-#ifdef MTDBLOCK_DEBUG
-static int debug = MTDBLOCK_DEBUG;
-MODULE_PARM(debug, "i");
-#endif
-
-struct mtdro_dev {
-	struct gendisk *disk;
-	struct mtd_info *mtd;
-	int open;
-};
+#include <linux/mtd/blktrans.h>
 
-static struct mtdro_dev mtd_dev[MAX_MTD_DEVICES];
-static DECLARE_MUTEX(mtd_sem);
-
-static struct request_queue mtdro_queue;
-static spinlock_t mtdro_lock = SPIN_LOCK_UNLOCKED;
-
-static int mtdblock_open(struct inode *inode, struct file *file)
+static int mtdblock_readsect(struct mtd_blktrans_dev *dev,
+			      unsigned long block, char *buf)
 {
-	struct mtdro_dev *mdev = inode->i_bdev->bd_disk->private_data;
-	int ret = 0;
-
-	DEBUG(1,"mtdblock_open\n");
-
-	down(&mtd_sem);
-	if (mdev->mtd == NULL) {
-		mdev->mtd = get_mtd_device(NULL, minor(inode->i_rdev));
-		if (!mdev->mtd || mdev->mtd->type == MTD_ABSENT) {
-			if (mdev->mtd)
-				put_mtd_device(mdev->mtd);
-			ret = -ENODEV;
-		}
-	}
-
-	if (ret == 0) {
-		set_device_ro(inode->i_bdev, !(mdev->mtd->flags & MTD_CAP_RAM));
-		mdev->open++;
-	}
-	up(&mtd_sem);
-
-	DEBUG(1, "%s\n", ret ? "ok" : "nodev");
+	size_t retlen;
 
-	return ret;
+	if (dev->mtd->read(dev->mtd, (block * 512), 512, &retlen, buf))
+		return 1;
+	return 0;
 }
 
-static release_t mtdblock_release(struct inode *inode, struct file *file)
+static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
+			      unsigned long block, char *buf)
 {
-	struct mtdro_dev *mdev = inode->i_bdev->bd_disk->private_data;
-
-   	DEBUG(1, "mtdblock_release\n");
-
-   	down(&mtd_sem);
-   	if (mdev->open-- == 0) {
-		struct mtd_info *mtd = mdev->mtd;
-
-		mdev->mtd = NULL;
-		if (mtd->sync)
-			mtd->sync(mtd);
-
-		put_mtd_device(mtd);
-	}
-	up(&mtd_sem);
+	size_t retlen;
 
-	DEBUG(1, "ok\n");
-
-	release_return(0);
-}
-
-static void mtdblock_request(request_queue_t *q)
-{
-	struct request *req;
-	
-	while ((req = elv_next_request(q)) != NULL) {
-		struct mtdro_dev *mdev = req->rq_disk->private_data;
-		struct mtd_info *mtd = mdev->mtd;
-		unsigned int res;
-
-		if (!(req->flags & REQ_CMD)) {
-			res = 0;
-			goto end_req;
-		}
-
-		if ((req->sector + req->current_nr_sectors) > (mtd->size >> 9)) {
-			printk("mtd: Attempt to read past end of device!\n");
-			printk("size: %x, sector: %lx, nr_sectors: %x\n",
-				mtd->size, req->sector, req->current_nr_sectors);
-			res = 0;
-			goto end_req;
-		}
-      
-		/* Now drop the lock that the ll_rw_blk functions grabbed for
-		   us and process the request. This is necessary due to the
-		   extreme time we spend processing it. */
-		spin_unlock_irq(q->queue_lock);
-
-		/* Handle the request */
-		switch (rq_data_dir(req)) {
-			size_t retlen;
-
-			case READ:
-				if (MTD_READ(mtd, req->sector << 9,
-					     req->current_nr_sectors << 9, 
-					     &retlen, req->buffer) == 0)
-					res = 1;
-				else
-					res = 0;
-				break;
-
-			case WRITE:
-				/* printk("mtdblock_request WRITE sector=%d(%d)\n",
-					req->sector, req->current_nr_sectors);
-				 */
-
-				/* Read only device */
-				if ((mtd->flags & MTD_CAP_RAM) == 0) {
-					res = 0;
-					break;
-				}
-
-				/* Do the write */
-				if (MTD_WRITE(mtd, req->sector << 9, 
-					      req->current_nr_sectors << 9, 
-					      &retlen, req->buffer) == 0)
-					res = 1;
-				else
-					res = 0;
-				break;
-
-			/* Shouldn't happen */
-			default:
-				printk("mtd: unknown request\n");
-				res = 0;
-				break;
-		}
-
-		/* Grab the lock and re-thread the item onto the linked list */
-		spin_lock_irq(q->queue_lock);
- end_req:
-		if (!end_that_request_first(req, res, req->hard_cur_sectors)) {
-			blkdev_dequeue_request(req);
-			end_that_request_last(req);
-		}
-	}
+	if (dev->mtd->write(dev->mtd, (block * 512), 512, &retlen, buf))
+		return 1;
+	return 0;
 }
 
-static int mtdblock_ioctl(struct inode * inode, struct file * file,
-		      unsigned int cmd, unsigned long arg)
+static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 {
-	struct mtdro_dev *mdev = inode->i_bdev->bd_disk->private_data;
-
-	if (cmd != BLKFLSBUF)
-		return -EINVAL;
-
-	fsync_bdev(inode->i_bdev);
-	invalidate_bdev(inode->i_bdev, 0);
-	if (mdev->mtd->sync)
-		mdev->mtd->sync(mdev->mtd);
+	struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
 
-	return 0;
-}
+	if (!dev)
+		return;
 
-static struct block_device_operations mtd_fops = {
-	.owner		= THIS_MODULE,
-	.open		= mtdblock_open,
-	.release	= mtdblock_release,
-	.ioctl		= mtdblock_ioctl
-};
-
-/* Called with mtd_table_mutex held. */
-static void mtd_notify_add(struct mtd_info* mtd)
-{
-	struct gendisk *disk;
+	memset(dev, 0, sizeof(*dev));
 
-        if (!mtd || mtd->type == MTD_ABSENT || mtd->index >= MAX_MTD_DEVICES)
-                return;
+	dev->mtd = mtd;
+	dev->devnum = mtd->index;
+	dev->blksize = 512;
+	dev->size = mtd->size >> 9;
+	dev->tr = tr;
+	if ((mtd->flags & (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEABLE)) !=
+	    (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEABLE))
+		dev->readonly = 1;
 
-	disk = alloc_disk(1);
-	if (disk) {
-		disk->major = MAJOR_NR;
-		disk->first_minor = mtd->index;
-		disk->fops = &mtd_fops;
-		sprintf(disk->disk_name, "mtdblock%d", mtd->index);
-
-		mtd_dev[mtd->index].disk = disk;
-		set_capacity(disk, mtd->size / 512);
-		disk->queue = &mtdro_queue;
-		disk->private_data = &mtd_dev[mtd->index];
-		add_disk(disk);
-	}
+	add_mtd_blktrans_dev(dev);
 }
 
-/* Called with mtd_table_mutex held. */
-static void mtd_notify_remove(struct mtd_info* mtd)
+static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev)
 {
-	struct mtdro_dev *mdev;
-	struct gendisk *disk;
-
-        if (!mtd || mtd->type == MTD_ABSENT || mtd->index >= MAX_MTD_DEVICES)
-                return;
-
-	mdev = &mtd_dev[mtd->index];
-
-	disk = mdev->disk;
-	mdev->disk = NULL;
-
-	if (disk) {
-		del_gendisk(disk);
-        	put_disk(disk);
-        }
+	del_mtd_blktrans_dev(dev);
+	kfree(dev);
 }
 
-static struct mtd_notifier notifier = {
-	.add	= mtd_notify_add,
-        .remove	= mtd_notify_remove,
+struct mtd_blktrans_ops mtdblock_tr = {
+	.name		= "mtdblock",
+	.major		= 31,
+	.part_bits	= 0,
+	.readsect	= mtdblock_readsect,
+	.writesect	= mtdblock_writesect,
+	.add_mtd	= mtdblock_add_mtd,
+	.remove_dev	= mtdblock_remove_dev,
+	.owner		= THIS_MODULE,
 };
 
-int __init init_mtdblock(void)
+static int __init mtdblock_init(void)
 {
-	if (register_blkdev(MAJOR_NR, DEVICE_NAME))
-		return -EAGAIN;
-
-	blk_init_queue(&mtdro_queue, &mtdblock_request, &mtdro_lock);
-	register_mtd_user(&notifier);
-
-	return 0;
+	return register_mtd_blktrans(&mtdblock_tr);
 }
 
-static void __exit cleanup_mtdblock(void)
+static void __exit mtdblock_exit(void)
 {
-	unregister_mtd_user(&notifier);
-	unregister_blkdev(MAJOR_NR,DEVICE_NAME);
-	blk_cleanup_queue(&mtdro_queue);
+	deregister_mtd_blktrans(&mtdblock_tr);
 }
 
-module_init(init_mtdblock);
-module_exit(cleanup_mtdblock);
-
+module_init(mtdblock_init);
+module_exit(mtdblock_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Erwin Authried <eauth@softsys.co.at> et al.");
-MODULE_DESCRIPTION("Simple uncached block device emulation access to MTD devices");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_DESCRIPTION("Simple read-only block device emulation access to MTD devices");
diff -Nru a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
--- a/drivers/mtd/mtdchar.c	Wed May  7 08:47:30 2003
+++ b/drivers/mtd/mtdchar.c	Wed May 28 08:01:05 2003
@@ -1,8 +1,7 @@
 /*
- * $Id: mtdchar.c,v 1.44 2001/10/02 15:05:11 dwmw2 Exp $
+ * $Id: mtdchar.c,v 1.54 2003/05/21 10:50:43 dwmw2 Exp $
  *
  * Character-device access to raw MTD devices.
- * Pure 2.4 version - compatibility cruft removed to mtdchar-compat.c
  *
  */
 
@@ -10,8 +9,10 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
 
 #ifdef CONFIG_DEVFS_FS
 #include <linux/devfs_fs_kernel.h>
@@ -29,7 +30,6 @@
 {
 	struct mtd_info *mtd=(struct mtd_info *)file->private_data;
 
-	lock_kernel();
 	switch (orig) {
 	case 0:
 		/* SEEK_SET */
@@ -44,7 +44,6 @@
 		file->f_pos =mtd->size + offset;
 		break;
 	default:
-		unlock_kernel();
 		return -EINVAL;
 	}
 
@@ -53,7 +52,6 @@
 	else if (file->f_pos >= mtd->size)
 		file->f_pos = mtd->size - 1;
 
-	unlock_kernel();
 	return file->f_pos;
 }
 
@@ -288,7 +286,12 @@
 
 	case MEMERASE:
 	{
-		struct erase_info *erase=kmalloc(sizeof(struct erase_info),GFP_KERNEL);
+		struct erase_info *erase;
+
+		if(!(file->f_mode & 2))
+			return -EPERM;
+
+		erase=kmalloc(sizeof(struct erase_info),GFP_KERNEL);
 		if (!erase)
 			ret = -ENOMEM;
 		else {
@@ -339,6 +342,9 @@
 		void *databuf;
 		ssize_t retlen;
 		
+		if(!(file->f_mode & 2))
+			return -EPERM;
+
 		if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
 			return -EFAULT;
 		
@@ -435,6 +441,12 @@
 		break;
 	}
 
+	case MEMSETOOBSEL:
+	{
+		if (copy_from_user(&mtd->oobinfo ,(void *)arg, sizeof(struct nand_oobinfo)))
+			return -EFAULT;
+		break;
+	}
 		
 	default:
 		DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)\n", cmd, MEMGETINFO);
@@ -446,12 +458,12 @@
 
 static struct file_operations mtd_fops = {
 	.owner		= THIS_MODULE,
-	.llseek		= mtd_lseek,	/* lseek */
-	.read		= mtd_read,	/* read */
-	.write 		= mtd_write, 	/* write */
-	.ioctl		= mtd_ioctl,	/* ioctl */
-	.open		= mtd_open,	/* open */
-	.release	= mtd_close,	/* release */
+	.llseek		= mtd_lseek,
+	.read		= mtd_read,
+	.write		= mtd_write,
+	.ioctl		= mtd_ioctl,
+	.open		= mtd_open,
+	.release	= mtd_close,
 };
 
 
diff -Nru a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
--- a/drivers/mtd/mtdconcat.c	Mon Oct 14 13:24:48 2002
+++ b/drivers/mtd/mtdconcat.c	Wed May 28 08:01:05 2003
@@ -3,9 +3,11 @@
  *
  * (C) 2002 Robert Kaiser <rkaiser@sysgo.de>
  *
+ * NAND support by Christian Gan <cgan@iders.ca>
+ *
  * This code is GPL
  *
- * $Id: mtdconcat.c,v 1.3 2002/05/21 21:04:25 dwmw2 Exp $
+ * $Id: mtdconcat.c,v 1.4 2003/03/07 17:44:59 rkaiser Exp $
  */
 
 #include <linux/module.h>
@@ -63,16 +65,16 @@
 		size_t size, retsize;
 
 		if (from >= subdev->size)
-		{
+		{   /* Not destined for this subdev */
 			size  = 0;
 			from -= subdev->size;
 		}
 		else
 		{
 			if (from + len > subdev->size)
-				size = subdev->size - from;
+				size = subdev->size - from; /* First part goes into this subdev */
 			else
-				size = len;
+				size = len; /* Entire transaction goes into this subdev */
 
 			err = subdev->read(subdev, from, size, &retsize, buf);
 
@@ -142,6 +144,214 @@
 	return err;
 }
 
+static int concat_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+            size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int err = -EINVAL;
+	int i;
+
+	*retlen = 0;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		size_t size, retsize;
+        
+		if (from >= subdev->size)
+		{   /* Not destined for this subdev */
+			size  = 0;
+			from -= subdev->size;
+		}
+		else
+		{
+			if (from + len > subdev->size)
+				size = subdev->size - from; /* First part goes into this subdev */
+			else
+				size = len; /* Entire transaction goes into this subdev */
+            
+            if (subdev->read_ecc)
+    			err = subdev->read_ecc(subdev, from, size, &retsize, buf, eccbuf, oobsel);
+            else
+                err = -EINVAL;
+
+			if(err)
+				break;
+
+			*retlen += retsize;
+			len -= size;
+			if(len == 0)
+				break;
+
+			err = -EINVAL;
+			buf += size;
+            if (eccbuf)
+            {
+                eccbuf += subdev->oobsize;
+                /* in nand.c at least, eccbufs are tagged with 2 (int)eccstatus',
+                   we must account for these */
+                eccbuf += 2 * (sizeof(int)); 
+            }
+			from = 0;
+		}
+	}
+	return err;
+}
+
+static int concat_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
+            size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int err = -EINVAL;
+	int i;
+
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+
+	*retlen = 0;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		size_t size, retsize;
+        
+		if (to >= subdev->size)
+		{
+			size  = 0;
+			to -= subdev->size;
+		}
+		else
+		{
+			if (to + len > subdev->size)
+				size = subdev->size - to;
+			else
+				size = len;
+
+			if (!(subdev->flags & MTD_WRITEABLE))
+				err = -EROFS;
+			else if (subdev->write_ecc)
+				err = subdev->write_ecc(subdev, to, size, &retsize, buf, eccbuf, oobsel);
+            else
+                err = -EINVAL;
+
+			if(err)
+				break;
+
+			*retlen += retsize;
+			len -= size;
+			if(len == 0)
+				break;
+
+			err = -EINVAL;
+			buf += size;
+            if (eccbuf)
+                eccbuf += subdev->oobsize;
+			to = 0;
+		}
+	}
+	return err;
+}
+
+static int concat_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
+            size_t *retlen, u_char *buf)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int err = -EINVAL;
+	int i;
+
+	*retlen = 0;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		size_t size, retsize;
+        
+		if (from >= subdev->size)
+		{   /* Not destined for this subdev */
+			size  = 0;
+			from -= subdev->size;
+		}
+		else
+		{
+			if (from + len > subdev->size)
+				size = subdev->size - from; /* First part goes into this subdev */
+			else
+				size = len; /* Entire transaction goes into this subdev */
+            
+            if (subdev->read_oob)
+    			err = subdev->read_oob(subdev, from, size, &retsize, buf);
+            else
+                err = -EINVAL;
+
+			if(err)
+				break;
+
+			*retlen += retsize;
+			len -= size;
+			if(len == 0)
+				break;
+
+			err = -EINVAL;
+			buf += size;
+			from = 0;
+		}
+	}
+	return err;
+}
+
+static int concat_write_oob (struct mtd_info *mtd, loff_t to, size_t len, 
+            size_t *retlen, const u_char *buf)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int err = -EINVAL;
+	int i;
+
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+
+	*retlen = 0;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		size_t size, retsize;
+        
+		if (to >= subdev->size)
+		{
+			size  = 0;
+			to -= subdev->size;
+		}
+		else
+		{
+			if (to + len > subdev->size)
+				size = subdev->size - to;
+			else
+				size = len;
+
+			if (!(subdev->flags & MTD_WRITEABLE))
+				err = -EROFS;
+			else if (subdev->write_oob)
+				err = subdev->write_oob(subdev, to, size, &retsize, buf);
+            else
+                err = -EINVAL;
+
+			if(err)
+				break;
+
+			*retlen += retsize;
+			len -= size;
+			if(len == 0)
+				break;
+
+			err = -EINVAL;
+			buf += size;
+			to = 0;
+		}
+	}
+	return err;
+}
+
+
 static void concat_erase_callback (struct erase_info *instr)
 {
 	wake_up((wait_queue_head_t *)instr->priv);
@@ -526,14 +736,18 @@
 	 *       because they are messy to implement and they are not
 	 *       used to a great extent anyway.
 	 */
-	concat->mtd.erase   = concat_erase;
-	concat->mtd.read    = concat_read;
-	concat->mtd.write   = concat_write;
-	concat->mtd.sync    = concat_sync;
-	concat->mtd.lock    = concat_lock;
-	concat->mtd.unlock  = concat_unlock;
-	concat->mtd.suspend = concat_suspend;
-	concat->mtd.resume  = concat_resume;
+	concat->mtd.erase     = concat_erase;
+	concat->mtd.read      = concat_read;    
+	concat->mtd.write     = concat_write;
+	concat->mtd.read_ecc  = concat_read_ecc;    
+	concat->mtd.write_ecc = concat_write_ecc;
+	concat->mtd.read_oob  = concat_read_oob;    
+	concat->mtd.write_oob = concat_write_oob;
+	concat->mtd.sync      = concat_sync;
+	concat->mtd.lock      = concat_lock;
+	concat->mtd.unlock    = concat_unlock;
+	concat->mtd.suspend   = concat_suspend;
+	concat->mtd.resume    = concat_resume;
 
 
 	/*
diff -Nru a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
--- a/drivers/mtd/mtdcore.c	Mon Feb  4 23:49:33 2002
+++ b/drivers/mtd/mtdcore.c	Wed May 28 08:01:05 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdcore.c,v 1.31 2001/10/02 15:05:11 dwmw2 Exp $
+ * $Id: mtdcore.c,v 1.39 2003/05/21 15:15:03 dwmw2 Exp $
  *
  * Core registration and callback routines for MTD
  * drivers and users.
@@ -17,7 +17,7 @@
 #include <linux/major.h>
 #include <linux/fs.h>
 #include <linux/ioctl.h>
-#include <stdarg.h>
+#include <linux/init.h>
 #include <linux/mtd/compatmac.h>
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
@@ -25,9 +25,15 @@
 
 #include <linux/mtd/mtd.h>
 
-static DECLARE_MUTEX(mtd_table_mutex);
-static struct mtd_info *mtd_table[MAX_MTD_DEVICES];
-static struct mtd_notifier *mtd_notifiers = NULL;
+/* These are exported solely for the purpose of mtd_blkdevs.c. You 
+   should not use them for _anything_ else */
+DECLARE_MUTEX(mtd_table_mutex);
+struct mtd_info *mtd_table[MAX_MTD_DEVICES];
+
+EXPORT_SYMBOL_GPL(mtd_table_mutex);
+EXPORT_SYMBOL_GPL(mtd_table);
+
+static LIST_HEAD(mtd_notifiers);
 
 /**
  *	add_mtd_device - register an MTD device
@@ -45,21 +51,28 @@
 
 	down(&mtd_table_mutex);
 
-	for (i=0; i< MAX_MTD_DEVICES; i++)
-		if (!mtd_table[i])
-		{
-			struct mtd_notifier *not=mtd_notifiers;
+	for (i=0; i < MAX_MTD_DEVICES; i++)
+		if (!mtd_table[i]) {
+			struct list_head *this;
 
 			mtd_table[i] = mtd;
 			mtd->index = i;
+			mtd->usecount = 0;
+
 			DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
-			while (not)
-			{
-				(*(not->add))(mtd);
-				not = not->next;
+			/* No need to get a refcount on the module containing
+			   the notifier, since we hold the mtd_table_mutex */
+			list_for_each(this, &mtd_notifiers) {
+				struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
+				not->add(mtd);
 			}
+			
 			up(&mtd_table_mutex);
-			MOD_INC_USE_COUNT;
+			/* We _know_ we aren't being removed, because
+			   our caller is still holding us here. So none
+			   of this try_ nonsense, and no bitching about it
+			   either. :) */
+			__module_get(THIS_MODULE);
 			return 0;
 		}
 	
@@ -79,29 +92,34 @@
 
 int del_mtd_device (struct mtd_info *mtd)
 {
-	struct mtd_notifier *not=mtd_notifiers;
-	int i;
+	int ret;
 	
 	down(&mtd_table_mutex);
 
-	for (i=0; i < MAX_MTD_DEVICES; i++)
-	{
-		if (mtd_table[i] == mtd)
-		{
-			while (not)
-			{
-				(*(not->remove))(mtd);
-				not = not->next;
-			}
-			mtd_table[i] = NULL;
-			up (&mtd_table_mutex);
-			MOD_DEC_USE_COUNT;
-			return 0;
+	if (mtd_table[mtd->index] != mtd) {
+		ret = -ENODEV;
+	} else if (mtd->usecount) {
+		printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", 
+		       mtd->index, mtd->name, mtd->usecount);
+		ret = -EBUSY;
+	} else {
+		struct list_head *this;
+
+		/* No need to get a refcount on the module containing
+		   the notifier, since we hold the mtd_table_mutex */
+		list_for_each(this, &mtd_notifiers) {
+			struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
+			not->remove(mtd);
 		}
+
+		mtd_table[mtd->index] = NULL;
+
+		module_put(THIS_MODULE);
+		ret = 0;
 	}
 
 	up(&mtd_table_mutex);
-	return 1;
+	return ret;
 }
 
 /**
@@ -119,10 +137,9 @@
 
 	down(&mtd_table_mutex);
 
-	new->next = mtd_notifiers;
-	mtd_notifiers = new;
+	list_add(&new->list, &mtd_notifiers);
 
- 	MOD_INC_USE_COUNT;
+ 	__module_get(THIS_MODULE);
 	
 	for (i=0; i< MAX_MTD_DEVICES; i++)
 		if (mtd_table[i])
@@ -143,34 +160,24 @@
 
 int unregister_mtd_user (struct mtd_notifier *old)
 {
-	struct mtd_notifier **prev = &mtd_notifiers;
-	struct mtd_notifier *cur;
 	int i;
 
 	down(&mtd_table_mutex);
 
-	while ((cur = *prev)) {
-		if (cur == old) {
-			*prev = cur->next;
-
-			MOD_DEC_USE_COUNT;
-
-			for (i=0; i< MAX_MTD_DEVICES; i++)
-				if (mtd_table[i])
-					old->remove(mtd_table[i]);
+	module_put(THIS_MODULE);
+
+	for (i=0; i< MAX_MTD_DEVICES; i++)
+		if (mtd_table[i])
+			old->remove(mtd_table[i]);
 			
-			up(&mtd_table_mutex);
-			return 0;
-		}
-		prev = &cur->next;
-	}
+	list_del(&old->list);
 	up(&mtd_table_mutex);
-	return 1;
+	return 0;
 }
 
 
 /**
- *	__get_mtd_device - obtain a validated handle for an MTD device
+ *	get_mtd_device - obtain a validated handle for an MTD device
  *	@mtd: last known address of the required MTD device
  *	@num: internal device number of the required MTD device
  *
@@ -178,11 +185,10 @@
  *	table, if any.	Given an address and num == -1, search the device table
  *	for a device with that address and return if it's still present. Given
  *	both, return the num'th driver only if its address matches. Return NULL
- *	if not. get_mtd_device() increases the use count, but
- *	__get_mtd_device() doesn't - you should generally use get_mtd_device().
+ *	if not.
  */
 	
-struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num)
+struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
 {
 	struct mtd_info *ret = NULL;
 	int i;
@@ -198,16 +204,97 @@
 		if (mtd && mtd != ret)
 			ret = NULL;
 	}
-	
+
+	if (ret && !try_module_get(ret->owner))
+		ret = NULL;
+
+	if (ret)
+		ret->usecount++;
+
 	up(&mtd_table_mutex);
 	return ret;
 }
 
+void put_mtd_device(struct mtd_info *mtd)
+{
+	int c;
+
+	down(&mtd_table_mutex);
+	c = --mtd->usecount;
+	up(&mtd_table_mutex);
+	BUG_ON(c < 0);
+
+	module_put(mtd->owner);
+}
+
+/* default_mtd_writev - default mtd writev method for MTD devices that
+ *			dont implement their own
+ */
+
+int default_mtd_writev(struct mtd_info *mtd, const struct iovec *vecs,
+		       unsigned long count, loff_t to, size_t *retlen)
+{
+	unsigned long i;
+	size_t totlen = 0, thislen;
+	int ret = 0;
+
+	if(!mtd->write) {
+		ret = -EROFS;
+	} else {
+		for (i=0; i<count; i++) {
+			if (!vecs[i].iov_len)
+				continue;
+			ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base);
+			totlen += thislen;
+			if (ret || thislen != vecs[i].iov_len)
+				break;
+			to += vecs[i].iov_len;
+		}
+	}
+	if (retlen)
+		*retlen = totlen;
+	return ret;
+}
+
+
+/* default_mtd_readv - default mtd readv method for MTD devices that dont
+ *		       implement their own
+ */
+
+int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs,
+		      unsigned long count, loff_t from, size_t *retlen)
+{
+	unsigned long i;
+	size_t totlen = 0, thislen;
+	int ret = 0;
+
+	if(!mtd->read) {
+		ret = -EIO;
+	} else {
+		for (i=0; i<count; i++) {
+			if (!vecs[i].iov_len)
+				continue;
+			ret = mtd->read(mtd, from, vecs[i].iov_len, &thislen, vecs[i].iov_base);
+			totlen += thislen;
+			if (ret || thislen != vecs[i].iov_len)
+				break;
+			from += vecs[i].iov_len;
+		}
+	}
+	if (retlen)
+		*retlen = totlen;
+	return ret;
+}
+
+
 EXPORT_SYMBOL(add_mtd_device);
 EXPORT_SYMBOL(del_mtd_device);
-EXPORT_SYMBOL(__get_mtd_device);
+EXPORT_SYMBOL(get_mtd_device);
+EXPORT_SYMBOL(put_mtd_device);
 EXPORT_SYMBOL(register_mtd_user);
 EXPORT_SYMBOL(unregister_mtd_user);
+EXPORT_SYMBOL(default_mtd_writev);
+EXPORT_SYMBOL(default_mtd_readv);
 
 /*====================================================================*/
 /* Power management code */
@@ -296,7 +383,7 @@
 	up(&mtd_table_mutex);
         if (off >= len+begin)
                 return 0;
-        *start = page + (begin-off);
+        *start = page + (off-begin);
         return ((count < begin+len-off) ? count : begin+len-off);
 }
 
diff -Nru a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
--- a/drivers/mtd/mtdpart.c	Mon Feb  4 23:49:33 2002
+++ b/drivers/mtd/mtdpart.c	Wed May 28 08:01:05 2003
@@ -5,18 +5,22 @@
  *
  * This code is GPL
  *
- * $Id: mtdpart.c,v 1.23 2001/10/02 15:05:11 dwmw2 Exp $
- */
+ * $Id: mtdpart.c,v 1.39 2003/05/21 15:15:03 dwmw2 Exp $
+ *
+ * 	02-21-2002	Thomas Gleixner <gleixner@autronix.de>
+ *			added support for read_oob, write_oob
+ */	
 
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/list.h>
-
+#include <linux/config.h>
+#include <linux/kmod.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
-
+#include <linux/mtd/compatmac.h>
 
 /* Our partition linked list */
 static LIST_HEAD(mtd_partitions);
@@ -28,6 +32,7 @@
 	u_int32_t offset;
 	int index;
 	struct list_head list;
+	int registered;
 };
 
 /*
@@ -50,7 +55,72 @@
 		len = 0;
 	else if (from + len > mtd->size)
 		len = mtd->size - from;
-	return part->master->read (part->master, from + part->offset, 
+	if (part->master->read_ecc == NULL)	
+		return part->master->read (part->master, from + part->offset, 
+					len, retlen, buf);
+	else
+		return part->master->read_ecc (part->master, from + part->offset, 
+					len, retlen, buf, NULL, &mtd->oobinfo);
+}
+
+static int part_point (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char **buf)
+{
+	struct mtd_part *part = PART(mtd);
+	if (from >= mtd->size)
+		len = 0;
+	else if (from + len > mtd->size)
+		len = mtd->size - from;
+	return part->master->point (part->master, from + part->offset, 
+				    len, retlen, buf);
+}
+static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+{
+	struct mtd_part *part = PART(mtd);
+
+	part->master->unpoint (part->master, addr, from + part->offset, len);
+}
+
+
+static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
+{
+	struct mtd_part *part = PART(mtd);
+	if (oobsel == NULL)
+		oobsel = &mtd->oobinfo;
+	if (from >= mtd->size)
+		len = 0;
+	else if (from + len > mtd->size)
+		len = mtd->size - from;
+	return part->master->read_ecc (part->master, from + part->offset, 
+					len, retlen, buf, eccbuf, oobsel);
+}
+
+static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf)
+{
+	struct mtd_part *part = PART(mtd);
+	if (from >= mtd->size)
+		len = 0;
+	else if (from + len > mtd->size)
+		len = mtd->size - from;
+	return part->master->read_oob (part->master, from + part->offset, 
+					len, retlen, buf);
+}
+
+static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf)
+{
+	struct mtd_part *part = PART(mtd);
+	return part->master->read_user_prot_reg (part->master, from, 
+					len, retlen, buf);
+}
+
+static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf)
+{
+	struct mtd_part *part = PART(mtd);
+	return part->master->read_user_prot_reg (part->master, from, 
 					len, retlen, buf);
 }
 
@@ -64,7 +134,51 @@
 		len = 0;
 	else if (to + len > mtd->size)
 		len = mtd->size - to;
-	return part->master->write (part->master, to + part->offset, 
+	if (part->master->write_ecc == NULL)	
+		return part->master->write (part->master, to + part->offset, 
+					len, retlen, buf);
+	else
+		return part->master->write_ecc (part->master, to + part->offset, 
+					len, retlen, buf, NULL, &mtd->oobinfo);
+							
+}
+
+static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
+			size_t *retlen, const u_char *buf,
+			 u_char *eccbuf, struct nand_oobinfo *oobsel)
+{
+	struct mtd_part *part = PART(mtd);
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	if (oobsel == NULL)
+		oobsel = &mtd->oobinfo;
+	if (to >= mtd->size)
+		len = 0;
+	else if (to + len > mtd->size)
+		len = mtd->size - to;
+	return part->master->write_ecc (part->master, to + part->offset, 
+					len, retlen, buf, eccbuf, oobsel);
+}
+
+static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
+			size_t *retlen, const u_char *buf)
+{
+	struct mtd_part *part = PART(mtd);
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	if (to >= mtd->size)
+		len = 0;
+	else if (to + len > mtd->size)
+		len = mtd->size - to;
+	return part->master->write_oob (part->master, to + part->offset, 
+					len, retlen, buf);
+}
+
+static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf)
+{
+	struct mtd_part *part = PART(mtd);
+	return part->master->write_user_prot_reg (part->master, from, 
 					len, retlen, buf);
 }
 
@@ -74,16 +188,52 @@
 	struct mtd_part *part = PART(mtd);
 	if (!(mtd->flags & MTD_WRITEABLE))
 		return -EROFS;
-	return part->master->writev (part->master, vecs, count,
+	if (part->master->writev_ecc == NULL)	
+		return part->master->writev (part->master, vecs, count,
 					to + part->offset, retlen);
+	else
+		return part->master->writev_ecc (part->master, vecs, count,
+					to + part->offset, retlen,
+					NULL, &mtd->oobinfo);
 }
 
 static int part_readv (struct mtd_info *mtd,  struct iovec *vecs,
 			 unsigned long count, loff_t from, size_t *retlen)
 {
 	struct mtd_part *part = PART(mtd);
-	return part->master->readv (part->master, vecs, count,
+	if (part->master->readv_ecc == NULL)	
+		return part->master->readv (part->master, vecs, count,
 					from + part->offset, retlen);
+	else
+		return part->master->readv_ecc (part->master, vecs, count,
+					from + part->offset, retlen, 
+					NULL, &mtd->oobinfo);
+}
+
+static int part_writev_ecc (struct mtd_info *mtd,  const struct iovec *vecs,
+			 unsigned long count, loff_t to, size_t *retlen,
+			 u_char *eccbuf,  struct nand_oobinfo *oobsel)
+{
+	struct mtd_part *part = PART(mtd);
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+	if (oobsel == NULL)
+		oobsel = &mtd->oobinfo;
+	return part->master->writev_ecc (part->master, vecs, count,
+					to + part->offset, retlen,
+					eccbuf, oobsel);
+}
+
+static int part_readv_ecc (struct mtd_info *mtd,  struct iovec *vecs,
+			 unsigned long count, loff_t from, size_t *retlen,
+			 u_char *eccbuf,  struct nand_oobinfo *oobsel)
+{
+	struct mtd_part *part = PART(mtd);
+	if (oobsel == NULL)
+		oobsel = &mtd->oobinfo;
+	return part->master->readv_ecc (part->master, vecs, count,
+					from + part->offset, retlen, 
+					eccbuf, oobsel);
 }
 
 static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
@@ -148,7 +298,8 @@
 		if (slave->master == master) {
 			struct list_head *prev = node->prev;
 			__list_del(prev, node->next);
-			del_mtd_device(&slave->mtd);
+			if(slave->registered)
+				del_mtd_device(&slave->mtd);
 			kfree(slave);
 			node = prev;
 		}
@@ -198,22 +349,44 @@
 
 		slave->mtd.name = parts[i].name;
 		slave->mtd.bank_size = master->bank_size;
-
-		slave->mtd.module = master->module;
+		slave->mtd.owner = master->owner;
 
 		slave->mtd.read = part_read;
 		slave->mtd.write = part_write;
+
+		if(master->point && master->unpoint){
+			slave->mtd.point = part_point;
+			slave->mtd.unpoint = part_unpoint;
+		}
+		
+		if (master->read_ecc)
+			slave->mtd.read_ecc = part_read_ecc;
+		if (master->write_ecc)
+			slave->mtd.write_ecc = part_write_ecc;
+		if (master->read_oob)
+			slave->mtd.read_oob = part_read_oob;
+		if (master->write_oob)
+			slave->mtd.write_oob = part_write_oob;
+		if(master->read_user_prot_reg)
+			slave->mtd.read_user_prot_reg = part_read_user_prot_reg;
+		if(master->read_fact_prot_reg)
+			slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
+		if(master->write_user_prot_reg)
+			slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
 		if (master->sync)
 			slave->mtd.sync = part_sync;
 		if (!i && master->suspend && master->resume) {
 				slave->mtd.suspend = part_suspend;
 				slave->mtd.resume = part_resume;
 		}
-
 		if (master->writev)
 			slave->mtd.writev = part_writev;
 		if (master->readv)
 			slave->mtd.readv = part_readv;
+		if (master->writev_ecc)
+			slave->mtd.writev_ecc = part_writev_ecc;
+		if (master->readv_ecc)
+			slave->mtd.readv_ecc = part_readv_ecc;
 		if (master->lock)
 			slave->mtd.lock = part_lock;
 		if (master->unlock)
@@ -225,6 +398,15 @@
 
 		if (slave->offset == MTDPART_OFS_APPEND)
 			slave->offset = cur_offset;
+		if (slave->offset == MTDPART_OFS_NXTBLK) {
+			u_int32_t emask = master->erasesize-1;
+			slave->offset = (cur_offset + emask) & ~emask;
+			if (slave->offset != cur_offset) {
+				printk(KERN_NOTICE "Moving partition %d: "
+				       "0x%08x -> 0x%08x\n", i,
+				       cur_offset, slave->offset);
+			}
+		}
 		if (slave->mtd.size == MTDPART_SIZ_FULL)
 			slave->mtd.size = master->size - slave->offset;
 		cur_offset = slave->offset + slave->mtd.size;
@@ -279,8 +461,17 @@
 				parts[i].name);
 		}
 
-		/* register our partition */
-		add_mtd_device(&slave->mtd);
+		if(parts[i].mtdp)
+		{	/* store the object pointer (caller may or may not register it */
+			*parts[i].mtdp = &slave->mtd;
+			slave->registered = 0;
+		}
+		else
+		{
+			/* register our partition */
+			add_mtd_device(&slave->mtd);
+			slave->registered = 1;
+		}
 	}
 
 	return 0;
@@ -289,6 +480,75 @@
 EXPORT_SYMBOL(add_mtd_partitions);
 EXPORT_SYMBOL(del_mtd_partitions);
 
+static spinlock_t part_parser_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(part_parsers);
+
+struct mtd_part_parser *get_partition_parser(const char *name)
+{
+	struct list_head *this;
+	void *ret = NULL;
+	spin_lock(&part_parser_lock);
+
+	list_for_each(this, &part_parsers) {
+		struct mtd_part_parser *p = list_entry(this, struct mtd_part_parser, list);
+
+		if (!strcmp(p->name, name) && try_module_get(p->owner)) {
+			ret = p;
+			break;
+		}
+	}
+	spin_unlock(&part_parser_lock);
+
+	return ret;
+}
+
+int register_mtd_parser(struct mtd_part_parser *p)
+{
+	spin_lock(&part_parser_lock);
+	list_add(&p->list, &part_parsers);
+	spin_unlock(&part_parser_lock);
+
+	return 0;
+}
+
+int deregister_mtd_parser(struct mtd_part_parser *p)
+{
+	spin_lock(&part_parser_lock);
+	list_del(&p->list);
+	spin_unlock(&part_parser_lock);
+	return 0;
+}
+
+int parse_mtd_partitions(struct mtd_info *master, const char **types, 
+			 struct mtd_partition **pparts, unsigned long origin)
+{
+	struct mtd_part_parser *parser;
+	int ret = 0;
+		
+	for ( ; ret <= 0 && *types; types++) {
+		parser = get_partition_parser(*types);
+#ifdef CONFIG_KMOD
+		if (!parser && !request_module("%s", *types))
+				parser = get_partition_parser(*types);
+#endif
+		if (!parser) {
+			printk(KERN_NOTICE "%s partition parsing not available\n",
+			       *types);
+			continue;
+		}
+		ret = (*parser->parse_fn)(master, pparts, origin);
+		if (ret > 0) {
+			printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", 
+			       ret, parser->name, master->name);
+		}
+		put_partition_parser(parser);
+	}
+	return ret;
+}
+
+EXPORT_SYMBOL_GPL(parse_mtd_partitions);
+EXPORT_SYMBOL_GPL(register_mtd_parser);
+EXPORT_SYMBOL_GPL(deregister_mtd_parser);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
diff -Nru a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
--- a/drivers/mtd/nand/Kconfig	Tue Oct 29 17:16:55 2002
+++ b/drivers/mtd/nand/Kconfig	Wed May 28 08:01:05 2003
@@ -1,5 +1,5 @@
-# drivers/mtd/nand/Config.in
-# $Id: Config.in,v 1.4 2001/09/19 09:35:23 dwmw2 Exp $
+# drivers/mtd/nand/Kconfig
+# $Id: Kconfig,v 1.4 2003/05/28 10:04:23 dwmw2 Exp $
 
 menu "NAND Flash Device Drivers"
 	depends on MTD!=n
@@ -9,16 +9,8 @@
 	depends on MTD
 	help
 	  This enables support for accessing all type of NAND flash
-	  devices.
-
-config MTD_NAND_ECC
-	bool "Enable ECC correction algorithm"
-	depends on MTD_NAND
-	help
-	  This enables software-based ECC for use with NAND flash chips. It
-	  can detect and correct 1 bit errors per 256 byte blocks. This
-	  should be used to increase the reliability of the data stored and
-	  read on the device.
+	  devices with an 8-bit data bus interface. For further 
+	  information see www.linux-mtd.infradead.org/tech/nand.html.
 
 config MTD_NAND_VERIFY_WRITE
 	bool "Verify NAND page writes"
@@ -28,8 +20,21 @@
 	  NAND flash device internally checks only bits transitioning
 	  from 1 to 0. There is a rare possibility that even though the
 	  device thinks the write was successful, a bit could have been
-	  flipped accidentaly due to device wear, gamma rays, whatever.
-	  Enable this if you are really paranoid.
+	  flipped accidentaly due to device wear or something else.
+
+config MTD_NAND_AUTCPU12
+	tristate "SmartMediaCard on autronix autcpu12 board"
+	depends on ARM && MTD_NAND && ARCH_AUTCPU12
+	help
+	  This enables the driver for the autronix autcpu12 board to 
+	  access the SmartMediaCard.
+
+config MTD_NAND_EDB7312
+	tristate "Support for Cirrus Logic EBD7312 evaluation board"
+	depends on ARM && MTD_NAND && ARCH_EDB7312
+	help
+	  This enables the driver for the Cirrus Logic EBD7312 evaluation 
+	  board to access the onboard NAND Flash.
 
 config MTD_NAND_SPIA
 	tristate "NAND Flash device on SPIA board"
@@ -37,5 +42,10 @@
 	help
 	  If you had to ask, you don't have one. Say 'N'.
 
+config MTD_NAND_IDS
+	tristate
+	default y if MTD_NAND = y || MTD_DOC2000 = y || MTD_DOC2001 = y || MTD_DOC2001PLUS = y
+	default m if MTD_NAND = m || MTD_DOC2000 = m || MTD_DOC2001 = m || MTD_DOC2001PLUS = m
+	
 endmenu
 
diff -Nru a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
--- a/drivers/mtd/nand/Makefile	Mon Feb  3 14:19:37 2003
+++ b/drivers/mtd/nand/Makefile	Wed May 28 08:01:05 2003
@@ -1,10 +1,10 @@
 #
 # linux/drivers/nand/Makefile
 #
-# $Id: Makefile,v 1.5 2001/09/19 22:39:59 dwmw2 Exp $
+# $Id: Makefile.common,v 1.2 2003/05/28 11:38:54 dwmw2 Exp $
 
-nandobjs-y			:= nand.o
-nandobjs-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
-
-obj-$(CONFIG_MTD_NAND)		+= $(nandobjs-y)
+obj-$(CONFIG_MTD_NAND)		+= nand.o nand_ecc.o
 obj-$(CONFIG_MTD_NAND_SPIA)	+= spia.o
+obj-$(CONFIG_MTD_NAND_AUTCPU12)	+= autcpu12.o
+obj-$(CONFIG_MTD_NAND_EDB7312)  += edb7312.o
+obj-$(CONFIG_MTD_NAND_IDS)	+= nand_ids.o
diff -Nru a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/nand/autcpu12.c	Wed May 28 08:01:24 2003
@@ -0,0 +1,254 @@
+/*
+ *  drivers/mtd/autcpu12.c
+ *
+ *  Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>
+ *
+ *  Derived from drivers/mtd/spia.c
+ * 	 Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ * 
+ * $Id: autcpu12.c,v 1.10 2003/04/20 07:24:40 gleixner Exp $
+ *
+ * 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.
+ *
+ *  Overview:
+ *   This is a device driver for the NAND flash device found on the
+ *   autronix autcpu12 board, which is a SmartMediaCard. It supports 
+ *   16MB, 32MB and 64MB cards.
+ *
+ *
+ *	02-12-2002 TG	Cleanup of module params
+ *
+ *	02-20-2002 TG	adjusted for different rd/wr adress support
+ *			added support for read device ready/busy line
+ *			added page_cache
+ *
+ *	10-06-2002 TG	128K card support added
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/sizes.h>
+#include <asm/arch/autcpu12.h>
+
+/*
+ * MTD structure for AUTCPU12 board
+ */
+static struct mtd_info *autcpu12_mtd = NULL;
+
+/*
+ * Module stuff
+ */
+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
+#define autcpu12_init init_module
+#define autcpu12_cleanup cleanup_module
+#endif
+
+static int autcpu12_io_base = CS89712_VIRT_BASE;
+static int autcpu12_fio_pbase = AUTCPU12_PHYS_SMC;
+static int autcpu12_fio_ctrl = AUTCPU12_SMC_SELECT_OFFSET;
+static int autcpu12_pedr = AUTCPU12_SMC_PORT_OFFSET;
+static int autcpu12_fio_base;
+
+#ifdef MODULE
+MODULE_PARM(autcpu12_fio_pbase, "i");
+MODULE_PARM(autcpu12_fio_ctrl, "i");
+MODULE_PARM(autcpu12_pedr, "i");
+
+__setup("autcpu12_fio_pbase=",autcpu12_fio_pbase);
+__setup("autcpu12_fio_ctrl=",autcpu12_fio_ctrl);
+__setup("autcpu12_pedr=",autcpu12_pedr);
+#endif
+
+/*
+ * Define partitions for flash devices
+ */
+extern struct nand_oobinfo jffs2_oobinfo;
+
+static struct mtd_partition partition_info16k[] = {
+	{ name: "AUTCPU12 flash partition 1",
+	  offset:  0,
+	  size:    8 * SZ_1M },
+	{ name: "AUTCPU12 flash partition 2",
+	  offset:  8 * SZ_1M,
+	  size:    8 * SZ_1M },
+};
+
+static struct mtd_partition partition_info32k[] = {
+	{ name: "AUTCPU12 flash partition 1",
+	  offset:  0,
+	  size:    8 * SZ_1M },
+	{ name: "AUTCPU12 flash partition 2",
+	  offset:  8 * SZ_1M,
+	  size:   24 * SZ_1M },
+};
+
+static struct mtd_partition partition_info64k[] = {
+	{ name: "AUTCPU12 flash partition 1",
+	  offset:  0,
+	  size:   16 * SZ_1M },
+	{ name: "AUTCPU12 flash partition 2",
+	  offset: 16 * SZ_1M,
+	  size:   48 * SZ_1M },
+};
+
+static struct mtd_partition partition_info128k[] = {
+	{ name: "AUTCPU12 flash partition 1",
+	  offset:  0,
+	  size:   16 * SZ_1M },
+	{ name: "AUTCPU12 flash partition 2",
+	  offset: 16 * SZ_1M,
+	  size:   112 * SZ_1M },
+};
+
+#define NUM_PARTITIONS16K 2
+#define NUM_PARTITIONS32K 2
+#define NUM_PARTITIONS64K 2
+#define NUM_PARTITIONS128K 2
+/* 
+ *	hardware specific access to control-lines
+*/
+void autcpu12_hwcontrol(int cmd)
+{
+
+	switch(cmd){
+
+		case NAND_CTL_SETCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |=  AUTCPU12_SMC_CLE; break;
+		case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_CLE; break;
+
+		case NAND_CTL_SETALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |=  AUTCPU12_SMC_ALE; break;
+		case NAND_CTL_CLRALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_ALE; break;
+
+		case NAND_CTL_SETNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x01; break;
+		case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x00; break;
+	}
+}
+
+/*
+*	read device ready pin
+*/
+int autcpu12_device_ready(void)
+{
+
+	return ( (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0;
+
+}
+/*
+ * Main initialization routine
+ */
+int __init autcpu12_init (void)
+{
+	struct nand_chip *this;
+	int err = 0;
+
+	/* Allocate memory for MTD device structure and private data */
+	autcpu12_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
+				GFP_KERNEL);
+	if (!autcpu12_mtd) {
+		printk ("Unable to allocate AUTCPU12 NAND MTD device structure.\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	/* map physical adress */
+	autcpu12_fio_base=(unsigned long)ioremap(autcpu12_fio_pbase,SZ_1K);
+	if(!autcpu12_fio_base){
+		printk("Ioremap autcpu12 SmartMedia Card failed\n");
+		err = -EIO;
+		goto out_mtd;
+	}
+
+	/* Get pointer to private data */
+	this = (struct nand_chip *) (&autcpu12_mtd[1]);
+
+	/* Initialize structures */
+	memset((char *) autcpu12_mtd, 0, sizeof(struct mtd_info));
+	memset((char *) this, 0, sizeof(struct nand_chip));
+
+	/* Link the private data with the MTD structure */
+	autcpu12_mtd->priv = this;
+
+	/* Set address of NAND IO lines */
+	this->IO_ADDR_R = autcpu12_fio_base;
+	this->IO_ADDR_W = autcpu12_fio_base;
+	this->hwcontrol = autcpu12_hwcontrol;
+	this->dev_ready = autcpu12_device_ready;
+	/* 20 us command delay time */
+	this->chip_delay = 20;		
+	this->eccmode = NAND_ECC_SOFT;
+
+	/* Scan to find existance of the device */
+	if (nand_scan (autcpu12_mtd)) {
+		err = -ENXIO;
+		goto out_ior;
+	}
+
+	/* Allocate memory for internal data buffer */
+	this->data_buf = kmalloc (sizeof(u_char) * (autcpu12_mtd->oobblock + autcpu12_mtd->oobsize), GFP_KERNEL);
+	if (!this->data_buf) {
+		printk ("Unable to allocate NAND data buffer for AUTCPU12.\n");
+		err = -ENOMEM;
+		goto out_ior;
+	}
+
+	/* Register the partitions */
+	switch(autcpu12_mtd->size){
+		case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break;
+		case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break;
+		case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; 
+		case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break; 
+		default: {
+			printk ("Unsupported SmartMedia device\n"); 
+			err = -ENXIO;
+			goto out_buf;
+		}
+	}
+	goto out;
+
+out_buf:
+	kfree (this->data_buf);    
+out_ior:
+	iounmap((void *)autcpu12_fio_base);
+out_mtd:
+	kfree (autcpu12_mtd);
+out:
+	return err;
+}
+
+module_init(autcpu12_init);
+
+/*
+ * Clean up routine
+ */
+#ifdef MODULE
+static void __exit autcpu12_cleanup (void)
+{
+	struct nand_chip *this = (struct nand_chip *) &autcpu12_mtd[1];
+
+	/* Unregister partitions */
+	del_mtd_partitions(autcpu12_mtd);
+	
+	/* Unregister the device */
+	del_mtd_device (autcpu12_mtd);
+
+	/* Free internal data buffers */
+	kfree (this->data_buf);
+
+	/* unmap physical adress */
+	iounmap((void *)autcpu12_fio_base);
+
+	/* Free the MTD device structure */
+	kfree (autcpu12_mtd);
+}
+module_exit(autcpu12_cleanup);
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION("Glue layer for SmartMediaCard on autronix autcpu12");
diff -Nru a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/nand/edb7312.c	Wed May 28 08:01:25 2003
@@ -0,0 +1,233 @@
+/*
+ *  drivers/mtd/nand/edb7312.c
+ *
+ *  Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
+ *
+ *  Derived from drivers/mtd/nand/autcpu12.c
+ *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
+ *
+ * $Id: edb7312.c,v 1.5 2003/04/20 07:24:40 gleixner Exp $
+ *
+ * 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.
+ *
+ *  Overview:
+ *   This is a device driver for the NAND flash device found on the
+ *   CLEP7312 board which utilizes the Toshiba TC58V64AFT part. This is
+ *   a 64Mibit (8MiB x 8 bits) NAND flash device.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h> /* for CLPS7111_VIRT_BASE */
+#include <asm/sizes.h>
+#include <asm/hardware/clps7111.h>
+
+/*
+ * MTD structure for EDB7312 board
+ */
+static struct mtd_info *ep7312_mtd = NULL;
+
+/*
+ * Values specific to the EDB7312 board (used with EP7312 processor)
+ */
+#define EP7312_FIO_PBASE 0x10000000	/* Phys address of flash */
+#define EP7312_PXDR	0x0001	/*
+				 * IO offset to Port B data register
+				 * where the CLE, ALE and NCE pins
+				 * are wired to.
+				 */
+#define EP7312_PXDDR	0x0041	/*
+				 * IO offset to Port B data direction
+				 * register so we can control the IO
+				 * lines.
+				 */
+
+/*
+ * Module stuff
+ */
+
+static int ep7312_fio_pbase = EP7312_FIO_PBASE;
+static int ep7312_pxdr = EP7312_PXDR;
+static int ep7312_pxddr = EP7312_PXDDR;
+
+#ifdef MODULE
+MODULE_PARM(ep7312_fio_pbase, "i");
+MODULE_PARM(ep7312_pxdr, "i");
+MODULE_PARM(ep7312_pxddr, "i");
+
+__setup("ep7312_fio_pbase=",ep7312_fio_pbase);
+__setup("ep7312_pxdr=",ep7312_pxdr);
+__setup("ep7312_pxddr=",ep7312_pxddr);
+#endif
+
+#ifdef CONFIG_MTD_PARTITIONS
+/*
+ * Define static partitions for flash device
+ */
+static struct mtd_partition partition_info[] = {
+	{ name: "EP7312 Nand Flash",
+		  offset: 0,
+		  size: 8*1024*1024 }
+};
+#define NUM_PARTITIONS 1
+
+#endif
+
+
+/* 
+ *	hardware specific access to control-lines
+ */
+static void ep7312_hwcontrol(int cmd) 
+{
+	switch(cmd) {
+		
+	case NAND_CTL_SETCLE: 
+		clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr); 
+		break;
+	case NAND_CTL_CLRCLE: 
+		clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr);
+		break;
+		
+	case NAND_CTL_SETALE:
+		clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr);
+		break;
+	case NAND_CTL_CLRALE:
+		clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr);
+		break;
+		
+	case NAND_CTL_SETNCE:
+		clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr);
+		break;
+	case NAND_CTL_CLRNCE:
+		clps_writeb((clps_readb(ep7312_pxdr) | 0x80) | 0x40, ep7312_pxdr);
+		break;
+	}
+}
+
+/*
+ *	read device ready pin
+ */
+static int ep7312_device_ready(void)
+{
+	return 1;
+}
+
+/*
+ * Main initialization routine
+ */
+static int __init ep7312_init (void)
+{
+	struct nand_chip *this;
+	const char *part_type = 0;
+	int mtd_parts_nb = 0;
+	struct mtd_partition *mtd_parts = 0;
+	int ep7312_fio_base;
+	
+	/* Allocate memory for MTD device structure and private data */
+	ep7312_mtd = kmalloc(sizeof(struct mtd_info) + 
+			     sizeof(struct nand_chip),
+			     GFP_KERNEL);
+	if (!ep7312_mtd) {
+		printk("Unable to allocate EDB7312 NAND MTD device structure.\n");
+		return -ENOMEM;
+	}
+	
+	/* map physical adress */
+	ep7312_fio_base = (unsigned long)ioremap(ep7312_fio_pbase, SZ_1K);
+	if(!ep7312_fio_base) {
+		printk("ioremap EDB7312 NAND flash failed\n");
+		kfree(ep7312_mtd);
+		return -EIO;
+	}
+	
+	/* Get pointer to private data */
+	this = (struct nand_chip *) (&ep7312_mtd[1]);
+	
+	/* Initialize structures */
+	memset((char *) ep7312_mtd, 0, sizeof(struct mtd_info));
+	memset((char *) this, 0, sizeof(struct nand_chip));
+	
+	/* Link the private data with the MTD structure */
+	ep7312_mtd->priv = this;
+	
+	/*
+	 * Set GPIO Port B control register so that the pins are configured
+	 * to be outputs for controlling the NAND flash.
+	 */
+	clps_writeb(0xf0, ep7312_pxddr);
+	
+	/* insert callbacks */
+	this->IO_ADDR_R = ep7312_fio_base;
+	this->IO_ADDR_W = ep7312_fio_base;
+	this->hwcontrol = ep7312_hwcontrol;
+	this->dev_ready = ep7312_device_ready;
+	/* 15 us command delay time */
+	this->chip_delay = 15;
+	
+	/* Scan to find existence of the device */
+	if (nand_scan (ep7312_mtd)) {
+		iounmap((void *)ep7312_fio_base);
+		kfree (ep7312_mtd);
+		return -ENXIO;
+	}
+	
+	/* Allocate memory for internal data buffer */
+	this->data_buf = kmalloc (sizeof(u_char) * (ep7312_mtd->oobblock + ep7312_mtd->oobsize), GFP_KERNEL);
+	if (!this->data_buf) {
+		printk("Unable to allocate NAND data buffer for EDB7312.\n");
+		iounmap((void *)ep7312_fio_base);
+		kfree (ep7312_mtd);
+		return -ENOMEM;
+	}
+	
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+	mtd_parts_nb = parse_cmdline_partitions(ep7312_mtd, &mtd_parts, 
+						"edb7312-nand");
+	if (mtd_parts_nb > 0)
+	  part_type = "command line";
+	else
+	  mtd_parts_nb = 0;
+#endif
+	if (mtd_parts_nb == 0)
+	{
+		mtd_parts = partition_info;
+		mtd_parts_nb = NUM_PARTITIONS;
+		part_type = "static";
+	}
+	
+	/* Register the partitions */
+	printk(KERN_NOTICE "Using %s partition definition\n", part_type);
+	add_mtd_partitions(ep7312_mtd, mtd_parts, mtd_parts_nb);
+	
+	/* Return happy */
+	return 0;
+}
+module_init(ep7312_init);
+
+/*
+ * Clean up routine
+ */
+static void __exit ep7312_cleanup (void)
+{
+	struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1];
+	
+	/* Unregister the device */
+	del_mtd_device (ep7312_mtd);
+	
+	/* Free internal data buffer */
+	kfree (this->data_buf);
+	
+	/* Free the MTD device structure */
+	kfree (ep7312_mtd);
+}
+module_exit(ep7312_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
+MODULE_DESCRIPTION("MTD map driver for Cogent EDB7312 board");
diff -Nru a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c
--- a/drivers/mtd/nand/nand.c	Mon Feb  4 23:49:33 2002
+++ b/drivers/mtd/nand/nand.c	Wed May 28 08:01:05 2003
@@ -1,17 +1,137 @@
 /*
  *  drivers/mtd/nand.c
  *
- *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ *  Overview:
+ *   This is the generic MTD driver for NAND flash devices. It should be
+ *   capable of working with almost all NAND chips currently available.
+ *   
+ *	Additional technical information is available on
+ *	http://www.linux-mtd.infradead.org/tech/nand.html
+ *	
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
+ * 		  2002 Thomas Gleixner (tglx@linutronix.de)
+ *
+ *  10-29-2001  Thomas Gleixner (tglx@linutronix.de)
+ * 		- Changed nand_chip structure for controlline function to
+ *		support different hardware structures (Access to
+ *		controllines ALE,CLE,NCE via hardware specific function. 
+ *		- exit out of "failed erase block" changed, to avoid
+ *		driver hangup
+ *		- init_waitqueue_head added in function nand_scan !!
+ *
+ *  01-30-2002  Thomas Gleixner (tglx@linutronix.de)
+ *		change in nand_writev to block invalid vecs entries
+ *
+ *  02-11-2002  Thomas Gleixner (tglx@linutronix.de)
+ *		- major rewrite to avoid duplicated code
+ *		  common nand_write_page function  
+ *		  common get_chip function 
+ *		- added oob_config structure for out of band layouts
+ *		- write_oob changed for partial programming
+ *		- read cache for faster access for subsequent reads
+ *		from the same page.
+ *		- support for different read/write address
+ *		- support for device ready/busy line
+ *		- read oob for more than one page enabled
+ *
+ *  02-27-2002	Thomas Gleixner (tglx@linutronix.de)
+ *		- command-delay can be programmed
+ *		- fixed exit from erase with callback-function enabled
+ *
+ *  03-21-2002  Thomas Gleixner (tglx@linutronix.de)
+ *		- DEBUG improvements provided by Elizabeth Clarke 
+ *		(eclarke@aminocom.com)
+ *		- added zero check for this->chip_delay
+ *
+ *  04-03-2002  Thomas Gleixner (tglx@linutronix.de)
+ *		- added added hw-driver supplied command and wait functions
+ *		- changed blocking for erase (erase suspend enabled)
+ *		- check pointers before accessing flash provided by
+ *		John Hall (john.hall@optionexist.co.uk)
+ *
+ *  04-09-2002  Thomas Gleixner (tglx@linutronix.de)
+ *		- nand_wait repaired
+ *
+ *  04-28-2002  Thomas Gleixner (tglx@linutronix.de)	
+ *		- OOB config defines moved to nand.h 
+ *
+ *  08-01-2002  Thomas Gleixner (tglx@linutronix.de)	
+ *		- changed my mailaddress, added pointer to tech/nand.html
+ *
+ *  08-07-2002 	Thomas Gleixner (tglx@linutronix.de)
+ *		forced bad block location to byte 5 of OOB, even if
+ *		CONFIG_MTD_NAND_ECC_JFFS2 is not set, to prevent
+ *		erase /dev/mtdX from erasing bad blocks and destroying
+ *		bad block info
+ *
+ *  08-10-2002 	Thomas Gleixner (tglx@linutronix.de)
+ *		Fixed writing tail of data. Thanks to Alice Hennessy
+ *		<ahennessy@mvista.com>.
  *
- * $Id: nand.c,v 1.12 2001/10/02 15:05:14 dwmw2 Exp $
+ *  08-10-2002 	Thomas Gleixner (tglx@linutronix.de)
+ *		nand_read_ecc and nand_write_page restructured to support
+ *		hardware ECC. Thanks to Steven Hein (ssh@sgi.com)
+ *		for basic implementation and suggestions.
+ *		3 new pointers in nand_chip structure:
+ *		calculate_ecc, correct_data, enabled_hwecc 					 
+ *		forcing all hw-drivers to support page cache
+ *		eccvalid_pos is now mandatory
+ *
+ *  08-17-2002	tglx: fixed signed/unsigned missmatch in write.c
+ *		Thanks to Ken Offer <koffer@arlut.utexas.edu> 	
+ *
+ *  08-29-2002  tglx: use buffered read/write only for non pagealigned 
+ *		access, speed up the aligned path by using the fs-buffer
+ *		reset chip removed from nand_select(), implicit done
+ *		only, when erase is interrupted
+ *		waitfuntion use yield, instead of schedule_timeout
+ *		support for 6byte/512byte hardware ECC
+ *		read_ecc, write_ecc extended for different oob-layout
+ *		selections: Implemented NAND_NONE_OOB, NAND_JFFS2_OOB,
+ *		NAND_YAFFS_OOB. fs-driver gives one of these constants
+ *		to select the oob-layout fitting the filesystem.
+ *		oobdata can be read together with the raw data, when
+ *		the fs-driver supplies a big enough buffer.
+ *		size = 12 * number of pages to read (256B pagesize)
+ *		       24 * number of pages to read (512B pagesize)
+ *		the buffer contains 8/16 byte oobdata and 4/8 byte
+ *		returncode from calculate_ecc
+ *		oobdata can be given from filesystem to program them
+ *		in one go together with the raw data. ECC codes are
+ *		filled in at the place selected by oobsel.
+ *
+ *  09-04-2002  tglx: fixed write_verify (John Hall (john.hall@optionexist.co.uk))
+ *
+ *  11-11-2002  tglx: fixed debug output in nand_write_page 
+ *		(John Hall (john.hall@optionexist.co.uk))
+ *
+ *  11-25-2002  tglx: Moved device ID/ manufacturer ID from nand_ids.h
+ *		Splitted device ID and manufacturer ID table. 
+ *		Removed CONFIG_MTD_NAND_ECC, as it defaults to ECC_NONE for
+ *		mtd->read / mtd->write and is controllable by the fs driver
+ *		for mtd->read_ecc / mtd->write_ecc
+ *		some minor cleanups
+ *
+ *  12-05-2002  tglx: Dave Ellis (DGE@sixnetio) provided the fix for
+ *		WRITE_VERIFY long time ago. Thanks for remembering me.	
+ *
+ *  02-14-2003  tglx: Reject non page aligned writes 	
+ *		Fixed ecc select in nand_write_page to match semantics. 
+ *
+ *  02-18-2003	tglx: Changed oobsel to pointer. Added a default oob-selector
+ *			
+ *  02-18-2003	tglx: Implemented oobsel again. Now it uses a pointer to
+ +		a structure, which will be supplied by a filesystem driver
+ *		If NULL is given, then the defaults (none or defaults
+ *		supplied by ioctl (MEMSETOOBSEL) are used.
+ *		For partitions the partition defaults are used (mtdpart.c)		
+ *	
+ * $Id: nand.c,v 1.45 2003/05/20 21:01:30 dwmw2 Exp $
  *
  * 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.
  *
- *  Overview:
- *   This is the generic MTD driver for NAND flash devices. It should be
- *   capable of working with almost all NAND chips currently available.
  */
 
 #include <linux/delay.h>
@@ -20,178 +140,426 @@
 #include <linux/types.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ids.h>
+#include <linux/mtd/nand_ecc.h>
 #include <linux/interrupt.h>
 #include <asm/io.h>
 
-#ifdef CONFIG_MTD_NAND_ECC
-#include <linux/mtd/nand_ecc.h>
-#endif
-
 /*
  * Macros for low-level register control
  */
-#define NAND_CTRL (*(volatile unsigned char *) \
-			((struct nand_chip *) mtd->priv)->CTRL_ADDR)
-#define nand_select()	NAND_CTRL &= ~this->NCE; \
-			nand_command(mtd, NAND_CMD_RESET, -1, -1); \
-			udelay (10);
-#define nand_deselect() NAND_CTRL |= ~this->NCE;
+#define nand_select()	this->hwcontrol(NAND_CTL_SETNCE);
+#define nand_deselect() this->hwcontrol(NAND_CTL_CLRNCE);
 
 /*
  * NAND low-level MTD interface functions
  */
-static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf);
+static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);
 static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-				size_t *retlen, u_char *buf, u_char *ecc_code);
-static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
-				size_t *retlen, u_char *buf);
-static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
-			size_t *retlen, const u_char *buf);
+			  size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel);
+static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);
+static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf);
 static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-				size_t *retlen, const u_char *buf,
-				u_char *ecc_code);
-static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
-				size_t *retlen, const u_char *buf);
+			   size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel);
+static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char *buf);
 static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
-				unsigned long count, loff_t to, size_t *retlen);
+			unsigned long count, loff_t to, size_t * retlen);
+static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs,
+			unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
 static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
 static void nand_sync (struct mtd_info *mtd);
+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf,  struct nand_oobinfo *oobsel);
+
 
 /*
  * Send command to NAND device
  */
-static void nand_command (struct mtd_info *mtd, unsigned command,
-				int column, int page_addr)
+static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
 {
 	register struct nand_chip *this = mtd->priv;
-	register unsigned long NAND_IO_ADDR = this->IO_ADDR;
+	register unsigned long NAND_IO_ADDR = this->IO_ADDR_W;
 
 	/* Begin command latch cycle */
-	NAND_CTRL |= this->CLE;
-
+	this->hwcontrol (NAND_CTL_SETCLE);
 	/*
 	 * Write out the command to the device.
 	 */
-	if (command != NAND_CMD_SEQIN)	
+	if (command != NAND_CMD_SEQIN)
 		writeb (command, NAND_IO_ADDR);
 	else {
 		if (mtd->oobblock == 256 && column >= 256) {
 			column -= 256;
-			writeb(NAND_CMD_RESET, NAND_IO_ADDR);
-			writeb(NAND_CMD_READOOB, NAND_IO_ADDR);
-			writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
-		}
-		else if (mtd->oobblock == 512 && column >= 256) {
+			writeb (NAND_CMD_READOOB, NAND_IO_ADDR);
+			writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
+		} else if (mtd->oobblock == 512 && column >= 256) {
 			if (column < 512) {
 				column -= 256;
-				writeb(NAND_CMD_READ1, NAND_IO_ADDR);
-				writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
-			}
-			else {
+				writeb (NAND_CMD_READ1, NAND_IO_ADDR);
+				writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
+			} else {
 				column -= 512;
-				writeb(NAND_CMD_READOOB, NAND_IO_ADDR);
-				writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
+				writeb (NAND_CMD_READOOB, NAND_IO_ADDR);
+				writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
 			}
-		}
-		else {
-			writeb(NAND_CMD_READ0, NAND_IO_ADDR);
-			writeb(NAND_CMD_SEQIN, NAND_IO_ADDR);
+		} else {
+			writeb (NAND_CMD_READ0, NAND_IO_ADDR);
+			writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
 		}
 	}
 
 	/* Set ALE and clear CLE to start address cycle */
-	NAND_CTRL &= ~this->CLE;
-	NAND_CTRL |= this->ALE;
+	this->hwcontrol (NAND_CTL_CLRCLE);
+
+	if (column != -1 || page_addr != -1) {
+		this->hwcontrol (NAND_CTL_SETALE);
 
-	/* Serially input address */
-	if (column != -1)
-		writeb (column, NAND_IO_ADDR);
-	if (page_addr != -1) {
-		writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR);
-		writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR);
-		/* One more address cycle for higher density devices */
-		if (mtd->size & 0x0c000000) {
-			writeb ((unsigned char) ((page_addr >> 16) & 0x0f),
-					NAND_IO_ADDR);
+		/* Serially input address */
+		if (column != -1)
+			writeb (column, NAND_IO_ADDR);
+		if (page_addr != -1) {
+			writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR);
+			writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR);
+			/* One more address cycle for higher density devices */
+			if (mtd->size & 0x0c000000) 
+				writeb ((unsigned char) ((page_addr >> 16) & 0x0f), NAND_IO_ADDR);
 		}
+		/* Latch in address */
+		this->hwcontrol (NAND_CTL_CLRALE);
 	}
+	
+	/* 
+	 * program and erase have their own busy handlers 
+	 * status and sequential in needs no delay
+	*/
+	switch (command) {
+			
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_STATUS:
+		return;
 
-	/* Latch in address */
-	NAND_CTRL &= ~this->ALE;
+	case NAND_CMD_RESET:
+		if (this->dev_ready)	
+			break;
+		this->hwcontrol (NAND_CTL_SETCLE);
+		writeb (NAND_CMD_STATUS, NAND_IO_ADDR);
+		this->hwcontrol (NAND_CTL_CLRCLE);
+		while ( !(readb (this->IO_ADDR_R) & 0x40));
+		return;
 
-	/* Pause for 15us */
-	udelay (15);
+	/* This applies to read commands */	
+	default:
+		/* 
+		 * If we don't have access to the busy pin, we apply the given
+		 * command delay
+		*/
+		if (!this->dev_ready) {
+			udelay (this->chip_delay);
+			return;
+		}	
+	}
+	
+	/* wait until command is processed */
+	while (!this->dev_ready());
 }
 
 /*
- * NAND read
+ *	Get chip for selected access
  */
-static int nand_read (struct mtd_info *mtd, loff_t from, size_t len,
-			size_t *retlen, u_char *buf)
+static inline void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state, int *erase_state)
 {
-#ifdef CONFIG_MTD_NAND_ECC
-	struct nand_chip *this = mtd->priv;
+
+	DECLARE_WAITQUEUE (wait, current);
+
+	/* 
+	 * Grab the lock and see if the device is available 
+	 * For erasing, we keep the spinlock until the
+	 * erase command is written. 
+	*/
+retry:
+	spin_lock_bh (&this->chip_lock);
+
+	if (this->state == FL_READY) {
+		this->state = new_state;
+		if (new_state != FL_ERASING)
+			spin_unlock_bh (&this->chip_lock);
+		return;
+	}
+
+	if (this->state == FL_ERASING) {
+		if (new_state != FL_ERASING) {
+			this->state = new_state;
+			spin_unlock_bh (&this->chip_lock);
+			nand_select ();	/* select in any case */
+			this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+			return;
+		}
+	}
+
+	set_current_state (TASK_UNINTERRUPTIBLE);
+	add_wait_queue (&this->wq, &wait);
+	spin_unlock_bh (&this->chip_lock);
+	schedule ();
+	remove_wait_queue (&this->wq, &wait);
+	goto retry;
+}
+
+/*
+ * Wait for command done. This applies to erase and program only
+ * Erase can take up to 400ms and program up to 20ms according to 
+ * general NAND and SmartMedia specs
+ *
+*/
+static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
+{
+
+	unsigned long	timeo = jiffies;
+	int	status;
+	
+	if (state == FL_ERASING)
+		 timeo += (HZ * 400) / 1000;
+	else
+		 timeo += (HZ * 20) / 1000;
+
+	spin_lock_bh (&this->chip_lock);
+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+
+	while (time_before(jiffies, timeo)) {		
+		/* Check, if we were interrupted */
+		if (this->state != state) {
+			spin_unlock_bh (&this->chip_lock);
+			return 0;
+		}
+		if (this->dev_ready) {
+			if (this->dev_ready ())
+				break;
+		}
+		if (readb (this->IO_ADDR_R) & 0x40)
+			break;
+						
+		spin_unlock_bh (&this->chip_lock);
+		yield ();
+		spin_lock_bh (&this->chip_lock);
+	}
+	status = (int) readb (this->IO_ADDR_R);
+	spin_unlock_bh (&this->chip_lock);
+
+	return status;
+}
+
+/*
+ *	Nand_page_program function is used for write and writev !
+ *	This function will always program a full page of data
+ *	If you call it with a non page aligned buffer, you're lost :)
+ */
+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf,  struct nand_oobinfo *oobsel)
+{
+	int 	i, status;
+	u_char	ecc_code[6], *oob_data;
+	int	eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
+	int  	*oob_config = oobsel->eccpos;
 	
-	return nand_read_ecc (mtd, from, len, retlen, buf, this->ecc_code_buf);
-#else
-	return nand_read_ecc (mtd, from, len, retlen, buf, NULL);
+	/* pad oob area, if we have no oob buffer from fs-driver */
+	if (!oob_buf) {
+		oob_data = &this->data_buf[mtd->oobblock];
+		for (i = 0; i < mtd->oobsize; i++)
+			oob_data[i] = 0xff;
+	} else 
+		oob_data = oob_buf;
+	
+	/* Send command to begin auto page programming */
+	this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page);
+
+	/* Write out complete page of data, take care of eccmode */
+	switch (eccmode) {
+	/* No ecc and software ecc 3/256, write all */
+	case NAND_ECC_NONE:
+		printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
+		for (i = 0; i < mtd->oobblock; i++) 
+			writeb ( this->data_poi[i] , this->IO_ADDR_W);
+		break;
+	case NAND_ECC_SOFT:
+		this->calculate_ecc (&this->data_poi[0], &(ecc_code[0]));
+		for (i = 0; i < 3; i++)
+			oob_data[oob_config[i]] = ecc_code[i];
+		/* Calculate and write the second ECC for 512 Byte page size */
+		if (mtd->oobblock == 512) {
+			this->calculate_ecc (&this->data_poi[256], &(ecc_code[3]));
+			for (i = 3; i < 6; i++)
+				oob_data[oob_config[i]] = ecc_code[i];
+		} 
+		for (i = 0; i < mtd->oobblock; i++) 
+			writeb ( this->data_poi[i] , this->IO_ADDR_W);
+		break;
+		
+	/* Hardware ecc 3 byte / 256 data, write first half, get ecc, then second, if 512 byte pagesize */	
+	case NAND_ECC_HW3_256:		
+		this->enable_hwecc (NAND_ECC_WRITE);	/* enable hardware ecc logic for write */
+		for (i = 0; i < mtd->eccsize; i++) 
+			writeb ( this->data_poi[i] , this->IO_ADDR_W);
+		
+		this->calculate_ecc (NULL, &(ecc_code[0]));
+		for (i = 0; i < 3; i++)
+			oob_data[oob_config[i]] = ecc_code[i];
+			
+		if (mtd->oobblock == 512) {
+			this->enable_hwecc (NAND_ECC_WRITE);	/* enable hardware ecc logic for write*/
+			for (i = mtd->eccsize; i < mtd->oobblock; i++) 
+				writeb ( this->data_poi[i] , this->IO_ADDR_W);
+			this->calculate_ecc (NULL, &(ecc_code[3]));
+			for (i = 3; i < 6; i++)
+				oob_data[oob_config[i]] = ecc_code[i];
+		}
+		break;
+				
+	/* Hardware ecc 3 byte / 512 byte data, write full page */	
+	case NAND_ECC_HW3_512:	
+		this->enable_hwecc (NAND_ECC_WRITE);	/* enable hardware ecc logic */
+		for (i = 0; i < mtd->oobblock; i++) 
+			writeb ( this->data_poi[i] , this->IO_ADDR_W);
+		this->calculate_ecc (NULL, &(ecc_code[0]));
+		for (i = 0; i < 3; i++)
+			oob_data[oob_config[i]] = ecc_code[i];
+		break;
+
+	/* Hardware ecc 6 byte / 512 byte data, write full page */	
+	case NAND_ECC_HW6_512:	
+		this->enable_hwecc (NAND_ECC_WRITE);	/* enable hardware ecc logic */
+		for (i = 0; i < mtd->oobblock; i++) 
+			writeb ( this->data_poi[i] , this->IO_ADDR_W);
+		this->calculate_ecc (NULL, &(ecc_code[0]));
+		for (i = 0; i < 6; i++)
+			oob_data[oob_config[i]] = ecc_code[i];
+		break;
+		
+	default:
+		printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
+		BUG();	
+	}	
+	
+	/* Write out OOB data */
+	for (i = 0; i <  mtd->oobsize; i++)
+		writeb ( oob_data[i] , this->IO_ADDR_W);
+
+	/* Send command to actually program the data */
+	this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+	/* call wait ready function */
+	status = this->waitfunc (mtd, this, FL_WRITING);
+
+	/* See if device thinks it succeeded */
+	if (status & 0x01) {
+		DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
+		return -EIO;
+	}
+
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+	/*
+	 * The NAND device assumes that it is always writing to
+	 * a cleanly erased page. Hence, it performs its internal
+	 * write verification only on bits that transitioned from
+	 * 1 to 0. The device does NOT verify the whole page on a
+	 * byte by byte basis. It is possible that the page was
+	 * not completely erased or the page is becoming unusable
+	 * due to wear. The read with ECC would catch the error
+	 * later when the ECC page check fails, but we would rather
+	 * catch it early in the page write stage. Better to write
+	 * no data than invalid data.
+	 */
+
+	/* Send command to read back the page */
+	this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);
+	/* Loop through and verify the data */
+	for (i = 0; i < mtd->oobblock; i++) {
+		if (this->data_poi[i] != readb (this->IO_ADDR_R)) {
+			DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
+			return -EIO;
+		}
+	}
+
+	/* check, if we have a fs-supplied oob-buffer */
+	if (oob_buf) {
+		for (i = 0; i < mtd->oobsize; i++) {
+			if (oob_data[i] != readb (this->IO_ADDR_R)) {
+				DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
+				return -EIO;
+			}
+		}
+	} else {
+		if (eccmode != NAND_ECC_NONE) {
+			int ecc_bytes = 0;
+
+			switch (this->eccmode) {
+			case NAND_ECC_SOFT:
+			case NAND_ECC_HW3_256: ecc_bytes = (mtd->oobblock == 512) ? 6 : 3; break;
+			case NAND_ECC_HW3_512: ecc_bytes = 3; break;
+			case NAND_ECC_HW6_512: ecc_bytes = 6; break;
+			}
+
+			for (i = 0; i < mtd->oobsize; i++)
+				oob_data[i] = readb (this->IO_ADDR_R);
+
+			for (i = 0; i < ecc_bytes; i++) {
+				if (oob_data[oob_config[i]] != ecc_code[i]) {
+					DEBUG (MTD_DEBUG_LEVEL0,
+					       "%s: Failed ECC write "
+				       "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i);
+				return -EIO;
+				}
+			}
+		}
+	}
 #endif
+	return 0;
 }
 
 /*
+*	Use NAND read ECC
+*/
+static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
+{
+	return (nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL));
+}			   
+
+
+/*
  * NAND read with ECC
  */
 static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-				size_t *retlen, u_char *buf, u_char *ecc_code)
+			  size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
 {
-	int j, col, page, state;
+	int j, col, page, end, ecc;
 	int erase_state = 0;
+	int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
-#ifdef CONFIG_MTD_NAND_ECC
-	int ecc_result;
+	u_char *data_poi, *oob_data = oob_buf;
 	u_char ecc_calc[6];
-#endif
+	u_char ecc_code[6];
+	int 	eccmode;
+	int	*oob_config;
+
+	// use chip default if zero
+	if (oobsel == NULL)
+		oobsel = &mtd->oobinfo;
+		
+	eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
+	oob_config = oobsel->eccpos;
 
-	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from,
-		(int) len);
+	DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
 
 	/* Do not allow reads past end of device */
 	if ((from + len) > mtd->size) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_read_ecc: Attempt read beyond end of device\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
 		*retlen = 0;
 		return -EINVAL;
 	}
 
 	/* Grab the lock and see if the device is available */
-retry:
-	spin_lock_bh (&this->chip_lock);
+	nand_get_chip (this, mtd ,FL_READING, &erase_state);
 
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_READING;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	case FL_ERASING:
-		this->state = FL_READING;
-		erase_state = 1;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
-
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
+	/* Select the NAND device */
+	nand_select ();
 
 	/* First we calculate the starting page */
 	page = from >> this->page_shift;
@@ -199,122 +567,127 @@
 	/* Get raw starting column */
 	col = from & (mtd->oobblock - 1);
 
-	/* State machine for devices having pages larger than 256 bytes */
-	state = (col < mtd->eccsize) ? 0 : 1;
-
-	/* Calculate column address within ECC block context */
-	col = (col >= mtd->eccsize) ? (col - mtd->eccsize) : col;
-
-	/* Initialize return value */
-	*retlen = 0;
-
-	/* Select the NAND device */
-	nand_select ();
+	end = mtd->oobblock;
+	ecc = mtd->eccsize;
 
+	/* Send the read command */
+	this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
+	
 	/* Loop until all data read */
-	while (*retlen < len) {
-
-#ifdef CONFIG_MTD_NAND_ECC
-		/* Send the read command */
-		if (!state)
-			nand_command (mtd, NAND_CMD_READ0, 0x00, page);
-		else 
-			nand_command (mtd, NAND_CMD_READ1, 0x00, page);
-
-		/* Read in a block big enough for ECC */
-		for (j=0 ; j < mtd->eccsize ; j++)
-			this->data_buf[j] = readb (this->IO_ADDR);
-
-		/* Read in the out-of-band data */
-		if (!state) {
-			nand_command (mtd, NAND_CMD_READOOB, 0x00, page);
-			for (j=0 ; j<3 ; j++)
-				ecc_code[j] = readb(this->IO_ADDR);
-			nand_command (mtd, NAND_CMD_READ0, 0x00, page);
-		}
-		else {
-			nand_command (mtd, NAND_CMD_READOOB, 0x03, page);
-			for (j=3 ; j<6 ; j++)
-				ecc_code[j] = readb(this->IO_ADDR);
-			nand_command (mtd, NAND_CMD_READ0, 0x00, page);
-		}
-
-		/* Calculate the ECC and verify it */
-		if (!state) {
-			nand_calculate_ecc (&this->data_buf[0],
-						&ecc_calc[0]);
-			ecc_result = nand_correct_data (&this->data_buf[0],
-						&ecc_code[0], &ecc_calc[0]);
-		}
-		else {
-			nand_calculate_ecc (&this->data_buf[0],
-						&ecc_calc[3]);
-			ecc_result = nand_correct_data (&this->data_buf[0],
-						&ecc_code[3], &ecc_calc[3]);
-		}
-		if (ecc_result == -1) {
-			DEBUG (MTD_DEBUG_LEVEL0,
-				"nand_read_ecc: " \
-				"Failed ECC read, page 0x%08x\n", page);
-			nand_deselect ();
-			spin_lock_bh (&this->chip_lock);
-			if (erase_state)
-				this->state = FL_ERASING;
+	while (read < len) {
+		
+		/* If we have consequent page reads, apply delay or wait for ready/busy pin */
+		if (read) {
+			if (!this->dev_ready) 
+				udelay (this->chip_delay);
 			else
-				this->state = FL_READY;
-			wake_up (&this->wq);
-			spin_unlock_bh (&this->chip_lock);
-			return -EIO;
+				while (!this->dev_ready());	
 		}
 
-		/* Read the data from ECC data buffer into return buffer */
-		if ((*retlen + (mtd->eccsize - col)) >= len) {
-			while (*retlen < len)
-				buf[(*retlen)++] = this->data_buf[col++];
-			/* We're done */
-			continue;
-		}
-		else
-			for (j=col ; j < mtd->eccsize ; j++)
-				buf[(*retlen)++] = this->data_buf[j];
-#else
-		/* Send the read command */
-		if (!state)
-			nand_command (mtd, NAND_CMD_READ0, col, page);
+		/* 
+		 * If the read is not page aligned, we have to read into data buffer
+		 * due to ecc, else we read into return buffer direct
+		 */
+		if (!col && (len - read) >= end)  
+			data_poi = &buf[read];
 		else 
-			nand_command (mtd, NAND_CMD_READ1, col, page);
+			data_poi = this->data_buf;
 
-		/* Read the data directly into the return buffer */ 
-		if ((*retlen + (mtd->eccsize - col)) >= len) {
-			while (*retlen < len)
-				buf[(*retlen)++] = readb (this->IO_ADDR);
-			/* We're done */
-			continue;
-		}
-		else
-			for (j=col ; j < mtd->eccsize ; j++)
-				buf[(*retlen)++] = readb (this->IO_ADDR);
-#endif
+		/* get oob area, if we have no oob buffer from fs-driver */
+		if (!oob_buf) {
+			oob_data = &this->data_buf[end];
+			oob = 0;
+		} 	
+			
+		j = 0;
+		switch (eccmode) {
+		case NAND_ECC_NONE:	/* No ECC, Read in a page */		
+			printk (KERN_WARNING "Reading data from NAND FLASH without ECC is not recommended\n");
+			while (j < end)
+				data_poi[j++] = readb (this->IO_ADDR_R);
+			break;
+			
+		case NAND_ECC_SOFT:	/* Software ECC 3/256: Read in a page + oob data */
+			while (j < end)
+				data_poi[j++] = readb (this->IO_ADDR_R);
+			this->calculate_ecc (&data_poi[0], &ecc_calc[0]);
+			if (mtd->oobblock == 512)
+				this->calculate_ecc (&data_poi[256], &ecc_calc[3]);
+			break;	
+			
+		case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data: Read in first 256 byte, get ecc, */
+			this->enable_hwecc (NAND_ECC_READ);	
+			while (j < ecc)
+				data_poi[j++] = readb (this->IO_ADDR_R);
+			this->calculate_ecc (&data_poi[0], &ecc_calc[0]);	/* read from hardware */
+			
+			if (mtd->oobblock == 512) { /* read second, if pagesize = 512 */
+				this->enable_hwecc (NAND_ECC_READ);	
+				while (j < end)
+					data_poi[j++] = readb (this->IO_ADDR_R);
+				this->calculate_ecc (&data_poi[256], &ecc_calc[3]); /* read from hardware */
+			}					
+			break;						
+				
+		case NAND_ECC_HW3_512:	
+		case NAND_ECC_HW6_512: /* Hardware ECC 3/6 byte / 512 byte data : Read in a page  */
+			this->enable_hwecc (NAND_ECC_READ);	
+			while (j < end)
+				data_poi[j++] = readb (this->IO_ADDR_R);
+			this->calculate_ecc (&data_poi[0], &ecc_calc[0]);	/* read from hardware */
+			break;
 
-		/*
-		 * If the amount of data to be read is greater than
-		 * (256 - col), then all subsequent reads will take
-		 * place on page or half-page (in the case of 512 byte
-		 * page devices) aligned boundaries and the column
-		 * address will be zero. Setting the column address to
-		 * to zero after the first read allows us to simplify
-		 * the reading of data and the if/else statements above.
-		 */
-		if (col)
-			col = 0x00;
+		default:
+			printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
+			BUG();	
+		}
 
+		/* read oobdata */
+		for (j = 0; j <  mtd->oobsize; j++) 
+			oob_data[oob + j] = readb (this->IO_ADDR_R);
+		
+		/* Skip ECC, if not active */
+		if (eccmode == NAND_ECC_NONE)
+			goto readdata;	
+		
+		/* Pick the ECC bytes out of the oob data */
+		for (j = 0; j < 6; j++)
+			ecc_code[j] = oob_data[oob + oob_config[j]];
+
+		/* correct data, if neccecary */
+		ecc_status = this->correct_data (&data_poi[0], &ecc_code[0], &ecc_calc[0]);
+		/* check, if we have a fs supplied oob-buffer */
+		if (oob_buf) { 
+			oob += mtd->oobsize;
+			*((int *)&oob_data[oob]) = ecc_status;
+			oob += sizeof(int);
+		}
+		if (ecc_status == -1) {	
+			DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
+			ecc_failed++;
+		}
+		
+		if (mtd->oobblock == 512 && eccmode != NAND_ECC_HW3_512) {
+			ecc_status = this->correct_data (&data_poi[256], &ecc_code[3], &ecc_calc[3]);
+			if (oob_buf) {
+				*((int *)&oob_data[oob]) = ecc_status;
+				oob += sizeof(int);
+			}
+			if (ecc_status == -1) {
+				DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
+				ecc_failed++;
+			}
+		}
+readdata:
+		if (col || (len - read) < end) { 
+			for (j = col; j < end && read < len; j++)
+				buf[read++] = data_poi[j];
+		} else		
+			read += mtd->oobblock;
+		/* For subsequent reads align to page boundary. */
+		col = 0;
 		/* Increment page address */
-		if ((mtd->oobblock == 256) || state)
-			page++;
-
-		/* Toggle state machine */
-		if (mtd->oobblock == 512)
-			state = state ? 0 : 1;
+		page++;
 	}
 
 	/* De-select the NAND device */
@@ -322,31 +695,29 @@
 
 	/* Wake up anyone waiting on the device */
 	spin_lock_bh (&this->chip_lock);
-	if (erase_state)
-		this->state = FL_ERASING;
-	else
-		this->state = FL_READY;
+	this->state = FL_READY;
 	wake_up (&this->wq);
 	spin_unlock_bh (&this->chip_lock);
-	
-	/* Return happy */
-	return 0;
+
+	/*
+	 * Return success, if no ECC failures, else -EIO
+	 * fs driver will take care of that, because
+	 * retlen == desired len and result == -EIO
+	 */
+	*retlen = read;
+	return ecc_failed ? -EIO : 0;
 }
 
 /*
  * NAND read out-of-band
  */
-static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
-				size_t *retlen, u_char *buf)
+static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
 {
 	int i, col, page;
 	int erase_state = 0;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
-	
-	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from,
-		(int) len);
+
+	DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
 
 	/* Shift to get page */
 	page = ((int) from) >> this->page_shift;
@@ -357,59 +728,36 @@
 	/* Initialize return length value */
 	*retlen = 0;
 
-	/* Do not allow read past end of page */
-	if ((col + len) > mtd->oobsize) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_read_oob: Attempt read past end of page " \
-			"0x%08x, column %i, length %i\n", page, col, len);
+	/* Do not allow reads past end of device */
+	if ((from + len) > mtd->size) {
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");
+		*retlen = 0;
 		return -EINVAL;
 	}
 
-retry:
 	/* Grab the lock and see if the device is available */
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_READING;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	case FL_ERASING:
-		this->state = FL_READING;
-		erase_state = 1;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
-
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
+	nand_get_chip (this, mtd , FL_READING, &erase_state);
 
 	/* Select the NAND device */
 	nand_select ();
 
 	/* Send the read command */
-	nand_command (mtd, NAND_CMD_READOOB, col, page);	
-
-	/* Read the data */
-	for (i = 0 ; i < len ; i++)
-		buf[i] = readb (this->IO_ADDR);
-
+	this->cmdfunc (mtd, NAND_CMD_READOOB, col, page);
+	/* 
+	 * Read the data, if we read more than one page
+	 * oob data, let the device transfer the data !
+	 */
+	for (i = 0; i < len; i++) {
+		buf[i] = readb (this->IO_ADDR_R);
+		if ((col++ & (mtd->oobsize - 1)) == (mtd->oobsize - 1))
+			udelay (this->chip_delay);
+	}
 	/* De-select the NAND device */
 	nand_deselect ();
 
 	/* Wake up anyone waiting on the device */
 	spin_lock_bh (&this->chip_lock);
-	if (erase_state)
-		this->state = FL_ERASING;
-	else
-		this->state = FL_READY;
+	this->state = FL_READY;
 	wake_up (&this->wq);
 	spin_unlock_bh (&this->chip_lock);
 
@@ -418,265 +766,80 @@
 	return 0;
 }
 
+#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0
+
 /*
- * NAND write
- */
-static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,
-			size_t *retlen, const u_char *buf)
+*	Use NAND write ECC
+*/
+static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf)
 {
-#ifdef CONFIG_MTD_NAND_ECC
-	struct nand_chip *this = mtd->priv;
-	
-	return nand_write_ecc (mtd, to, len, retlen, buf, this->ecc_code_buf);
-#else
-	return nand_write_ecc (mtd, to, len, retlen, buf, NULL);
-#endif
-}
-
+	return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL));
+}			   
 /*
  * NAND write with ECC
  */
 static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-				size_t *retlen, const u_char *buf,
-				u_char *ecc_code)
+			   size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel)
 {
-	int i, page, col, cnt, status;
+	int page, ret = 0, oob = 0, written = 0;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
-#ifdef CONFIG_MTD_NAND_ECC
-	int ecc_bytes = (mtd->oobblock == 512) ? 6 : 3;
-#endif
 
-	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to,
-		(int) len);
+	DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
 
-	/* Do not allow write past end of page */
+	/* Do not allow write past end of device */
 	if ((to + len) > mtd->size) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_write_ecc: Attempted write past end of device\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n");
 		return -EINVAL;
 	}
 
-retry:
-	/* Grab the lock and see if the device is available */
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_WRITING;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
+	/* reject writes, which are not page aligned */	
+	if (NOTALIGNED (to) || NOTALIGNED(len)) {
+		printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
+		return -EINVAL;
+	}
 
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
+	// if oobsel is NULL, use chip defaults
+	if (oobsel == NULL) 
+		oobsel = &mtd->oobinfo;		
 
 	/* Shift to get page */
 	page = ((int) to) >> this->page_shift;
 
-	/* Get the starting column */
-	col = to & (mtd->oobblock - 1);
-
-	/* Initialize return length value */
-	*retlen = 0;
+	/* Grab the lock and see if the device is available */
+	nand_get_chip (this, mtd, FL_WRITING, NULL);
 
 	/* Select the NAND device */
 	nand_select ();
 
 	/* Check the WP bit */
-	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-	if (!(readb (this->IO_ADDR) & 0x80)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_write_ecc: Device is write protected!!!\n");
-		nand_deselect ();
-		spin_lock_bh (&this->chip_lock);
-		this->state = FL_READY;
-		wake_up (&this->wq);
-		spin_unlock_bh (&this->chip_lock);
-		return -EIO;
+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR_R) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n");
+		ret = -EIO;
+		goto out;
 	}
 
 	/* Loop until all data is written */
-	while (*retlen < len) {
-		/* Write data into buffer */
-		if ((col + len) >= mtd->oobblock)
-			for(i=col, cnt=0 ; i < mtd->oobblock ; i++, cnt++)
-				this->data_buf[i] = buf[(*retlen + cnt)];
-		else
-			for(i=col, cnt=0 ; cnt < (len - *retlen) ; i++, cnt++)
-				this->data_buf[i] = buf[(*retlen + cnt)];
+	while (written < len) {
+		int cnt = mtd->oobblock;
+		this->data_poi = (u_char*) &buf[written];
+		/* We use the same function for write and writev */
+		if (eccbuf) {
+			ret = nand_write_page (mtd, this, page, &eccbuf[oob], oobsel);
+			oob += mtd->oobsize;
+		} else 
+			ret = nand_write_page (mtd, this, page, NULL, oobsel);	
 		
-#ifdef CONFIG_MTD_NAND_ECC
-		/* Zero out the ECC array */
-		for (i=0 ; i < 6 ; i++)
-			ecc_code[i] = 0x00;
-
-		/* Calculate and write the ECC if we have enough data */
-		if ((col < mtd->eccsize) &&
-			((col + (len - *retlen)) >= mtd->eccsize)) {
-			nand_command (mtd, NAND_CMD_READ0, col, page);
-			for (i=0 ; i < col ; i++)
-				this->data_buf[i] = readb (this->IO_ADDR); 
-			nand_calculate_ecc (&this->data_buf[0], &ecc_code[0]);
-			for (i=0 ; i<3 ; i++)
-				this->data_buf[(mtd->oobblock + i)] =
-					ecc_code[i];
-		}
-
-		/* Calculate and write the second ECC if we have enough data */
-		if ((mtd->oobblock == 512) &&
-			((col + (len - *retlen)) >= mtd->oobblock)) {
-			nand_calculate_ecc (&this->data_buf[256], &ecc_code[3]);
-			for (i=3 ; i<6 ; i++)
-				this->data_buf[(mtd->oobblock + i)] =
-					ecc_code[i];
-		}
-
-		/* Write ones for partial page programming */
-		for (i=ecc_bytes ; i < mtd->oobsize ; i++)
-			this->data_buf[(mtd->oobblock + i)] = 0xff;
-#else
-		/* Write ones for partial page programming */
-		for (i=mtd->oobblock ; i < (mtd->oobblock + mtd->oobsize) ; i++)
-			this->data_buf[i] = 0xff;
-#endif
-
-		/* Write pre-padding bytes into buffer */
-		for (i=0 ; i < col ; i++)
-			this->data_buf[i] = 0xff;
-
-		/* Write post-padding bytes into buffer */
-		if ((col + (len - *retlen)) < mtd->oobblock) {
-			for(i=(col + cnt) ; i < mtd->oobblock ; i++)
-				this->data_buf[i] = 0xff;
-		}
-
-		/* Send command to begin auto page programming */
-		nand_command (mtd, NAND_CMD_SEQIN, 0x00, page);
-
-		/* Write out complete page of data */
-		for (i=0 ; i < (mtd->oobblock + mtd->oobsize) ; i++)
-			writeb (this->data_buf[i], this->IO_ADDR);
-
-		/* Send command to actually program the data */
-		nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);
-
-		/*
-		 * Wait for program operation to complete. This could
-		 * take up to 3000us (3ms) on some devices, so we try
-		 * and exit as quickly as possible.
-		 */
-		status = 0;
-		for (i=0 ; i<24 ; i++) {
-			/* Delay for 125us */
-			udelay (125);
-
-			/* Check the status */
-			nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-			status = (int) readb (this->IO_ADDR);
-			if (status & 0x40)
-				break;
-		}
-
-		/* See if device thinks it succeeded */
-		if (status & 0x01) {
-			DEBUG (MTD_DEBUG_LEVEL0,
-				"nand_write_ecc: " \
-				"Failed write, page 0x%08x, " \
-				"%6i bytes were succesful\n", page, *retlen);
-			nand_deselect ();
-			spin_lock_bh (&this->chip_lock);
-			this->state = FL_READY;
-			wake_up (&this->wq);
-			spin_unlock_bh (&this->chip_lock);
-			return -EIO;
-		}
-
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-		/*
-		 * The NAND device assumes that it is always writing to
-		 * a cleanly erased page. Hence, it performs its internal
-		 * write verification only on bits that transitioned from
-		 * 1 to 0. The device does NOT verify the whole page on a
-		 * byte by byte basis. It is possible that the page was
-		 * not completely erased or the page is becoming unusable
-		 * due to wear. The read with ECC would catch the error
-		 * later when the ECC page check fails, but we would rather
-		 * catch it early in the page write stage. Better to write
-		 * no data than invalid data.
-		 */
-		
-		/* Send command to read back the page */
-		if (col < mtd->eccsize)
-			nand_command (mtd, NAND_CMD_READ0, col, page);
-		else
-			nand_command (mtd, NAND_CMD_READ1, col - 256, page);
-
-		/* Loop through and verify the data */
-		for (i=col ; i < cnt ; i++) {
-			if (this->data_buf[i] != readb (this->IO_ADDR)) {
-				DEBUG (MTD_DEBUG_LEVEL0,
-					"nand_write_ecc: " \
-					"Failed write verify, page 0x%08x, " \
-					"%6i bytes were succesful\n",
-					page, *retlen);
-				nand_deselect ();
-				spin_lock_bh (&this->chip_lock);
-				this->state = FL_READY;
-				wake_up (&this->wq);
-				spin_unlock_bh (&this->chip_lock);
-				return -EIO;
-			}
-		}
-
-#ifdef CONFIG_MTD_NAND_ECC
-		/*
-		 * We also want to check that the ECC bytes wrote
-		 * correctly for the same reasons stated above.
-		 */
-		nand_command (mtd, NAND_CMD_READOOB, 0x00, page);
-		for (i=0 ; i < ecc_bytes ; i++) {
-			if ((readb (this->IO_ADDR) != ecc_code[i]) &&
-					ecc_code[i]) {
-				DEBUG (MTD_DEBUG_LEVEL0,
-					"nand_write_ecc: Failed ECC write " \
-					"verify, page 0x%08x, " \
-					"%6i bytes were succesful\n",
-					page, i);
-				nand_deselect ();
-				spin_lock_bh (&this->chip_lock);
-				this->state = FL_READY;
-				wake_up (&this->wq);
-				spin_unlock_bh (&this->chip_lock);
-				return -EIO;
-			}
-		}
-#endif
-
-#endif
-
-		/*
-		 * If we are writing a large amount of data and/or it
-		 * crosses page or half-page boundaries, we set the
-		 * the column to zero. It simplifies the program logic.
-		 */
-		if (col)
-			col = 0x00;
+		if (ret)
+			goto out;
 
 		/* Update written bytes count */
-		*retlen += cnt;
-
+		written += cnt;
 		/* Increment page address */
 		page++;
 	}
 
+out:
 	/* De-select the NAND device */
 	nand_deselect ();
 
@@ -686,24 +849,19 @@
 	wake_up (&this->wq);
 	spin_unlock_bh (&this->chip_lock);
 
-	/* Return happy */
-	*retlen = len;
-	return 0;
+	*retlen = written;
+	return ret;
 }
 
 /*
  * NAND write out-of-band
  */
-static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
-				size_t *retlen, const u_char *buf)
+static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf)
 {
-	int i, column, page, status;
+	int i, column, page, status, ret = 0;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
-	
-	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to,
-		(int) len);
+
+	DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
 
 	/* Shift to get page */
 	page = ((int) to) >> this->page_shift;
@@ -716,105 +874,65 @@
 
 	/* Do not allow write past end of page */
 	if ((column + len) > mtd->oobsize) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_write_oob: Attempt to write past end of page\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
 		return -EINVAL;
 	}
 
-retry:
 	/* Grab the lock and see if the device is available */
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_WRITING;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
-
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
+	nand_get_chip (this, mtd, FL_WRITING, NULL);
 
 	/* Select the NAND device */
 	nand_select ();
 
 	/* Check the WP bit */
-	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-	if (!(readb (this->IO_ADDR) & 0x80)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_write_oob: Device is write protected!!!\n");
-		nand_deselect ();
-		spin_lock_bh (&this->chip_lock);
-		this->state = FL_READY;
-		wake_up (&this->wq);
-		spin_unlock_bh (&this->chip_lock);
-		return -EIO;
+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR_R) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n");
+		ret = -EIO;
+		goto out;
 	}
 
 	/* Write out desired data */
-	nand_command (mtd, NAND_CMD_SEQIN, column + 512, page);
-	for (i=0 ; i<len ; i++)
-		writeb (buf[i], this->IO_ADDR);
+	this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page);
+	/* prepad 0xff for partial programming */
+	for (i = 0; i < column; i++)
+		writeb (0xff, this->IO_ADDR_W);
+	/* write data */
+	for (i = 0; i < len; i++)
+		writeb (buf[i], this->IO_ADDR_W);	
+	/* postpad 0xff for partial programming */
+	for (i = len + column; i < mtd->oobsize; i++)
+		writeb (0xff, this->IO_ADDR_W);
 
 	/* Send command to program the OOB data */
-	nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);
+	this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
 
-	/*
-	 * Wait for program operation to complete. This could
-	 * take up to 3000us (3ms) on some devices, so we try
-	 * and exit as quickly as possible.
-	 */
-	status = 0;
-	for (i=0 ; i<24 ; i++) {
-		/* Delay for 125us */
-		udelay (125);
-
-		/* Check the status */
-		nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-		status = (int) readb (this->IO_ADDR);
-		if (status & 0x40)
-			break;
-	}
+	status = this->waitfunc (mtd, this, FL_WRITING);
 
 	/* See if device thinks it succeeded */
 	if (status & 0x01) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_write_oob: " \
-			"Failed write, page 0x%08x\n", page);
-		nand_deselect ();
-		spin_lock_bh (&this->chip_lock);
-		this->state = FL_READY;
-		wake_up (&this->wq);
-		spin_unlock_bh (&this->chip_lock);
-		return -EIO;
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
+		ret = -EIO;
+		goto out;
 	}
+	/* Return happy */
+	*retlen = len;
 
 #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
 	/* Send command to read back the data */
-	nand_command (mtd, NAND_CMD_READOOB, column, page);
+	this->cmdfunc (mtd, NAND_CMD_READOOB, column, page);
 
 	/* Loop through and verify the data */
-	for (i=0 ; i<len ; i++) {
-		if (buf[i] != readb (this->IO_ADDR)) {
-			DEBUG (MTD_DEBUG_LEVEL0,
-				"nand_write_oob: " \
-				"Failed write verify, page 0x%08x\n", page);
-			nand_deselect ();
-			spin_lock_bh (&this->chip_lock);
-			this->state = FL_READY;
-			wake_up (&this->wq);
-			spin_unlock_bh (&this->chip_lock);
-			return -EIO;
+	for (i = 0; i < len; i++) {
+		if (buf[i] != readb (this->IO_ADDR_R)) {
+			DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
+			ret = -EIO;
+			goto out;
 		}
 	}
 #endif
 
+out:
 	/* De-select the NAND device */
 	nand_deselect ();
 
@@ -824,258 +942,117 @@
 	wake_up (&this->wq);
 	spin_unlock_bh (&this->chip_lock);
 
-	/* Return happy */
-	*retlen = len;
-	return 0;
+	return ret;
 }
 
+
 /*
  * NAND write with iovec
  */
-static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,
-				unsigned long count, loff_t to, size_t *retlen)
+static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, 
+		loff_t to, size_t * retlen)
+{
+	return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, 0));	
+}
+
+static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, 
+		loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel)
 {
-	int i, page, col, cnt, len, total_len, status;
+	int i, page, len, total_len, ret = 0, written = 0;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
-#ifdef CONFIG_MTD_NAND_ECC
-	int ecc_bytes = (mtd->oobblock == 512) ? 6 : 3;
-#endif
 
 	/* Calculate total length of data */
 	total_len = 0;
-	for (i=0 ; i < count ; i++)
+	for (i = 0; i < count; i++)
 		total_len += (int) vecs[i].iov_len;
 
 	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_writev: to = 0x%08x, len = %i\n", (unsigned int) to,
-			(unsigned int) total_len);
+	       "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count);
 
 	/* Do not allow write past end of page */
 	if ((to + total_len) > mtd->size) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_writev: Attempted write past end of device\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n");
 		return -EINVAL;
 	}
 
-retry:
-	/* Grab the lock and see if the device is available */
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_WRITING;
-		spin_unlock_bh (&this->chip_lock);
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
+	/* reject writes, which are not page aligned */	
+	if (NOTALIGNED (to) || NOTALIGNED(total_len)) {
+		printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
+		return -EINVAL;
+	}
 
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
+	// if oobsel is NULL, use chip defaults
+	if (oobsel == NULL) 
+		oobsel = &mtd->oobinfo;		
 
 	/* Shift to get page */
 	page = ((int) to) >> this->page_shift;
 
-	/* Get the starting column */
-	col = to & (mtd->oobblock - 1);
-
-	/* Initialize return length value */
-	*retlen = 0;
+	/* Grab the lock and see if the device is available */
+	nand_get_chip (this, mtd, FL_WRITING, NULL);
 
 	/* Select the NAND device */
 	nand_select ();
 
 	/* Check the WP bit */
-	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-	if (!(readb (this->IO_ADDR) & 0x80)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_writev: Device is write protected!!!\n");
-		nand_deselect ();
-		spin_lock_bh (&this->chip_lock);
-		this->state = FL_READY;
-		wake_up (&this->wq);
-		spin_unlock_bh (&this->chip_lock);
-		return -EIO;
+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR_R) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Device is write protected!!!\n");
+		ret = -EIO;
+		goto out;
 	}
 
 	/* Loop until all iovecs' data has been written */
-	cnt = col;
 	len = 0;
 	while (count) {
-		/* Do any need pre-fill for partial page programming */
-		for (i=0 ; i < cnt ; i++)
-			this->data_buf[i] = 0xff;
-
-		/*
-		 * Read data out of each tuple until we have a full page
-		 * to write or we've read all the tuples.
+		/* 
+		 *  Check, if the tuple gives us not enough data for a 
+		 *  full page write. Then we can use the iov direct, 
+		 *  else we have to copy into data_buf.		
 		 */
-		while ((cnt < mtd->oobblock) && count) {
-			this->data_buf[cnt++] =
-				((u_char *) vecs->iov_base)[len++];
+		if ((vecs->iov_len - len) >= mtd->oobblock) {
+			this->data_poi = (u_char *) vecs->iov_base;
+			this->data_poi += len;
+			len += mtd->oobblock; 
+			/* Check, if we have to switch to the next tuple */
 			if (len >= (int) vecs->iov_len) {
 				vecs++;
 				len = 0;
 				count--;
 			}
+		} else {
+			/*
+			 * Read data out of each tuple until we have a full page
+			 * to write or we've read all the tuples.
+		 	*/
+			int cnt = 0;
+			while ((cnt < mtd->oobblock) && count) {
+				if (vecs->iov_base != NULL && vecs->iov_len) {
+					this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
+				}
+				/* Check, if we have to switch to the next tuple */
+				if (len >= (int) vecs->iov_len) {
+					vecs++;
+					len = 0;
+					count--;
+				}
+			}	
+			this->data_poi = this->data_buf;	
 		}
 		
-		/* Do any need post-fill for partial page programming */
-		for (i=cnt ; i < mtd->oobblock ; i++)
-			this->data_buf[i] = 0xff;
-
-#ifdef CONFIG_MTD_NAND_ECC
-		/* Zero out the ECC array */
-		for (i=0 ; i < 6 ; i++)
-			this->ecc_code_buf[i] = 0x00;
-
-		/* Calculate and write the first ECC */
-		if (col >= mtd->eccsize) {
-			nand_command (mtd, NAND_CMD_READ0, col, page);
-			for (i=0 ; i < col ; i++)
-				this->data_buf[i] = readb (this->IO_ADDR); 
-			nand_calculate_ecc (&this->data_buf[0],
-				&(this->ecc_code_buf[0]));
-			for (i=0 ; i<3 ; i++)
-				this->data_buf[(mtd->oobblock + i)] =
-					this->ecc_code_buf[i];
-		}
-
-		/* Calculate and write the second ECC */
-		if ((mtd->oobblock == 512) && (cnt == mtd->oobblock)) {
-			nand_calculate_ecc (&this->data_buf[256],
-				&(this->ecc_code_buf[3]));
-			for (i=3 ; i<6 ; i++)
-				this->data_buf[(mtd->oobblock + i)] =
-					this->ecc_code_buf[i];
-		}
-
-		/* Write ones for partial page programming */
-		for (i=ecc_bytes ; i < mtd->oobsize ; i++)
-			this->data_buf[(mtd->oobblock + i)] = 0xff;
-#else
-		/* Write ones for partial page programming */
-		for (i=mtd->oobblock ; i < (mtd->oobblock + mtd->oobsize) ; i++)
-			this->data_buf[i] = 0xff;
-#endif
-		/* Send command to begin auto page programming */
-		nand_command (mtd, NAND_CMD_SEQIN, 0x00, page);
-
-		/* Write out complete page of data */
-		for (i=0 ; i < (mtd->oobblock + mtd->oobsize) ; i++)
-			writeb (this->data_buf[i], this->IO_ADDR);
-
-		/* Send command to actually program the data */
-		nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);
-
-		/*
-		 * Wait for program operation to complete. This could
-		 * take up to 3000us (3ms) on some devices, so we try
-		 * and exit as quickly as possible.
-		 */
-		status = 0;
-		for (i=0 ; i<24 ; i++) {
-			/* Delay for 125us */
-			udelay (125);
-
-			/* Check the status */
-			nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-			status = (int) readb (this->IO_ADDR);
-			if (status & 0x40)
-				break;
-		}
-
-		/* See if device thinks it succeeded */
-		if (status & 0x01) {
-			DEBUG (MTD_DEBUG_LEVEL0,
-				"nand_writev: " \
-				"Failed write, page 0x%08x, " \
-				"%6i bytes were succesful\n", page, *retlen);
-			nand_deselect ();
-			spin_lock_bh (&this->chip_lock);
-			this->state = FL_READY;
-			wake_up (&this->wq);
-			spin_unlock_bh (&this->chip_lock);
-			return -EIO;
-		}
-
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-		/*
-		 * The NAND device assumes that it is always writing to
-		 * a cleanly erased page. Hence, it performs its internal
-		 * write verification only on bits that transitioned from
-		 * 1 to 0. The device does NOT verify the whole page on a
-		 * byte by byte basis. It is possible that the page was
-		 * not completely erased or the page is becoming unusable
-		 * due to wear. The read with ECC would catch the error
-		 * later when the ECC page check fails, but we would rather
-		 * catch it early in the page write stage. Better to write
-		 * no data than invalid data.
-		 */
-		
-		/* Send command to read back the page */
-		if (col < mtd->eccsize)
-			nand_command (mtd, NAND_CMD_READ0, col, page);
-		else
-			nand_command (mtd, NAND_CMD_READ1, col - 256, page);
-
-		/* Loop through and verify the data */
-		for (i=col ; i < cnt ; i++) {
-			if (this->data_buf[i] != readb (this->IO_ADDR)) {
-				DEBUG (MTD_DEBUG_LEVEL0,
-					"nand_writev: " \
-					"Failed write verify, page 0x%08x, " \
-					"%6i bytes were succesful\n",
-					page, *retlen);
-				nand_deselect ();
-				spin_lock_bh (&this->chip_lock);
-				this->state = FL_READY;
-				wake_up (&this->wq);
-				spin_unlock_bh (&this->chip_lock);
-				return -EIO;
-			}
-		}
+		/* We use the same function for write and writev !) */
+		ret = nand_write_page (mtd, this, page, NULL, oobsel);
+		if (ret)
+			goto out;
 
-#ifdef CONFIG_MTD_NAND_ECC
-		/*
-		 * We also want to check that the ECC bytes wrote
-		 * correctly for the same reasons stated above.
-		 */
-		nand_command (mtd, NAND_CMD_READOOB, 0x00, page);
-		for (i=0 ; i < ecc_bytes ; i++) {
-			if ((readb (this->IO_ADDR) != this->ecc_code_buf[i]) &&
-					this->ecc_code_buf[i]) {
-				DEBUG (MTD_DEBUG_LEVEL0,
-					"nand_writev: Failed ECC write " \
-					"verify, page 0x%08x, " \
-					"%6i bytes were succesful\n",
-					page, i);
-				nand_deselect ();
-				spin_lock_bh (&this->chip_lock);
-				this->state = FL_READY;
-				wake_up (&this->wq);
-				spin_unlock_bh (&this->chip_lock);
-				return -EIO;
-			}
-		}
-#endif
-
-#endif
 		/* Update written bytes count */
-		*retlen += (cnt - col);
-
-		/* Reset written byte counter and column */
-		col = cnt = 0;
+		written += mtd->oobblock;;
 
 		/* Increment page address */
 		page++;
 	}
 
+out:
 	/* De-select the NAND device */
 	nand_deselect ();
 
@@ -1085,8 +1062,8 @@
 	wake_up (&this->wq);
 	spin_unlock_bh (&this->chip_lock);
 
-	/* Return happy */
-	return 0;
+	*retlen = written;
+	return ret;
 }
 
 /*
@@ -1094,53 +1071,33 @@
  */
 static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
 {
-	int i, page, len, status, pages_per_block;
+	int page, len, status, pages_per_block, ret;
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
+	DECLARE_WAITQUEUE (wait, current);
 
 	DEBUG (MTD_DEBUG_LEVEL3,
-		"nand_erase: start = 0x%08x, len = %i\n",
-		(unsigned int) instr->addr, (unsigned int) instr->len);
+	       "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
 
 	/* Start address must align on block boundary */
 	if (instr->addr & (mtd->erasesize - 1)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_erase: Unaligned address\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
 		return -EINVAL;
 	}
 
 	/* Length must align on block boundary */
 	if (instr->len & (mtd->erasesize - 1)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_erase: Length not block aligned\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");
 		return -EINVAL;
 	}
 
 	/* Do not allow erase past end of device */
 	if ((instr->len + instr->addr) > mtd->size) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_erase: Erase past end of device\n");
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");
 		return -EINVAL;
 	}
 
-retry:
 	/* Grab the lock and see if the device is available */
-	spin_lock_bh (&this->chip_lock);
-
-	switch (this->state) {
-	case FL_READY:
-		this->state = FL_ERASING;
-		break;
-
-	default:
-		set_current_state (TASK_UNINTERRUPTIBLE);
-		add_wait_queue (&this->wq, &wait);
-		spin_unlock_bh (&this->chip_lock);
-		schedule();
-
-		remove_wait_queue (&this->wq, &wait);
-		goto retry;
-	};
+	nand_get_chip (this, mtd, FL_ERASING, NULL);
 
 	/* Shift to get first page */
 	page = (int) (instr->addr >> this->page_shift);
@@ -1152,81 +1109,78 @@
 	nand_select ();
 
 	/* Check the WP bit */
-	nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-	if (!(readb (this->IO_ADDR) & 0x80)) {
-		DEBUG (MTD_DEBUG_LEVEL0,
-			"nand_erase: Device is write protected!!!\n");
-		nand_deselect ();
-		this->state = FL_READY;
-		spin_unlock_bh (&this->chip_lock);
-		return -EIO;
+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
+	if (!(readb (this->IO_ADDR_R) & 0x80)) {
+		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
+		instr->state = MTD_ERASE_FAILED;
+		goto erase_exit;
 	}
 
 	/* Loop through the pages */
 	len = instr->len;
+
+	instr->state = MTD_ERASING;
+
 	while (len) {
+		/* Check if we have a bad block, we do not erase bad blocks ! */
+		this->cmdfunc (mtd, NAND_CMD_READOOB, NAND_BADBLOCK_POS, page);
+		if (readb (this->IO_ADDR_R) != 0xff) {
+			printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
+			instr->state = MTD_ERASE_FAILED;
+			goto erase_exit;
+		}
+
 		/* Send commands to erase a page */
-		nand_command(mtd, NAND_CMD_ERASE1, -1, page);
-		nand_command(mtd, NAND_CMD_ERASE2, -1, -1);
+		this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page);
+		this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1);
 
-		/*
-		 * Wait for program operation to complete. This could
-		 * take up to 4000us (4ms) on some devices, so we try
-		 * and exit as quickly as possible.
-		 */
-		status = 0;
-		for (i=0 ; i<32 ; i++) {
-			/* Delay for 125us */
-			udelay (125);
-
-			/* Check the status */
-			nand_command (mtd, NAND_CMD_STATUS, -1, -1);
-			status = (int) readb (this->IO_ADDR);
-			if (status & 0x40)
-				break;
-		}
+		spin_unlock_bh (&this->chip_lock);
+		status = this->waitfunc (mtd, this, FL_ERASING);
 
+		/* Get spinlock, in case we exit */
+		spin_lock_bh (&this->chip_lock);
 		/* See if block erase succeeded */
 		if (status & 0x01) {
-			DEBUG (MTD_DEBUG_LEVEL0,
-				"nand_erase: " \
-				"Failed erase, page 0x%08x\n", page);
-			nand_deselect ();
-			this->state = FL_READY;
-			spin_unlock_bh (&this->chip_lock);
-			return -EIO;
+			DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
+			instr->state = MTD_ERASE_FAILED;
+			goto erase_exit;
+		}
+		
+		/* Check, if we were interupted */
+		if (this->state == FL_ERASING) {
+			/* Increment page address and decrement length */
+			len -= mtd->erasesize;
+			page += pages_per_block;
 		}
-
-		/* Increment page address and decrement length */
-		len -= mtd->erasesize;
-		page += pages_per_block;
-
 		/* Release the spin lock */
 		spin_unlock_bh (&this->chip_lock);
-
 erase_retry:
-		/* Check the state and sleep if it changed */
 		spin_lock_bh (&this->chip_lock);
-		if (this->state == FL_ERASING) {
+		/* Check the state and sleep if it changed */
+		if (this->state == FL_ERASING || this->state == FL_READY) {
+			/* Select the NAND device again, if we were interrupted */
+			this->state = FL_ERASING;
+			nand_select ();
 			continue;
-		}
-		else {
+		} else {
 			set_current_state (TASK_UNINTERRUPTIBLE);
 			add_wait_queue (&this->wq, &wait);
 			spin_unlock_bh (&this->chip_lock);
-			schedule();
-
+			schedule ();
 			remove_wait_queue (&this->wq, &wait);
 			goto erase_retry;
 		}
 	}
-	spin_unlock_bh (&this->chip_lock);
+	instr->state = MTD_ERASE_DONE;
 
+erase_exit:
 	/* De-select the NAND device */
 	nand_deselect ();
+	spin_unlock_bh (&this->chip_lock);
 
+	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;;
 	/* Do call back function */
-	if (instr->callback)
+	if (!ret && instr->callback)
 		instr->callback (instr);
 
 	/* The device is ready */
@@ -1234,8 +1188,8 @@
 	this->state = FL_READY;
 	spin_unlock_bh (&this->chip_lock);
 
-	/* Return happy */
-	return 0;
+	/* Return more or less happy */
+	return ret;
 }
 
 /*
@@ -1244,16 +1198,16 @@
 static void nand_sync (struct mtd_info *mtd)
 {
 	struct nand_chip *this = mtd->priv;
-	DECLARE_WAITQUEUE(wait, current);
+	DECLARE_WAITQUEUE (wait, current);
 
 	DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");
 
 retry:
 	/* Grab the spinlock */
-	spin_lock_bh(&this->chip_lock);
+	spin_lock_bh (&this->chip_lock);
 
 	/* See what's going on */
-	switch(this->state) {
+	switch (this->state) {
 	case FL_READY:
 	case FL_SYNCING:
 		this->state = FL_SYNCING;
@@ -1270,7 +1224,7 @@
 		goto retry;
 	}
 
-        /* Lock the device */
+	/* Lock the device */
 	spin_lock_bh (&this->chip_lock);
 
 	/* Set the device to be ready again */
@@ -1279,7 +1233,7 @@
 		wake_up (&this->wq);
 	}
 
-        /* Unlock the device */
+	/* Unlock the device */
 	spin_unlock_bh (&this->chip_lock);
 }
 
@@ -1291,46 +1245,100 @@
 	int i, nand_maf_id, nand_dev_id;
 	struct nand_chip *this = mtd->priv;
 
+	/* check for proper chip_delay setup, set 20us if not */
+	if (!this->chip_delay)
+		this->chip_delay = 20;
+
+	/* check, if a user supplied command function given */
+	if (this->cmdfunc == NULL)
+		this->cmdfunc = nand_command;
+
+	/* check, if a user supplied wait function given */
+	if (this->waitfunc == NULL)
+		this->waitfunc = nand_wait;
+
 	/* Select the device */
 	nand_select ();
 
 	/* Send the command for reading device ID */
-	nand_command (mtd, NAND_CMD_READID, 0x00, -1);
+	this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);
 
 	/* Read manufacturer and device IDs */
-	nand_maf_id = readb (this->IO_ADDR);
-	nand_dev_id = readb (this->IO_ADDR);
+	nand_maf_id = readb (this->IO_ADDR_R);
+	nand_dev_id = readb (this->IO_ADDR_R);
 
 	/* Print and store flash device information */
 	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-		if (nand_maf_id == nand_flash_ids[i].manufacture_id &&
-		    nand_dev_id == nand_flash_ids[i].model_id) {
-			if (!mtd->size) {
-				mtd->name = nand_flash_ids[i].name;
-				mtd->erasesize = nand_flash_ids[i].erasesize;
-				mtd->size = (1 << nand_flash_ids[i].chipshift);
-				mtd->eccsize = 256;
-				if (nand_flash_ids[i].page256) {
-					mtd->oobblock = 256;
-					mtd->oobsize = 8;
-					this->page_shift = 8;
-				}
-				else {
-					mtd->oobblock = 512;
-					mtd->oobsize = 16;
-					this->page_shift = 9;
-				}
+		if (nand_dev_id == nand_flash_ids[i].id && !mtd->size) {
+			mtd->name = nand_flash_ids[i].name;
+			mtd->erasesize = nand_flash_ids[i].erasesize;
+			mtd->size = (1 << nand_flash_ids[i].chipshift);
+			mtd->eccsize = 256;
+			if (nand_flash_ids[i].page256) {
+				mtd->oobblock = 256;
+				mtd->oobsize = 8;
+				this->page_shift = 8;
+			} else {
+				mtd->oobblock = 512;
+				mtd->oobsize = 16;
+				this->page_shift = 9;
 			}
-			printk (KERN_INFO "NAND device: Manufacture ID:" \
-				" 0x%02x, Chip ID: 0x%02x (%s)\n",
-			       nand_maf_id, nand_dev_id, mtd->name);
+			/* Try to identify manufacturer */
+			for (i = 0; nand_manuf_ids[i].id != 0x0; i++) {
+				if (nand_manuf_ids[i].id == nand_maf_id)
+					break;
+			}	
+			printk (KERN_INFO "NAND device: Manufacture ID:"
+				" 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
+				nand_manuf_ids[i].name , mtd->name);
 			break;
 		}
 	}
 
-	/* Initialize state and spinlock */
+	/* 
+	 * check ECC mode, default to software
+	 * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
+	 * fallback to software ECC 
+	*/
+	this->eccsize = 256;	/* set default eccsize */	
+
+	switch (this->eccmode) {
+
+	case NAND_ECC_HW3_512: 
+		if (mtd->oobblock == 256) {
+			printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");
+			this->eccmode = NAND_ECC_SOFT;
+			this->calculate_ecc = nand_calculate_ecc;
+			this->correct_data = nand_correct_data;
+			break;		
+		} else 
+			this->eccsize = 512; /* set eccsize to 512 and fall through for function check */
+
+	case NAND_ECC_HW3_256:
+		if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
+			break;
+		printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
+		BUG();	
+
+	case NAND_ECC_NONE: 
+		printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
+		this->eccmode = NAND_ECC_NONE;
+		break;
+
+	case NAND_ECC_SOFT:	
+		this->calculate_ecc = nand_calculate_ecc;
+		this->correct_data = nand_correct_data;
+		break;
+
+	default:
+		printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
+		BUG();	
+	}	
+	
+	/* Initialize state, waitqueue and spinlock */
 	this->state = FL_READY;
-	spin_lock_init(&this->chip_lock);
+	init_waitqueue_head (&this->wq);
+	spin_lock_init (&this->chip_lock);
 
 	/* De-select the device */
 	nand_deselect ();
@@ -1344,7 +1352,6 @@
 	/* Fill in remaining MTD driver data */
 	mtd->type = MTD_NANDFLASH;
 	mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
-	mtd->module = THIS_MODULE;
 	mtd->ecctype = MTD_ECC_SW;
 	mtd->erase = nand_erase;
 	mtd->point = NULL;
@@ -1357,18 +1364,20 @@
 	mtd->write_oob = nand_write_oob;
 	mtd->readv = NULL;
 	mtd->writev = nand_writev;
+	mtd->writev_ecc = nand_writev_ecc;
 	mtd->sync = nand_sync;
 	mtd->lock = NULL;
 	mtd->unlock = NULL;
 	mtd->suspend = NULL;
 	mtd->resume = NULL;
+	mtd->owner = THIS_MODULE;
 
 	/* Return happy */
 	return 0;
 }
 
-EXPORT_SYMBOL(nand_scan);
+EXPORT_SYMBOL (nand_scan);
 
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com");
-MODULE_DESCRIPTION("Generic NAND flash driver code");
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION ("Generic NAND flash driver code");
diff -Nru a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
--- a/drivers/mtd/nand/nand_ecc.c	Sun Sep 29 15:25:44 2002
+++ b/drivers/mtd/nand/nand_ecc.c	Wed May 28 08:01:05 2003
@@ -1,14 +1,14 @@
 /*
  *  drivers/mtd/nand_ecc.c
  *
- *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
  *                     Toshiba America Electronics Components, Inc.
  *
- * $Id: nand_ecc.c,v 1.6 2001/06/28 10:52:26 dwmw2 Exp $
+ * $Id: nand_ecc.c,v 1.9 2003/02/20 13:34:19 sjhill Exp $
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
  *
  * This file contains an ECC algorithm from Toshiba that detects and
  * corrects 1 bit errors in a 256 byte block of data.
@@ -209,5 +209,5 @@
 EXPORT_SYMBOL(nand_correct_data);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com>");
+MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
 MODULE_DESCRIPTION("Generic NAND ECC support");
diff -Nru a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/nand/nand_ids.c	Wed May 28 08:01:25 2003
@@ -0,0 +1,56 @@
+/*
+ *  drivers/mtd/nandids.c
+ *
+ *  Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
+ *
+ *
+ * $Id: nand_ids.c,v 1.4 2003/05/21 15:15:08 dwmw2 Exp $
+ *
+ * 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/mtd/nand.h>
+
+/*
+*	Chip ID list
+*/
+struct nand_flash_dev nand_flash_ids[] = {
+	{"NAND 1MiB 5V", 0x6e, 20, 0x1000, 1},
+	{"NAND 2MiB 5V", 0x64, 21, 0x1000, 1},
+	{"NAND 4MiB 5V", 0x6b, 22, 0x2000, 0},
+	{"NAND 1MiB 3,3V", 0xe8, 20, 0x1000, 1},
+	{"NAND 1MiB 3,3V", 0xec, 20, 0x1000, 1},
+	{"NAND 2MiB 3,3V", 0xea, 21, 0x1000, 1},
+	{"NAND 4MiB 3,3V", 0xd5, 22, 0x2000, 0},
+	{"NAND 4MiB 3,3V", 0xe3, 22, 0x2000, 0},
+	{"NAND 4MiB 3,3V", 0xe5, 22, 0x2000, 0},
+	{"NAND 8MiB 3,3V", 0xd6, 23, 0x2000, 0},
+	{"NAND 8MiB 3,3V", 0xe6, 23, 0x2000, 0},
+	{"NAND 16MiB 3,3V", 0x73, 24, 0x4000, 0},
+	{"NAND 32MiB 3,3V", 0x75, 25, 0x4000, 0},
+	{"NAND 64MiB 3,3V", 0x76, 26, 0x4000, 0},
+	{"NAND 128MiB 3,3V", 0x79, 27, 0x4000, 0},
+	{NULL,}
+};
+
+/*
+*	Manufacturer ID list
+*/
+struct nand_manufacturers nand_manuf_ids[] = {
+	{NAND_MFR_TOSHIBA, "Toshiba"},
+	{NAND_MFR_SAMSUNG, "Samsung"},
+	{NAND_MFR_FUJITSU, "Fujitsu"},
+	{NAND_MFR_NATIONAL, "National"},
+	{0x0, "Unknown"}
+};
+
+
+EXPORT_SYMBOL (nand_manuf_ids);
+EXPORT_SYMBOL (nand_flash_ids);
+
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR ("Thomas Gleixner <tglx@linutronix.de>");
+MODULE_DESCRIPTION ("Nand device & manufacturer ID's");
diff -Nru a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c
--- a/drivers/mtd/nand/spia.c	Wed Feb 26 05:44:53 2003
+++ b/drivers/mtd/nand/spia.c	Wed May 28 08:01:05 2003
@@ -1,9 +1,14 @@
 /*
  *  drivers/mtd/nand/spia.c
  *
- *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
  *
- * $Id: spia.c,v 1.12 2001/10/02 15:05:14 dwmw2 Exp $
+ *
+ *	10-29-2001 TG	change to support hardwarespecific access
+ *			to controllines	(due to change in nand.c)
+ *			page_cache added
+ *
+ * $Id: spia.c,v 1.19 2003/04/20 07:24:40 gleixner Exp $
  *
  * 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
@@ -68,6 +73,7 @@
 const static struct mtd_partition partition_info[] = {
 	{
 		.name	= "SPIA flash partition 1",
+		.offset	= 0,
 		.size	= 2*1024*1024
 	},
 	{
@@ -78,6 +84,25 @@
 };
 #define NUM_PARTITIONS 2
 
+
+/* 
+ *	hardware specific access to control-lines
+*/
+void spia_hwcontrol(int cmd){
+
+    switch(cmd){
+
+	case NAND_CTL_SETCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |=  0x01; break;
+	case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x01; break;
+
+	case NAND_CTL_SETALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |=  0x02; break;
+	case NAND_CTL_CLRALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x02; break;
+
+	case NAND_CTL_SETNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x04; break;
+	case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |=  0x04; break;
+    }
+}
+
 /*
  * Main initialization routine
  */
@@ -110,11 +135,12 @@
 	(*(volatile unsigned char *) (spia_io_base + spia_peddr)) = 0x07;
 
 	/* Set address of NAND IO lines */
-	this->IO_ADDR = spia_fio_base;
-	this->CTRL_ADDR = spia_io_base + spia_pedr;
-	this->CLE = 0x01;
-	this->ALE = 0x02;
-	this->NCE = 0x04;
+	this->IO_ADDR_R = spia_fio_base;
+	this->IO_ADDR_W = spia_fio_base;
+	/* Set address of hardware control function */
+	this->hwcontrol = spia_hwcontrol;
+	/* 15 us command delay time */
+	this->chip_delay = 15;		
 
 	/* Scan to find existence of the device */
 	if (nand_scan (spia_mtd)) {
@@ -159,5 +185,5 @@
 #endif
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com");
+MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com");
 MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on SPIA board");
diff -Nru a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
--- a/drivers/mtd/nftlcore.c	Sun May 25 02:45:06 2003
+++ b/drivers/mtd/nftlcore.c	Wed May 28 08:01:05 2003
@@ -1,7 +1,7 @@
 /* Linux driver for NAND Flash Translation Layer      */
 /* (c) 1999 Machine Vision Holdings, Inc.             */
 /* Author: David Woodhouse <dwmw2@infradead.org>      */
-/* $Id: nftlcore.c,v 1.82 2001/10/02 15:05:11 dwmw2 Exp $ */
+/* $Id: nftlcore.c,v 1.92 2003/05/23 11:41:47 dwmw2 Exp $ */
 
 /*
   The contents of this file are distributed under the GNU General
@@ -23,15 +23,13 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/init.h>
-#include <linux/blkpg.h>
-#include <linux/buffer_head.h>
+#include <linux/hdreg.h>
 
-#ifdef CONFIG_KMOD
 #include <linux/kmod.h>
-#endif
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
 #include <linux/mtd/nftl.h>
-#include <linux/mtd/compatmac.h>
+#include <linux/mtd/blktrans.h>
 
 /* maximum number of loops while examining next block, to have a
    chance to detect consistency problems (they should never happen
@@ -39,154 +37,97 @@
 
 #define MAX_LOOPS 10000
 
-/* NFTL block device stuff */
-#define MAJOR_NR NFTL_MAJOR
-
-#include <linux/blk.h>
-#include <linux/hdreg.h>
-
-/* Linux-specific block device functions */
-
-struct NFTLrecord *NFTLs[MAX_NFTLS];
 
-static struct request_queue nftl_queue;
-
-static void NFTL_setup(struct mtd_info *mtd)
+static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 {
-	int i;
 	struct NFTLrecord *nftl;
 	unsigned long temp;
-	int firstfree = -1;
-	struct gendisk *gd;
-
-	DEBUG(MTD_DEBUG_LEVEL1,"NFTL_setup\n");
 
-	for (i = 0; i < MAX_NFTLS; i++) {
-		if (!NFTLs[i] && firstfree == -1)
-			firstfree = i;
-		else if (NFTLs[i] && NFTLs[i]->mtd == mtd) {
-			/* This is a Spare Media Header for an NFTL we've already found */
-			DEBUG(MTD_DEBUG_LEVEL1, "MTD already mounted as NFTL\n");
-			return;
-		}
-	}
-        if (firstfree == -1) {
-		printk(KERN_WARNING "No more NFTL slot available\n");
+	if (mtd->ecctype != MTD_ECC_RS_DiskOnChip)
 		return;
-        }
+
+	DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name);
 
 	nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
-	gd = alloc_disk(1 << NFTL_PARTN_BITS);
-	if (!nftl || !gd) {
-		kfree(nftl);
-		put_disk(gd);
-		printk(KERN_WARNING "Out of memory for NFTL data structures\n");
+
+	if (!nftl) {
+		printk(KERN_WARNING "NFTL: out of memory for data structures\n");
 		return;
 	}
+	memset(nftl, 0, sizeof(*nftl));
 
-	init_MUTEX(&nftl->mutex);
-
-        /* get physical parameters */
-	nftl->EraseSize = mtd->erasesize;
-        nftl->nb_blocks = mtd->size / mtd->erasesize;
-	nftl->mtd = mtd;
+	nftl->mbd.mtd = mtd;
+	nftl->mbd.devnum = -1;
+	nftl->mbd.blksize = 512;
+	nftl->mbd.tr = tr;
 
         if (NFTL_mount(nftl) < 0) {
-		printk(KERN_WARNING "Could not mount NFTL device\n");
+		printk(KERN_WARNING "NFTL: could not mount device\n");
 		kfree(nftl);
-		put_disk(gd);
 		return;
         }
 
 	/* OK, it's a new one. Set up all the data structures. */
-#ifdef PSYCHO_DEBUG
-	printk("Found new NFTL nftl%c\n", firstfree + 'a');
-#endif
 
-        /* linux stuff */
+	/* Calculate geometry */
 	nftl->cylinders = 1024;
 	nftl->heads = 16;
 
 	temp = nftl->cylinders * nftl->heads;
-	nftl->sectors = nftl->nr_sects / temp;
-	if (nftl->nr_sects % temp) {
+	nftl->sectors = nftl->mbd.size / temp;
+	if (nftl->mbd.size % temp) {
 		nftl->sectors++;
 		temp = nftl->cylinders * nftl->sectors;
-		nftl->heads = nftl->nr_sects / temp;
+		nftl->heads = nftl->mbd.size / temp;
 
-		if (nftl->nr_sects % temp) {
+		if (nftl->mbd.size % temp) {
 			nftl->heads++;
 			temp = nftl->heads * nftl->sectors;
-			nftl->cylinders = nftl->nr_sects / temp;
+			nftl->cylinders = nftl->mbd.size / temp;
 		}
 	}
 
-	if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) {
-		printk(KERN_WARNING "Cannot calculate an NFTL geometry to "
-		       "match size of 0x%lx.\n", nftl->nr_sects);
-		printk(KERN_WARNING "Using C:%d H:%d S:%d (== 0x%lx sects)\n", 
-		       nftl->cylinders, nftl->heads , nftl->sectors, 
-		       (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors );
-
-		/* Oh no we don't have nftl->nr_sects = nftl->heads * nftl->cylinders * nftl->sectors; */
-	}
-	NFTLs[firstfree] = nftl;
-	sprintf(gd->disk_name, "nftl%c", 'a' + firstfree);
-	gd->major = MAJOR_NR;
-	gd->first_minor = firstfree << NFTL_PARTN_BITS;
-	set_capacity(gd, nftl->nr_sects);
-	nftl->disk = gd;
-	gd->private_data = nftl;
-	gd->queue = &nftl_queue;
-	add_disk(gd);
+	if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) {
+		/*
+		  Oh no we don't have 
+		   mbd.size == heads * cylinders * sectors
+		*/
+		printk(KERN_WARNING "NFTL: cannot calculate a geometry to "
+		       "match size of 0x%lx.\n", nftl->mbd.size);
+		printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d "
+			"(== 0x%lx sects)\n",
+			nftl->cylinders, nftl->heads , nftl->sectors, 
+			(long)nftl->cylinders * (long)nftl->heads *
+			(long)nftl->sectors );
+	}
+
+	if (add_mtd_blktrans_dev) {
+		if (nftl->ReplUnitTable)
+			kfree(nftl->ReplUnitTable);
+		if (nftl->EUNtable)
+			kfree(nftl->EUNtable);
+		kfree(nftl);
+		return;
+	}
+#ifdef PSYCHO_DEBUG
+	printk(KERN_INFO "NFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a');
+#endif
 }
 
-static void NFTL_unsetup(int i)
+static void nftl_remove_dev(struct mtd_blktrans_dev *dev)
 {
-	struct NFTLrecord *nftl = NFTLs[i];
+	struct NFTLrecord *nftl = (void *)dev;
 
-	DEBUG(MTD_DEBUG_LEVEL1, "NFTL_unsetup %d\n", i);
-	
-	NFTLs[i] = NULL;
-	
+	DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum);
+
+	del_mtd_blktrans_dev(dev);
 	if (nftl->ReplUnitTable)
 		kfree(nftl->ReplUnitTable);
 	if (nftl->EUNtable)
 		kfree(nftl->EUNtable);
-	del_gendisk(nftl->disk);
-	put_disk(nftl->disk);
 	kfree(nftl);
 }
 
-/* Search the MTD device for NFTL partitions */
-static void NFTL_notify_add(struct mtd_info *mtd)
-{
-	DEBUG(MTD_DEBUG_LEVEL1, "NFTL_notify_add for %s\n", mtd->name);
-
-	if (mtd) {
-		if (!mtd->read_oob) {
-			/* If this MTD doesn't have out-of-band data,
-			   then there's no point continuing */
-			DEBUG(MTD_DEBUG_LEVEL1, "No OOB data, quitting\n");
-			return;
-		}
-		DEBUG(MTD_DEBUG_LEVEL3, "mtd->read = %p, size = %d, erasesize = %d\n", 
-		      mtd->read, mtd->size, mtd->erasesize);
-
-                NFTL_setup(mtd);
-	}
-}
-
-static void NFTL_notify_remove(struct mtd_info *mtd)
-{
-	int i;
-
-	for (i = 0; i < MAX_NFTLS; i++) {
-		if (NFTLs[i] && NFTLs[i]->mtd == mtd)
-			NFTL_unsetup(i);
-	}
-}
-
 #ifdef CONFIG_NFTL_RW
 
 /* Actual NFTL access routines */
@@ -268,7 +209,7 @@
 
 		targetEUN = thisEUN;
 		for (block = 0; block < nftl->EraseSize / 512; block ++) {
-			MTD_READOOB(nftl->mtd,
+			MTD_READOOB(nftl->mbd.mtd,
 				    (thisEUN * nftl->EraseSize) + (block * 512),
 				    16 , &retlen, (char *)&oob);
 			if (block == 2) {
@@ -385,7 +326,7 @@
                chain by selecting the longer one */
             oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
             oob.u.c.unused = 0xffffffff;
-            MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, 
+            MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, 
                          8, &retlen, (char *)&oob.u);
         }
 
@@ -409,17 +350,17 @@
                 if (BlockMap[block] == BLOCK_NIL)
                         continue;
                 
-                ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
-                                  + (block * 512), 512, &retlen, movebuf, (char *)&oob); 
+                ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
+				  512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); 
                 if (ret < 0) {
-                    ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
+                    ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
                                       + (block * 512), 512, &retlen,
-                                      movebuf, (char *)&oob); 
+                                      movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); 
                     if (ret != -EIO) 
                         printk("Error went away on retry.\n");
                 }
-                MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512),
-                             512, &retlen, movebuf, (char *)&oob);
+                MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512),
+                             512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
 	}
         
         /* add the header so that it is now a valid chain */
@@ -427,7 +368,7 @@
                 = cpu_to_le16(thisVUC);
         oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
         
-        MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 8, 
+        MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8, 
                      8, &retlen, (char *)&oob.u);
 
 	/* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
@@ -547,7 +488,7 @@
 
 			lastEUN = writeEUN;
 
-			MTD_READOOB(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
+			MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
 				    8, &retlen, (char *)&bci);
 			
 			DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
@@ -635,12 +576,12 @@
 		nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
 
 		/* ... and on the flash itself */
-		MTD_READOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
+		MTD_READOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8,
 			    &retlen, (char *)&oob.u);
 
 		oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
 
-		MTD_WRITEOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
+		MTD_WRITEOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8,
                              &retlen, (char *)&oob.u);
 
                 /* we link the new block to the chain only after the
@@ -650,13 +591,13 @@
 			/* Both in our cache... */
 			nftl->ReplUnitTable[lastEUN] = writeEUN;
 			/* ... and on the flash itself */
-			MTD_READOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
+			MTD_READOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8,
 				    8, &retlen, (char *)&oob.u);
 
 			oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
 				= cpu_to_le16(writeEUN);
 
-			MTD_WRITEOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
+			MTD_WRITEOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8,
 				     8, &retlen, (char *)&oob.u);
 		}
 
@@ -669,8 +610,10 @@
 	return 0xffff;
 }
 
-static int NFTL_writeblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
+static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
+			   char *buffer)
 {
+	struct NFTLrecord *nftl = (void *)mbd;
 	u16 writeEUN;
 	unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
 	size_t retlen;
@@ -685,16 +628,18 @@
 		return 1;
 	}
 
-	MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
-		     512, &retlen, (char *)buffer, (char *)eccbuf);
+	MTD_WRITEECC(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
+		     512, &retlen, (char *)buffer, (char *)eccbuf, NAND_ECC_DISKONCHIP);
         /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
 
 	return 0;
 }
 #endif /* CONFIG_NFTL_RW */
 
-static int NFTL_readblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
+static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
+			  char *buffer)
 {
+	struct NFTLrecord *nftl = (void *)mbd;
 	u16 lastgoodEUN;
 	u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
 	unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
@@ -707,7 +652,7 @@
 
         if (thisEUN != BLOCK_NIL) {
 		while (thisEUN < nftl->nb_blocks) {
-			if (MTD_READOOB(nftl->mtd, (thisEUN * nftl->EraseSize) + blockofs,
+			if (MTD_READOOB(nftl->mbd.mtd, (thisEUN * nftl->EraseSize) + blockofs,
 					8, &retlen, (char *)&bci) < 0)
 				status = SECTOR_IGNORE;
 			else
@@ -726,13 +671,13 @@
 			case SECTOR_IGNORE:
 				break;
 			default:
-				printk("Unknown status for block %d in EUN %d: %x\n",
+				printk("Unknown status for block %ld in EUN %d: %x\n",
 				       block, thisEUN, status);
 				break;
 			}
 
 			if (!silly--) {
-				printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
+				printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%lx\n",
 				       block / (nftl->EraseSize / 512));
 				return 1;
 			}
@@ -748,15 +693,18 @@
 		loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
 		size_t retlen;
 		u_char eccbuf[6];
-		if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf))
+		if (MTD_READECC(nftl->mbd.mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP))
 			return -EIO;
 	}
 	return 0;
 }
 
-static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
+static int nftl_ioctl(struct mtd_blktrans_dev *dev,
+		     struct inode * inode, struct file * file, 
+		     unsigned int cmd, unsigned long arg)
 {
-	struct NFTLrecord *nftl = inode->i_bdev->bd_disk->private_data;
+	struct NFTLrecord *nftl = (void *)dev;
+
 	switch (cmd) {
 	case HDIO_GETGEO: {
 		struct hd_geometry g;
@@ -764,149 +712,15 @@
 		g.heads = nftl->heads;
 		g.sectors = nftl->sectors;
 		g.cylinders = nftl->cylinders;
-		g.start = get_start_sect(inode->i_bdev);
+		g.start = 0;
 		return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0;
 	}
-	case BLKFLSBUF:
-		fsync_bdev(inode->i_bdev);
-		invalidate_bdev(inode->i_bdev, 0);
-		if (nftl->mtd->sync)
-			nftl->mtd->sync(nftl->mtd);
-		return 0;
-	default:
-		return -EINVAL;
-	}
-}
-
-void nftl_request(struct request_queue *q)
-{
-	struct request *req;
-	
-	while ((req = elv_next_request(q)) != NULL) {
-		unsigned block = req->sector;
-		unsigned nsect = req->current_nr_sectors;
-		char *buffer = req->buffer;
-		struct NFTLrecord *nftl = req->rq_disk->private_data;
-		int res = 1; /* succeed */
-		
-		/* We can do this because the generic code knows not to
-		   touch the request at the head of the queue */
-		spin_unlock_irq(q->queue_lock);
-
-		DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n");
-		DEBUG(MTD_DEBUG_LEVEL3,
-		      "NFTL %s request, from sector 0x%04llx for %d sectors\n",
-		      (req->cmd == READ) ? "Read " : "Write",
-		      (unsigned long long)req->sector, req->current_nr_sectors);
-
-		DEBUG(MTD_DEBUG_LEVEL3, "Waiting for mutex\n");
-		down(&nftl->mutex);
-		DEBUG(MTD_DEBUG_LEVEL3, "Got mutex\n");
-
-		if (block + nsect > get_capacity(nftl->disk)) {
-			/* access past the end of device */
-			printk("%s: bad access: block = %d, count = %d\n",
-			       nftl->disk->disk_name, block, nsect);
-			up(&nftl->mutex);
-			res = 0; /* fail */
-			goto repeat;
-		}
-		
-		if (req->cmd == READ) {
-			DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request of 0x%x sectors @ %x "
-			      "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors);
-	
-			for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
-				/* Read a single sector to req->buffer + (512 * i) */
-				if (NFTL_readblock(nftl, block, buffer)) {
-					DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request failed\n");
-					up(&nftl->mutex);
-					res = 0;
-					goto repeat;
-				}
-			}
 
-			DEBUG(MTD_DEBUG_LEVEL2,"NFTL read request completed OK\n");
-			up(&nftl->mutex);
-			goto repeat;
-		} else if (rq_data_dir(req) == WRITE) {
-			DEBUG(MTD_DEBUG_LEVEL2, "NFTL write request of 0x%x sectors @ %x "
-			      "(req->nr_sectors == %lx)\n", nsect, block,
-			      req->nr_sectors);
-#ifdef CONFIG_NFTL_RW
-			for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
-				/* Read a single sector to req->buffer + (512 * i) */
-				if (NFTL_writeblock(nftl, block, buffer)) {
-					DEBUG(MTD_DEBUG_LEVEL1,"NFTL write request failed\n");
-					up(&nftl->mutex);
-					res = 0;
-					goto repeat;
-				}
-			}
-			DEBUG(MTD_DEBUG_LEVEL2,"NFTL write request completed OK\n");
-#else
-			res = 0; /* Writes always fail */
-#endif /* CONFIG_NFTL_RW */
-			up(&nftl->mutex);
-			goto repeat;
-		} else {
-			DEBUG(MTD_DEBUG_LEVEL0, "NFTL unknown request\n");
-			up(&nftl->mutex);
-			res = 0;
-			goto repeat;
-		}
-	repeat: 
-		DEBUG(MTD_DEBUG_LEVEL3, "end_request(%d)\n", res);
-		spin_lock_irq(q->queue_lock);
-		end_request(req, res);
+	default:
+		return -ENOTTY;
 	}
 }
 
-static struct kobject *nftl_probe(dev_t dev, int *part, void *data)
-{
-	request_module("docprobe");
-	return NULL;
-}
-
-static int nftl_open(struct inode *ip, struct file *fp)
-{
-	struct NFTLrecord *thisNFTL = ip->i_bdev->bd_disk->private_data;
-
-	DEBUG(MTD_DEBUG_LEVEL2,"NFTL_open\n");
-	if (!thisNFTL)
-		return -ENODEV;
-
-#ifndef CONFIG_NFTL_RW
-	if (fp->f_mode & FMODE_WRITE)
-		return -EROFS;
-#endif /* !CONFIG_NFTL_RW */
-
-	if (!get_mtd_device(thisNFTL->mtd, -1))
-		return /* -E'SBUGGEREDOFF */ -ENXIO;
-
-	return 0;
-}
-
-static int nftl_release(struct inode *inode, struct file *fp)
-{
-	struct NFTLrecord *thisNFTL = inode->i_bdev->bd_disk->private_data;
-
-	DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n");
-
-	if (thisNFTL->mtd->sync)
-		thisNFTL->mtd->sync(thisNFTL->mtd);
-
-	put_mtd_device(thisNFTL->mtd);
-
-	return 0;
-}
-static struct block_device_operations nftl_fops = 
-{
-	.owner		= THIS_MODULE,
-	.open		= nftl_open,
-	.release	= nftl_release,
-	.ioctl 		= nftl_ioctl
-};
 
 /****************************************************************************
  *
@@ -914,40 +728,33 @@
  *
  ****************************************************************************/
 
-static struct mtd_notifier nftl_notifier = {
-	.add	= NFTL_notify_add,
-	.remove	= NFTL_notify_remove
+
+struct mtd_blktrans_ops nftl_tr = {
+	.name		= "nftl",
+	.major		= NFTL_MAJOR,
+	.part_bits	= NFTL_PARTN_BITS,
+	.ioctl		= nftl_ioctl,
+	.readsect	= nftl_readblock,
+#ifdef CONFIG_NFTL_RW
+	.writesect	= nftl_writeblock,
+#endif
+	.add_mtd	= nftl_add_mtd,
+	.remove_dev	= nftl_remove_dev,
+	.owner		= THIS_MODULE,
 };
 
 extern char nftlmountrev[];
-static spinlock_t nftl_lock = SPIN_LOCK_UNLOCKED;
 
 int __init init_nftl(void)
 {
+	printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.92 $, nftlmount.c %s\n", nftlmountrev);
 
-#ifdef PRERELEASE 
-	printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.82 $, nftlmount.c %s\n", nftlmountrev);
-#endif
-
-	if (register_blkdev(MAJOR_NR, "nftl"))
-		return -EBUSY;
-
-	blk_register_region(MKDEV(MAJOR_NR, 0), 256,
-			THIS_MODULE, nftl_probe, NULL, NULL);
-
-	blk_init_queue(&nftl_queue, &nftl_request, &nftl_lock);
-	
-	register_mtd_user(&nftl_notifier);
-
-	return 0;
+	return register_mtd_blktrans(&nftl_tr);
 }
 
 static void __exit cleanup_nftl(void)
 {
-  	unregister_mtd_user(&nftl_notifier);
-	blk_unregister_region(MKDEV(MAJOR_NR, 0), 256);
-  	unregister_blkdev(MAJOR_NR, "nftl");
-  	blk_cleanup_queue(&nftl_queue);
+	deregister_mtd_blktrans(&nftl_tr);
 }
 
 module_init(init_nftl);
diff -Nru a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c
--- a/drivers/mtd/nftlmount.c	Thu Mar 13 16:52:15 2003
+++ b/drivers/mtd/nftlmount.c	Wed May 28 08:01:05 2003
@@ -4,7 +4,7 @@
  * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
  * Copyright (C) 2000 Netgem S.A.
  *
- * $Id: nftlmount.c,v 1.25 2001/11/30 16:46:27 dwmw2 Exp $
+ * $Id: nftlmount.c,v 1.34 2003/05/21 10:54:10 dwmw2 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
@@ -22,23 +22,16 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <linux/miscdevice.h>
-#include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/init.h>
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
 #include <linux/mtd/nftl.h>
-#include <linux/mtd/compatmac.h>
 
 #define SECTORSIZE 512
 
-char nftlmountrev[]="$Revision: 1.25 $";
+char nftlmountrev[]="$Revision: 1.34 $";
 
 /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
  *	various device information of the NFTL partition and Bad Unit Table. Update
@@ -50,11 +43,16 @@
 	struct nftl_uci1 h1;
 	struct nftl_oob oob;
 	unsigned int block, boot_record_count = 0;
-	int retlen;
+	size_t retlen;
 	u8 buf[SECTORSIZE];
 	struct NFTLMediaHeader *mh = &nftl->MediaHdr;
 	unsigned int i;
 
+        /* Assume logical EraseSize == physical erasesize for starting the scan. 
+	   We'll sort it out later if we find a MediaHeader which says otherwise */
+	nftl->EraseSize = nftl->mbd.mtd->erasesize;
+        nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
+
 	nftl->MediaUnit = BLOCK_NIL;
 	nftl->SpareMediaUnit = BLOCK_NIL;
 
@@ -64,12 +62,12 @@
 
 		/* Check for ANAND header first. Then can whinge if it's found but later
 		   checks fail */
-		if ((ret = MTD_READ(nftl->mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf))) {
+		if ((ret = MTD_READ(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf))) {
 			static int warncount = 5;
 
 			if (warncount) {
 				printk(KERN_WARNING "Block read at 0x%x of mtd%d failed: %d\n",
-				       block * nftl->EraseSize, nftl->mtd->index, ret);
+				       block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
 				if (!--warncount)
 					printk(KERN_WARNING "Further failures for this block will not be printed\n");
 			}
@@ -80,16 +78,16 @@
 			/* ANAND\0 not found. Continue */
 #if 0
 			printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n", 
-			       block * nftl->EraseSize, nftl->mtd->index);
+			       block * nftl->EraseSize, nftl->mbd.mtd->index);
 #endif			
 			continue;
 		}
 
 		/* To be safer with BIOS, also use erase mark as discriminant */
-		if ((ret = MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,
+		if ((ret = MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8,
 				8, &retlen, (char *)&h1) < 0)) {
 			printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n",
-			       block * nftl->EraseSize, nftl->mtd->index, ret);
+			       block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
 			continue;
 		}
 
@@ -99,29 +97,28 @@
       */
 		if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) {
 			printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n",
-			       block * nftl->EraseSize, nftl->mtd->index, 
+			       block * nftl->EraseSize, nftl->mbd.mtd->index, 
 			       le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1));
 			continue;
 		}
 
 		/* Finally reread to check ECC */
-		if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize, SECTORSIZE,
-				&retlen, buf, (char *)&oob) < 0)) {
+		if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE,
+				&retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP) < 0)) {
 			printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n",
-			       block * nftl->EraseSize, nftl->mtd->index, ret);
+			       block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
 			continue;
 		}
 
 		/* Paranoia. Check the ANAND header is still there after the ECC read */
 		if (memcmp(buf, "ANAND", 6)) {
 			printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but went away on reread!\n",
-			       block * nftl->EraseSize, nftl->mtd->index);
+			       block * nftl->EraseSize, nftl->mbd.mtd->index);
 			printk(KERN_NOTICE "New data are: %02x %02x %02x %02x %02x %02x\n",
 			       buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
 			continue;
 		}
 #endif
-			       
 		/* OK, we like it. */
 
 		if (boot_record_count) {
@@ -131,11 +128,19 @@
 				printk(KERN_NOTICE "NFTL Media Headers at 0x%x and 0x%x disagree.\n",
 				       nftl->MediaUnit * nftl->EraseSize, block * nftl->EraseSize);
 				/* if (debug) Print both side by side */
-				return -1;
+				if (boot_record_count < 2) {
+					/* We haven't yet seen two real ones */
+					return -1;
+				}
+				continue;
 			}
 			if (boot_record_count == 1)
 				nftl->SpareMediaUnit = block;
 
+			/* Mark this boot record (NFTL MediaHeader) block as reserved */
+			nftl->ReplUnitTable[block] = BLOCK_RESERVED;
+
+
 			boot_record_count++;
 			continue;
 		}
@@ -144,12 +149,18 @@
 		memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
 
 		/* Do some sanity checks on it */
-		if (mh->UnitSizeFactor != 0xff) {
-			printk(KERN_NOTICE "Sorry, we don't support UnitSizeFactor "
-			       "of != 1 yet.\n");
+		if (mh->UnitSizeFactor == 0) {
+			printk(KERN_NOTICE "NFTL: UnitSizeFactor 0x00 detected. This violates the spec but we think we know what it means...\n");
+		} else if (mh->UnitSizeFactor < 0xfc) {
+			printk(KERN_NOTICE "Sorry, we don't support UnitSizeFactor 0x%02x\n",
+			       mh->UnitSizeFactor);
 			return -1;
+		} else if (mh->UnitSizeFactor != 0xff) {
+			printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n",
+			       mh->UnitSizeFactor);
+			nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor);
+			nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
 		}
-
 		nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
 		if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
 			printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
@@ -166,21 +177,51 @@
 			return -1;
 		}
 		
-		nftl->nr_sects  = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
-		
+		nftl->mbd.size  = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
+
 		/* If we're not using the last sectors in the device for some reason,
 		   reduce nb_blocks accordingly so we forget they're there */
 		nftl->nb_blocks = le16_to_cpu(mh->NumEraseUnits) + le16_to_cpu(mh->FirstPhysicalEUN);
 
+		/* XXX: will be suppressed */
+		nftl->lastEUN = nftl->nb_blocks - 1;
+
+		/* memory alloc */
+		nftl->EUNtable = kmalloc(nftl->nb_blocks * sizeof(u16), GFP_KERNEL);
+		if (!nftl->EUNtable) {
+			printk(KERN_NOTICE "NFTL: allocation of EUNtable failed\n");
+			return -ENOMEM;
+		}
+
+		nftl->ReplUnitTable = kmalloc(nftl->nb_blocks * sizeof(u16), GFP_KERNEL);
+		if (!nftl->ReplUnitTable) {
+			kfree(nftl->EUNtable);
+			printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n");
+			return -ENOMEM;
+		}
+		
+		/* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */
+		for (i = 0; i < nftl->nb_boot_blocks; i++)
+			nftl->ReplUnitTable[i] = BLOCK_RESERVED;
+		/* mark all remaining blocks as potentially containing data */
+		for (; i < nftl->nb_blocks; i++) { 
+			nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED;
+		}
+
+		/* Mark this boot record (NFTL MediaHeader) block as reserved */
+		nftl->ReplUnitTable[block] = BLOCK_RESERVED;
+
 		/* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */
 		for (i = 0; i < nftl->nb_blocks; i++) {
 			if ((i & (SECTORSIZE - 1)) == 0) {
 				/* read one sector for every SECTORSIZE of blocks */
-				if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize +
-						       i + SECTORSIZE, SECTORSIZE,
-						       &retlen, buf, (char *)&oob)) < 0) {
+				if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize +
+						       i + SECTORSIZE, SECTORSIZE, &retlen, buf,
+						       (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) {
 					printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
 					       ret);
+					kfree(nftl->ReplUnitTable);
+					kfree(nftl->EUNtable);
 					return -1;
 				}
 			}
@@ -217,16 +258,16 @@
 	for (i = 0; i < len; i += SECTORSIZE) {
 		/* we want to read the sector without ECC check here since a free
 		   sector does not have ECC syndrome on it yet */
-		if (MTD_READ(nftl->mtd, address, SECTORSIZE, &retlen, buf) < 0)
+		if (MTD_READ(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0)
 			return -1;
 		if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
 			return -1;
 
 		if (check_oob) {
-			if (MTD_READOOB(nftl->mtd, address, nftl->mtd->oobsize,
+			if (MTD_READOOB(nftl->mbd.mtd, address, nftl->mbd.mtd->oobsize,
 					&retlen, buf) < 0)
 				return -1;
-			if (memcmpb(buf, 0xff, nftl->mtd->oobsize) != 0)
+			if (memcmpb(buf, 0xff, nftl->mbd.mtd->oobsize) != 0)
 				return -1;
 		}
 		address += SECTORSIZE;
@@ -245,13 +286,13 @@
  */
 int NFTL_formatblock(struct NFTLrecord *nftl, int block)
 {
-	int retlen;
+	size_t retlen;
 	unsigned int nb_erases, erase_mark;
 	struct nftl_uci1 uci;
 	struct erase_info *instr = &nftl->instr;
 
 	/* Read the Unit Control Information #1 for Wear-Leveling */
-	if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8,
+	if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8,
 			8, &retlen, (char *)&uci) < 0)
 		goto default_uci1;
 
@@ -268,7 +309,7 @@
 	/* XXX: use async erase interface, XXX: test return code */
 	instr->addr = block * nftl->EraseSize;
 	instr->len = nftl->EraseSize;
-	MTD_ERASE(nftl->mtd, instr);
+	MTD_ERASE(nftl->mbd.mtd, instr);
 
 	if (instr->state == MTD_ERASE_FAILED) {
 		/* could not format, FixMe: We should update the BadUnitTable 
@@ -291,7 +332,7 @@
 			return -1;
 
 		uci.WearInfo = le32_to_cpu(nb_erases);
-		if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
+		if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
 				 &retlen, (char *)&uci) < 0)
 			return -1;
 		return 0;
@@ -317,7 +358,7 @@
 	block = first_block;
 	for (;;) {
 		for (i = 0; i < sectors_per_block; i++) {
-			if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i * SECTORSIZE,
+			if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i * SECTORSIZE,
 					8, &retlen, (char *)&bci) < 0)
 				status = SECTOR_IGNORE;
 			else
@@ -337,7 +378,7 @@
 					/* sector not free actually : mark it as SECTOR_IGNORE  */
 					bci.Status = SECTOR_IGNORE;
 					bci.Status1 = SECTOR_IGNORE;
-					MTD_WRITEOOB(nftl->mtd,
+					MTD_WRITEOOB(nftl->mbd.mtd,
 						     block * nftl->EraseSize + i * SECTORSIZE,
 						     8, &retlen, (char *)&bci);
 				}
@@ -427,10 +468,10 @@
 {
 	struct nftl_uci1 h1;
 	unsigned int erase_mark;
-	int retlen;
+	size_t retlen;
 
 	/* check erase mark. */
-	if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, 
+	if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, 
 			&retlen, (char *)&h1) < 0)
 		return -1;
 
@@ -445,7 +486,7 @@
 		h1.EraseMark = cpu_to_le16(ERASE_MARK);
 		h1.EraseMark1 = cpu_to_le16(ERASE_MARK);
 		h1.WearInfo = cpu_to_le32(0);
-		if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, 
+		if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, 
 				 &retlen, (char *)&h1) < 0)
 			return -1;
 	} else {
@@ -457,7 +498,7 @@
 						SECTORSIZE, 0) != 0)
 				return -1;
 
-			if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i,
+			if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i,
 					16, &retlen, buf) < 0)
 				return -1;
 			if (i == SECTORSIZE) {
@@ -485,9 +526,9 @@
 static int get_fold_mark(struct NFTLrecord *nftl, unsigned int block)
 {
 	struct nftl_uci2 uci;
-	int retlen;
+	size_t retlen;
 
-	if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
+	if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8,
 			8, &retlen, (char *)&uci) < 0)
 		return 0;
 
@@ -502,44 +543,14 @@
 	int chain_length, do_format_chain;
 	struct nftl_uci0 h0;
 	struct nftl_uci1 h1;
-	int retlen;
-
-	/* XXX: will be suppressed */
-	s->lastEUN = s->nb_blocks - 1;
-
-	/* memory alloc */
-	s->EUNtable = kmalloc(s->nb_blocks * sizeof(u16), GFP_KERNEL);
-	s->ReplUnitTable = kmalloc(s->nb_blocks * sizeof(u16), GFP_KERNEL);
-	if (!s->EUNtable || !s->ReplUnitTable) {
-	fail:
-		if (s->EUNtable)
-			kfree(s->EUNtable);
-		if (s->ReplUnitTable)
-			kfree(s->ReplUnitTable);
-		return -1;
-	}
-
-	/* mark all blocks as potentially containing data */
-	for (i = 0; i < s->nb_blocks; i++) { 
-		s->ReplUnitTable[i] = BLOCK_NOTEXPLORED;
-	}
+	size_t retlen;
 
 	/* search for NFTL MediaHeader and Spare NFTL Media Header */
 	if (find_boot_record(s) < 0) {
 		printk("Could not find valid boot record\n");
-		goto fail;
+		return -1;
 	}
 
-	/* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */
-	for (i = 0; i < s->nb_boot_blocks; i++)
-		s->ReplUnitTable[i] = BLOCK_RESERVED;
-
-	/* also mark the boot records (NFTL MediaHeader) blocks as reserved */
-	if (s->MediaUnit != BLOCK_NIL)
-		s->ReplUnitTable[s->MediaUnit] = BLOCK_RESERVED;
-	if (s->SpareMediaUnit != BLOCK_NIL)
-		s->ReplUnitTable[s->SpareMediaUnit] = BLOCK_RESERVED;
-
 	/* init the logical to physical table */
 	for (i = 0; i < s->nb_blocks; i++) {
 		s->EUNtable[i] = BLOCK_NIL;
@@ -556,9 +567,9 @@
 
 			for (;;) {
 				/* read the block header. If error, we format the chain */
-				if (MTD_READOOB(s->mtd, block * s->EraseSize + 8, 8, 
+				if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8, 
 						&retlen, (char *)&h0) < 0 ||
-				    MTD_READOOB(s->mtd, block * s->EraseSize + SECTORSIZE + 8, 8, 
+				    MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8, 
 						&retlen, (char *)&h1) < 0) {
 					s->ReplUnitTable[block] = BLOCK_NIL;
 					do_format_chain = 1;
@@ -724,7 +735,7 @@
 
 	/* second pass to format unreferenced blocks  and init free block count */
 	s->numfreeEUNs = 0;
-	s->LastFreeEUN = BLOCK_NIL;
+	s->LastFreeEUN = le16_to_cpu(s->MediaHdr.FirstPhysicalEUN);
 
 	for (block = 0; block < s->nb_blocks; block++) {
 		if (s->ReplUnitTable[block] == BLOCK_NOTEXPLORED) {
diff -Nru a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c
--- a/drivers/mtd/redboot.c	Mon Feb  4 23:55:06 2002
+++ b/drivers/mtd/redboot.c	Wed May 28 08:01:05 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: redboot.c,v 1.6 2001/10/25 09:16:06 dwmw2 Exp $
+ * $Id: redboot.c,v 1.11 2003/05/21 10:39:26 dwmw2 Exp $
  *
  * Parse RedBoot-style Flash Image System (FIS) tables and
  * produce a Linux partition array to match.
@@ -7,6 +7,7 @@
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/init.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -34,7 +35,9 @@
 	return 1;
 }
 
-int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts)
+static int parse_redboot_partitions(struct mtd_info *master, 
+                             struct mtd_partition **pparts,
+                             unsigned long fis_origin)
 {
 	int nrparts = 0;
 	struct fis_image_desc *buf;
@@ -43,7 +46,9 @@
 	int ret, i;
 	size_t retlen;
 	char *names;
+	char *nullname;
 	int namelen = 0;
+	static char nullstring[] = "unallocated";
 
 	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 
@@ -90,7 +95,11 @@
 			goto out;
 		}
 		new_fl->img = &buf[i];
-		buf[i].flash_base &= master->size-1;
+                if (fis_origin) {
+                        buf[i].flash_base -= fis_origin;
+                } else {
+                        buf[i].flash_base &= master->size-1;
+                }
 
 		/* I'm sure the JFFS2 code has done me permanent damage.
 		 * I now think the following is _normal_
@@ -110,18 +119,24 @@
 		if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize < tmp_fl->next->img->flash_base)
 			nrparts++;
 	}
-	parts = kmalloc(sizeof(*parts)*nrparts + namelen, GFP_KERNEL);
+	parts = kmalloc(sizeof(*parts)*nrparts + sizeof(nullstring) + namelen, GFP_KERNEL);
 
 	if (!parts) {
 		ret = -ENOMEM;
 		goto out;
 	}
-	names = (char *)&parts[nrparts];
+
 	memset(parts, 0, sizeof(*parts)*nrparts + namelen);
+
+	/* FIXME: Include nullname only if it's used */
+	nullname = (char *)&parts[nrparts];
+	sprintf(nullname, nullstring);
+	names = nullname + sizeof(nullstring);
+
 	i=0;
 
 	if (fl->img->flash_base) {
-	       parts[0].name = "unallocated space";
+	       parts[0].name = nullname;
 	       parts[0].size = fl->img->flash_base;
 	       parts[0].offset = 0;
 	}
@@ -137,7 +152,7 @@
 			i++;
 			parts[i].offset = parts[i-1].size + parts[i-1].offset;
 			parts[i].size = fl->next->img->flash_base - parts[i].offset;
-			parts[i].name = "unallocated space";
+			parts[i].name = nullname;
 		}
 		tmp_fl = fl;
 		fl = fl->next;
@@ -155,7 +170,24 @@
 	return ret;
 }
 
-EXPORT_SYMBOL(parse_redboot_partitions);
+static struct mtd_part_parser redboot_parser = {
+	.owner = THIS_MODULE,
+	.parse_fn = parse_redboot_partitions,
+	.name = "RedBoot",
+};
+
+static int __init redboot_parser_init(void)
+{
+	return register_mtd_parser(&redboot_parser);
+}
+
+static void __exit redboot_parser_exit(void)
+{
+	deregister_mtd_parser(&redboot_parser);
+}
+
+module_init(redboot_parser_init);
+module_exit(redboot_parser_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>");
diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c
--- a/drivers/net/8139too.c	Tue May 20 20:02:19 2003
+++ b/drivers/net/8139too.c	Wed May 28 21:03:45 2003
@@ -980,7 +980,7 @@
 
 	dev->irq = pdev->irq;
 
-	/* dev->priv/tp zeroed and aligned in init_etherdev */
+	/* dev->priv/tp zeroed and aligned in alloc_etherdev */
 	tp = dev->priv;
 
 	/* note: tp->chipset set in rtl8139_init_board */
@@ -2143,9 +2143,7 @@
 
 	spin_unlock_irqrestore (&tp->lock, flags);
 
-	/* TODO: isn't this code racy? we synchronize the IRQ and then free it, */ 
-	/* but another IRQ could've happened in between the sync and free */ 
-	synchronize_irq (dev->irq);
+	synchronize_irq (dev->irq);	/* racy, but that's ok here */
 	free_irq (dev->irq, dev);
 
 	rtl8139_tx_clear (tp);
diff -Nru a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
--- a/drivers/net/amd8111e.c	Tue May 20 20:02:19 2003
+++ b/drivers/net/amd8111e.c	Thu May 29 13:46:33 2003
@@ -1,6 +1,6 @@
 
 /* Advanced  Micro Devices Inc. AMD8111E Linux Network Driver 
- * Copyright (C) 2002 Advanced Micro Devices 
+ * Copyright (C) 2003 Advanced Micro Devices 
  *
  * 
  * Copyright 2001,2002 Jeff Garzik <jgarzik@mandrakesoft.com> [ 8139cp.c,tg3.c ]
@@ -41,6 +41,18 @@
 	Kernel Mode
 
 Revision History:
+ 	3.0.0
+	   Initial Revision.
+	3.0.1
+	 1. Dynamic interrupt coalescing.
+	 2. Removed prev_stats.
+	 3. MII support.
+	 4. Dynamic IPG support
+	3.0.2  05/29/2003
+	 1. Bug fix: Fixed failure to send jumbo packets larger than 4k.
+	 2. Bug fix: Fixed VLAN support failure.
+	 3. Bug fix: Fixed receive interrupt coalescing bug.
+	 4. Dynamic IPG support is disabled by default.
 
 */
 
@@ -77,13 +89,16 @@
 
 #include "amd8111e.h"
 #define MODULE_NAME	"amd8111e"
-#define MODULE_VERSION	"3.0.0"
+#define MODULE_VERSION	"3.0.2"
 MODULE_AUTHOR("Advanced Micro Devices, Inc.");
-MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.0"); 
+MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.2");
 MODULE_LICENSE("GPL");
-
 MODULE_PARM(speed_duplex, "1-" __MODULE_STRING (MAX_UNITS) "i");
 MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotitate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex");
+MODULE_PARM(coalesce, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC(coalesce, "Enable or Disable interrupt coalescing, 1: Enable, 0: Disable");
+MODULE_PARM(dynamic_ipg, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC(dynamic_ipg, "Enable or Disable dynamic IPG, 1: Enable, 0: Disable");
 
 static struct pci_device_id amd8111e_pci_tbl[] __devinitdata = {
 		
@@ -92,6 +107,88 @@
 	{ 0, }
 
 };
+/* 
+This function will read the PHY registers.
+*/
+static int amd8111e_read_phy(struct amd8111e_priv* lp, int phy_id, int reg, u32* val)
+{
+	void * mmio = lp->mmio;
+	unsigned int reg_val;
+	unsigned int repeat= REPEAT_CNT;
+
+	reg_val = readl(mmio + PHY_ACCESS);
+	while (reg_val & PHY_CMD_ACTIVE)
+		reg_val = readl( mmio + PHY_ACCESS );
+
+	writel( PHY_RD_CMD | ((phy_id & 0x1f) << 21) |
+			   ((reg & 0x1f) << 16),  mmio +PHY_ACCESS);
+	do{
+		reg_val = readl(mmio + PHY_ACCESS);
+		udelay(30);  /* It takes 30 us to read/write data */
+	} while (--repeat && (reg_val & PHY_CMD_ACTIVE));
+	if(reg_val & PHY_RD_ERR)
+		goto err_phy_read;
+	
+	*val = reg_val & 0xffff;
+	return 0;
+err_phy_read:	
+	*val = 0;
+	return -EINVAL;
+	
+}
+
+/* 
+This function will write into PHY registers. 
+*/
+static int amd8111e_write_phy(struct amd8111e_priv* lp,int phy_id, int reg, u32 val)
+{
+	unsigned int repeat = REPEAT_CNT
+	void * mmio = lp->mmio;
+	unsigned int reg_val;
+
+	reg_val = readl(mmio + PHY_ACCESS);
+	while (reg_val & PHY_CMD_ACTIVE)
+		reg_val = readl( mmio + PHY_ACCESS );
+
+	writel( PHY_WR_CMD | ((phy_id & 0x1f) << 21) |
+			   ((reg & 0x1f) << 16)|val, mmio + PHY_ACCESS);
+
+	do{
+		reg_val = readl(mmio + PHY_ACCESS);
+		udelay(30);  /* It takes 30 us to read/write the data */
+	} while (--repeat && (reg_val & PHY_CMD_ACTIVE));
+	
+	if(reg_val & PHY_RD_ERR)
+		goto err_phy_write;
+	
+	return 0;
+
+err_phy_write:	
+	return -EINVAL;
+	
+}
+/* 
+This is the mii register read function provided to the mii interface.
+*/ 
+static int amd8111e_mdio_read(struct net_device * dev, int phy_id, int reg_num)
+{
+	struct amd8111e_priv* lp = dev->priv;
+	unsigned int reg_val;
+
+	amd8111e_read_phy(lp,phy_id,reg_num,&reg_val);
+	return reg_val;
+	
+}
+
+/* 
+This is the mii register write function provided to the mii interface.
+*/ 
+static void amd8111e_mdio_write(struct net_device * dev, int phy_id, int reg_num, int val)
+{
+	struct amd8111e_priv* lp = dev->priv;
+
+	amd8111e_write_phy(lp, phy_id, reg_num, val);
+}
 
 /*
 This function will set PHY speed. During initialization sets the original speed to 100 full.
@@ -99,26 +196,39 @@
 static void amd8111e_set_ext_phy(struct net_device *dev)
 {
 	struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv;
-	unsigned long  reg_val = 0;
-	void * mmio = lp->mmio;
-	struct amd8111e_link_config *link_config = &lp->link_config;
+	u32 bmcr,advert,tmp;
 	
-	if(!lp->opened){
-		/* Initializing SPEED_100 and DUPLEX_FULL as original values */
-		link_config->orig_speed = SPEED_100;
-		link_config->orig_duplex = DUPLEX_FULL;
-		link_config->orig_phy_option = XPHYSP |XPHYFD;
-	}
-	reg_val = lp->ext_phy_option;
-
-	/* Disable port manager */
-	writel((u32) EN_PMGR, mmio + CMD3 );
+	/* Determine mii register values to set the speed */
+	advert = amd8111e_mdio_read(dev, PHY_ID, MII_ADVERTISE);
+	tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+	switch (lp->ext_phy_option){
+
+		default:
+		case SPEED_AUTONEG: /* advertise all values */
+			tmp |= ( ADVERTISE_10HALF|ADVERTISE_10FULL|
+				ADVERTISE_100HALF|ADVERTISE_100FULL) ;
+			break;
+		case SPEED10_HALF:
+			tmp |= ADVERTISE_10HALF;
+			break;
+		case SPEED10_FULL:
+			tmp |= ADVERTISE_10FULL;
+			break;
+		case SPEED100_HALF: 
+			tmp |= ADVERTISE_100HALF;
+			break;
+		case SPEED100_FULL:
+			tmp |= ADVERTISE_100FULL;
+			break;
+	}
+
+	if(advert != tmp)
+		amd8111e_mdio_write(dev, PHY_ID, MII_ADVERTISE, tmp);
+	/* Restart auto negotiation */
+	bmcr = amd8111e_mdio_read(dev, PHY_ID, MII_BMCR);
+	bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+	amd8111e_mdio_write(dev, PHY_ID, MII_BMCR, bmcr);
 
-	/* Reset PHY */
-	writel((u32)XPHYRST | lp->ext_phy_option, mmio + CTRL2);
-
-	/* Enable port manager */
-	writel((u32)VAL1 | EN_PMGR, mmio + CMD3 );
 }
 
 /* 
@@ -156,7 +266,7 @@
 }
 
 /*
- This will set the receive buffer length corresponding to the mtu size of network interface.
+This will set the receive buffer length corresponding to the mtu size of networkinterface.
 */
 static inline void amd8111e_set_rx_buff_len(struct net_device* dev)
 {
@@ -226,13 +336,13 @@
 
 		lp->rx_ring[i].buff_phy_addr = cpu_to_le32(lp->rx_dma_addr[i]);
 		lp->rx_ring[i].buff_count = cpu_to_le16(lp->rx_buff_len);
-		lp->rx_ring[i].rx_dr_offset10 = cpu_to_le16(OWN_BIT);
+		lp->rx_ring[i].rx_flags = cpu_to_le16(OWN_BIT);
 	}
 
 	/* Initializing transmit descriptors */
 	for (i = 0; i < NUM_TX_RING_DR; i++) {
 		lp->tx_ring[i].buff_phy_addr = 0;
-		lp->tx_ring[i].tx_dr_offset2 = 0;
+		lp->tx_ring[i].tx_flags = 0;
 		lp->tx_ring[i].buff_count = 0;
 	}
 
@@ -253,6 +363,65 @@
 err_no_mem:
 	return -ENOMEM;
 }
+/* This function will set the interrupt coalescing according to the input arguments */
+static int amd8111e_set_coalesce(struct net_device * dev, enum coal_mode cmod)
+{
+	unsigned int timeout;
+	unsigned int event_count;
+
+	struct amd8111e_priv *lp = dev->priv;
+	void* mmio = lp->mmio;
+	struct amd8111e_coalesce_conf * coal_conf = &lp->coal_conf;
+
+
+	switch(cmod)
+	{
+		case RX_INTR_COAL :
+			timeout = coal_conf->rx_timeout;
+			event_count = coal_conf->rx_event_count;
+			if( timeout > MAX_TIMEOUT || 
+					event_count > MAX_EVENT_COUNT ) 
+			return -EINVAL;
+
+			timeout = timeout * DELAY_TIMER_CONV; 
+			writel(VAL0|STINTEN, mmio+INTEN0);
+			writel((u32)DLY_INT_A_R0|( event_count<< 16 )|timeout,
+							mmio+DLY_INT_A);
+			break;
+
+		case TX_INTR_COAL :
+			timeout = coal_conf->tx_timeout;
+			event_count = coal_conf->tx_event_count;
+			if( timeout > MAX_TIMEOUT || 
+					event_count > MAX_EVENT_COUNT ) 
+			return -EINVAL;
+
+		   
+			timeout = timeout * DELAY_TIMER_CONV; 
+			writel(VAL0|STINTEN,mmio+INTEN0);
+			writel((u32)DLY_INT_B_T0|( event_count<< 16 )|timeout,
+							 mmio+DLY_INT_B);
+			break;
+
+		case DISABLE_COAL:
+			writel(0,mmio+STVAL);
+			writel(STINTEN, mmio+INTEN0);
+			writel(0, mmio +DLY_INT_B);
+			writel(0, mmio+DLY_INT_A);
+			break;
+		 case ENABLE_COAL: 
+		       /* Start the timer */
+			writel((u32)SOFT_TIMER_FREQ, mmio+STVAL); /*  0.5 sec */
+			writel(VAL0|STINTEN, mmio+INTEN0);
+			break;
+		default:
+			break;
+
+   }
+	return 0;
+
+}
+
 /* 
 This function initializes the device registers  and starts the device.  
 */
@@ -267,13 +436,17 @@
 
 	if(amd8111e_init_ring(dev))
 		return -ENOMEM;
+
+	/* enable the port manager and set auto negotiation always */
+	writel((u32) VAL1|EN_PMGR, mmio + CMD3 );
+	writel((u32)XPHYANE|XPHYRST , mmio + CTRL2); 
 	
 	amd8111e_set_ext_phy(dev);
 
 	/* set control registers */
 	reg_val = readl(mmio + CTRL1);
-	
-	writel( reg_val| XMTSP_128 | CACHE_ALIGN | B1_MASK, mmio + CTRL1 );
+	reg_val &= ~XMTSP_MASK;
+	writel( reg_val| XMTSP_128 | CACHE_ALIGN, mmio + CTRL1 );
 
 	/* enable interrupt */
 	writel( APINT5EN | APINT4EN | APINT3EN | APINT2EN | APINT1EN | 
@@ -288,15 +461,21 @@
 
 	writew((u32)NUM_TX_RING_DR, mmio + XMT_RING_LEN0);
 	writew((u16)NUM_RX_RING_DR, mmio + RCV_RING_LEN0);
+	
+	/* set default IPG to 96 */
+	writew((u32)DEFAULT_IPG,mmio+IPG);
+	writew((u32)(DEFAULT_IPG-IFS1_DELTA), mmio + IFS1); 
 
 	if(lp->options & OPTION_JUMBO_ENABLE){
 		writel((u32)VAL2|JUMBO, mmio + CMD3);
 		/* Reset REX_UFLO */
 		writel( REX_UFLO, mmio + CMD2);
 		/* Should not set REX_UFLO for jumbo frames */
-		writel( VAL0 | APAD_XMT | REX_RTRY, mmio + CMD2);
-	}else
+		writel( VAL0 | APAD_XMT|REX_RTRY , mmio + CMD2);
+	}else{
 		writel( VAL0 | APAD_XMT | REX_RTRY|REX_UFLO, mmio + CMD2);
+		writel((u32)JUMBO, mmio + CMD3);
+	}
 
 #if AMD8111E_VLAN_TAG_USED
 	writel((u32) VAL2|VSIZE|VL_TAG_DEL, mmio + CMD3);
@@ -306,11 +485,20 @@
 	/* Setting the MAC address to the device */
 	for(i = 0; i < ETH_ADDR_LEN; i++)
 		writeb( dev->dev_addr[i], mmio + PADR + i ); 
+
+	/* Enable interrupt coalesce */
+	if(lp->options & OPTION_INTR_COAL_ENABLE){
+		printk(KERN_INFO "%s: Interrupt Coalescing Enabled.\n",
+								dev->name);
+		amd8111e_set_coalesce(dev,ENABLE_COAL);
+	}
 	
 	/* set RUN bit to start the chip */
 	writel(VAL2 | RDMD0, mmio + CMD0);
 	writel(VAL0 | INTREN | RUN, mmio + CMD0);
 	
+	/* To avoid PCI posting bug */
+	readl(mmio+CMD0);
 	return 0;
 }
 /* 
@@ -383,7 +571,7 @@
 	writew(MIB_CLEAR, mmio + MIB_ADDR);
 
 	/* Clear LARF */
-	AMD8111E_WRITE_REG64(mmio, LADRF,logic_filter);
+	amd8111e_writeq(*(u64*)logic_filter,mmio+LADRF);
 
 	/* SRAM_SIZE register */
 	reg_val = readl(mmio + SRAM_SIZE);
@@ -393,8 +581,11 @@
 #if AMD8111E_VLAN_TAG_USED
 	writel(VAL2|VSIZE|VL_TAG_DEL, mmio + CMD3 );
 #endif
-	/* CMD2 register */
-	reg_val = readl(mmio + CMD2);
+	/* Set default value to CTRL1 Register */
+	writel(CTRL1_DEFAULT, mmio + CTRL1);
+
+	/* To avoid PCI posting bug */
+	readl(mmio + CMD2);
 
 }
 
@@ -412,6 +603,9 @@
 	/* Clear INT0 */
 	intr0 = readl(lp->mmio + INT0);
 	writel(intr0, lp->mmio + INT0);
+	
+	/* To avoid PCI posting bug */
+	readl(lp->mmio + INT0);
 
 }
 
@@ -421,6 +615,9 @@
 static void amd8111e_stop_chip(struct amd8111e_priv* lp)
 {
 	writel(RUN, lp->mmio + CMD0);
+	
+	/* To avoid PCI posting bug */
+	readl(lp->mmio + CMD0);
 }
 
 /* 
@@ -467,11 +664,10 @@
 	struct amd8111e_priv* lp = dev->priv;
 	int tx_index = lp->tx_complete_idx & TX_RING_DR_MOD_MASK;
 	int status;
-	
 	/* Complete all the transmit packet */
 	while (lp->tx_complete_idx != lp->tx_idx){
 		tx_index =  lp->tx_complete_idx & TX_RING_DR_MOD_MASK;
-		status = le16_to_cpu(lp->tx_ring[tx_index].tx_dr_offset2);
+		status = le16_to_cpu(lp->tx_ring[tx_index].tx_flags);
 
 		if(status & OWN_BIT)
 			break;	/* It still hasn't been Txed */
@@ -487,11 +683,15 @@
 			lp->tx_skbuff[tx_index] = 0;
 			lp->tx_dma_addr[tx_index] = 0;
 		}
-		lp->tx_complete_idx++;	
+		lp->tx_complete_idx++;
+		/*COAL update tx coalescing parameters */
+		lp->coal_conf.tx_packets++;
+		lp->coal_conf.tx_bytes += lp->tx_ring[tx_index].buff_count;	
 
 		if (netif_queue_stopped(dev) &&
 			lp->tx_complete_idx > lp->tx_idx - NUM_TX_BUFFERS +2){
 			/* The ring is no longer full, clear tbusy. */
+			/* lp->tx_full = 0; */
 			netif_wake_queue (dev);
 		}
 	}
@@ -516,33 +716,31 @@
 	
 	/* If we own the next entry, it's a new packet. Send it up. */
 	while(++num_rx_pkt <= max_rx_pkt){
-		if(lp->rx_ring[rx_index].rx_dr_offset10 & OWN_BIT)
+		if(lp->rx_ring[rx_index].rx_flags & OWN_BIT)
 			return 0;
 	       
 		/* check if err summary bit is set */ 
-		if(le16_to_cpu(lp->rx_ring[rx_index].rx_dr_offset10) & ERR_BIT){
+		if(le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & ERR_BIT){
 			/* 
 			 * There is a tricky error noted by John Murphy,
 			 * <murf@perftech.com> to Russ Nelson: Even with full-sized
 			 * buffers it's possible for a jabber packet to use two
 			 * buffers, with only the last correctly noting the error.			 */
 			/* reseting flags */
-			lp->rx_ring[rx_index].rx_dr_offset10 &= 
-						cpu_to_le16(RESET_RX_FLAGS);
+			lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
 			goto err_next_pkt;
 		}
 		/* check for STP and ENP */
-		status = le16_to_cpu(lp->rx_ring[rx_index].rx_dr_offset10);
+		status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags);
 		if(!((status & STP_BIT) && (status & ENP_BIT))){
 			/* reseting flags */
-			lp->rx_ring[rx_index].rx_dr_offset10 &= 
-						cpu_to_le16(RESET_RX_FLAGS);
+			lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
 			goto err_next_pkt;
 		}
 		pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;
 
 #if AMD8111E_VLAN_TAG_USED		
-		vtag = le16_to_cpu(lp->rx_ring[rx_index].rx_dr_offset10) & TT_MASK;
+		vtag = le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & TT_MASK;
 		/*MAC will strip vlan tag*/ 
 		if(lp->vlgrp != NULL && vtag !=0)
 			min_pkt_len =MIN_PKT_LEN - 4;
@@ -551,16 +749,14 @@
 			min_pkt_len =MIN_PKT_LEN;
 
 		if (pkt_len < min_pkt_len) {
-			lp->rx_ring[rx_index].rx_dr_offset10 &= 
-				cpu_to_le16(RESET_RX_FLAGS);
+			lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
 			lp->stats.rx_errors++;
 			goto err_next_pkt;
 		}
 		if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){
 			/* if allocation fail, 
 				ignore that pkt and go to next one */
-			lp->rx_ring[rx_index].rx_dr_offset10 &= 
-				cpu_to_le16(RESET_RX_FLAGS);
+			lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
 			lp->stats.rx_errors++;
 			goto err_next_pkt;
 		}
@@ -580,22 +776,26 @@
 
 #if AMD8111E_VLAN_TAG_USED		
 		
-		vtag = lp->rx_ring[rx_index].rx_dr_offset10 & TT_MASK;
+		vtag = lp->rx_ring[rx_index].rx_flags & TT_MASK;
 		if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){
 			amd8111e_vlan_rx(lp, skb,
 				    lp->rx_ring[rx_index].tag_ctrl_info);
 		} else
 #endif
 			
-			dev->last_rx = jiffies;
 			netif_rx (skb);
+			/*COAL update rx coalescing parameters*/
+			lp->coal_conf.rx_packets++;
+			lp->coal_conf.rx_bytes += pkt_len;	
+
+			dev->last_rx = jiffies;
 	
 err_next_pkt:
 		lp->rx_ring[rx_index].buff_phy_addr
 			 = cpu_to_le32(lp->rx_dma_addr[rx_index]);
 		lp->rx_ring[rx_index].buff_count = 
 				cpu_to_le16(lp->rx_buff_len-2);
-		lp->rx_ring[rx_index].rx_dr_offset10 |= cpu_to_le16(OWN_BIT);
+		lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT);
 		rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK;
 	}
 
@@ -603,8 +803,8 @@
 }
 
 /* 
-This function will store the original speed to restore later, if autoneg is turned on. This speed will be set later when the autoneg is turned off. If the link status indicates that link is down, that will be indicated to the kernel */
-
+This function will indicate the link status to the kernel.
+*/
 static int amd8111e_link_change(struct net_device* dev)
 {	
 	struct amd8111e_priv *lp = dev->priv;
@@ -614,21 +814,11 @@
      	status0 = readl(lp->mmio + STAT0);
 	
 	if(status0 & LINK_STATS){
-		if(status0 & AUTONEG_COMPLETE){
-			/* keeping the original speeds */
-			if((lp->link_config.speed != SPEED_INVALID)&&
-				(lp->link_config.duplex != DUPLEX_INVALID)){
-			lp->link_config.orig_speed = lp->link_config.speed;
-			lp->link_config.orig_duplex = lp->link_config.duplex;
-			lp->link_config.orig_phy_option = lp->ext_phy_option;
-			}
-	
-			lp->link_config.speed = SPEED_INVALID;
-			lp->link_config.duplex = DUPLEX_INVALID;
+		if(status0 & AUTONEG_COMPLETE)
 			lp->link_config.autoneg = AUTONEG_ENABLE;
-			netif_carrier_on(dev);
-			return 0;
-		}
+		else 
+			lp->link_config.autoneg = AUTONEG_DISABLE;
+
 		if(status0 & FULL_DPLX)
 			lp->link_config.duplex = DUPLEX_FULL;
 		else 
@@ -638,13 +828,17 @@
 			lp->link_config.speed = SPEED_10;
 		else if(speed == PHY_SPEED_100)
 			lp->link_config.speed = SPEED_100;
-		lp->link_config.autoneg = AUTONEG_DISABLE;
+
+		printk(KERN_INFO "%s: Link is Up. Speed is %s Mbps %s Duplex\n",			dev->name,
+		       (lp->link_config.speed == SPEED_100) ? "100": "10", 
+		       (lp->link_config.duplex == DUPLEX_FULL)? "Full": "Half"); 
 		netif_carrier_on(dev);
 	}
 	else{	
 		lp->link_config.speed = SPEED_INVALID;
 		lp->link_config.duplex = DUPLEX_INVALID;
 		lp->link_config.autoneg = AUTONEG_INVALID;
+		printk(KERN_INFO "%s: Link is Down.\n",dev->name);
 		netif_carrier_off(dev);
 	}
 		
@@ -671,129 +865,250 @@
 }
 
 /*
-This function retuurns the reads the mib registers and returns the hardware statistics. It adds the previous statistics with new values.*/ 
+This function reads the mib registers and returns the hardware statistics. It  updates previous internal driver statistics with new values.
+*/ 
 static struct net_device_stats *amd8111e_get_stats(struct net_device * dev)
 {
 	struct amd8111e_priv *lp = dev->priv;
 	void * mmio = lp->mmio;
 	unsigned long flags;
-	struct net_device_stats *prev_stats = &lp->prev_stats;
+	/* struct net_device_stats *prev_stats = &lp->prev_stats; */
 	struct net_device_stats* new_stats = &lp->stats;
 	
 	if(!lp->opened)
-		return prev_stats;	
+		return &lp->stats;	
 	spin_lock_irqsave (&lp->lock, flags);
 
 	/* stats.rx_packets */
-	new_stats->rx_packets = prev_stats->rx_packets+
-		amd8111e_read_mib(mmio, rcv_broadcast_pkts)+
-		amd8111e_read_mib(mmio, rcv_multicast_pkts)+
-		amd8111e_read_mib(mmio, rcv_unicast_pkts);
+	new_stats->rx_packets = amd8111e_read_mib(mmio, rcv_broadcast_pkts)+
+				amd8111e_read_mib(mmio, rcv_multicast_pkts)+
+				amd8111e_read_mib(mmio, rcv_unicast_pkts);
 
 	/* stats.tx_packets */
-	new_stats->tx_packets = prev_stats->tx_packets+
-		amd8111e_read_mib(mmio, xmt_packets);
+	new_stats->tx_packets = amd8111e_read_mib(mmio, xmt_packets);
 
 	/*stats.rx_bytes */
-	new_stats->rx_bytes = prev_stats->rx_bytes+
-		amd8111e_read_mib(mmio, rcv_octets);
+	new_stats->rx_bytes = amd8111e_read_mib(mmio, rcv_octets);
 
 	/* stats.tx_bytes */
-	new_stats->tx_bytes = prev_stats->tx_bytes+
-		amd8111e_read_mib(mmio, xmt_octets);
+	new_stats->tx_bytes = amd8111e_read_mib(mmio, xmt_octets);
 
 	/* stats.rx_errors */
-	new_stats->rx_errors = prev_stats->rx_errors+
-		amd8111e_read_mib(mmio, rcv_undersize_pkts)+
-		amd8111e_read_mib(mmio, rcv_fragments)+
-		amd8111e_read_mib(mmio, rcv_jabbers)+
-		amd8111e_read_mib(mmio, rcv_alignment_errors)+
-		amd8111e_read_mib(mmio, rcv_fcs_errors)+
-		amd8111e_read_mib(mmio, rcv_miss_pkts);
+	new_stats->rx_errors = amd8111e_read_mib(mmio, rcv_undersize_pkts)+
+				amd8111e_read_mib(mmio, rcv_fragments)+
+				amd8111e_read_mib(mmio, rcv_jabbers)+
+				amd8111e_read_mib(mmio, rcv_alignment_errors)+
+				amd8111e_read_mib(mmio, rcv_fcs_errors)+
+				amd8111e_read_mib(mmio, rcv_miss_pkts);
 
 	/* stats.tx_errors */
-	new_stats->tx_errors = prev_stats->tx_errors+
-		amd8111e_read_mib(mmio, xmt_underrun_pkts);
+	new_stats->tx_errors = amd8111e_read_mib(mmio, xmt_underrun_pkts);
 
 	/* stats.rx_dropped*/
-	new_stats->rx_dropped = prev_stats->rx_dropped+
-		amd8111e_read_mib(mmio, rcv_miss_pkts);
+	new_stats->rx_dropped = amd8111e_read_mib(mmio, rcv_miss_pkts);
 
 	/* stats.tx_dropped*/
-	new_stats->tx_dropped = prev_stats->tx_dropped+
-		amd8111e_read_mib(mmio,  xmt_underrun_pkts);
+	new_stats->tx_dropped = amd8111e_read_mib(mmio,  xmt_underrun_pkts);
 
 	/* stats.multicast*/
-	new_stats->multicast = prev_stats->multicast+
-		amd8111e_read_mib(mmio, rcv_multicast_pkts);
+	new_stats->multicast = amd8111e_read_mib(mmio, rcv_multicast_pkts);
 
 	/* stats.collisions*/
-	new_stats->collisions = prev_stats->collisions+
-		amd8111e_read_mib(mmio, xmt_collisions);
+	new_stats->collisions = amd8111e_read_mib(mmio, xmt_collisions);
 
 	/* stats.rx_length_errors*/
-	new_stats->rx_length_errors = prev_stats->rx_length_errors+
+	new_stats->rx_length_errors = 
 		amd8111e_read_mib(mmio, rcv_undersize_pkts)+
 		amd8111e_read_mib(mmio, rcv_oversize_pkts);
 
 	/* stats.rx_over_errors*/
-	new_stats->rx_over_errors = prev_stats->rx_over_errors+
-		amd8111e_read_mib(mmio, rcv_miss_pkts);
+	new_stats->rx_over_errors = amd8111e_read_mib(mmio, rcv_miss_pkts);
 
 	/* stats.rx_crc_errors*/
-	new_stats->rx_crc_errors = prev_stats->rx_crc_errors+
-		amd8111e_read_mib(mmio, rcv_fcs_errors);
+	new_stats->rx_crc_errors = amd8111e_read_mib(mmio, rcv_fcs_errors);
 
 	/* stats.rx_frame_errors*/
-	new_stats->rx_frame_errors = prev_stats->rx_frame_errors+
+	new_stats->rx_frame_errors =
 		amd8111e_read_mib(mmio, rcv_alignment_errors);
 
 	/* stats.rx_fifo_errors */
-	new_stats->rx_fifo_errors = prev_stats->rx_fifo_errors+
-		amd8111e_read_mib(mmio, rcv_miss_pkts);
+	new_stats->rx_fifo_errors = amd8111e_read_mib(mmio, rcv_miss_pkts);
 
 	/* stats.rx_missed_errors */
-	new_stats->rx_missed_errors = prev_stats->rx_missed_errors+
-		amd8111e_read_mib(mmio, rcv_miss_pkts);
+	new_stats->rx_missed_errors = amd8111e_read_mib(mmio, rcv_miss_pkts);
 
 	/* stats.tx_aborted_errors*/
-	new_stats->tx_aborted_errors = prev_stats->tx_aborted_errors+
+	new_stats->tx_aborted_errors = 
 		amd8111e_read_mib(mmio, xmt_excessive_collision);
 
 	/* stats.tx_carrier_errors*/
-	new_stats->tx_carrier_errors = prev_stats->tx_carrier_errors+
+	new_stats->tx_carrier_errors = 
 		amd8111e_read_mib(mmio, xmt_loss_carrier);
 
 	/* stats.tx_fifo_errors*/
-	new_stats->tx_fifo_errors = prev_stats->tx_fifo_errors+
-		amd8111e_read_mib(mmio, xmt_underrun_pkts);
+	new_stats->tx_fifo_errors = amd8111e_read_mib(mmio, xmt_underrun_pkts);
 
 	/* stats.tx_window_errors*/
-	new_stats->tx_window_errors = prev_stats->tx_window_errors+
+	new_stats->tx_window_errors =
 		amd8111e_read_mib(mmio, xmt_late_collision);
 
+	/* Reset the mibs for collecting new statistics */
+	/* writew(MIB_CLEAR, mmio + MIB_ADDR);*/
+		
 	spin_unlock_irqrestore (&lp->lock, flags);
 
 	return new_stats;
 }
+/* This function recalculate the interupt coalescing  mode on every interrupt 
+according to the datarate and the packet rate.
+*/
+static int amd8111e_calc_coalesce(struct net_device *dev)
+{
+	struct amd8111e_priv *lp = dev->priv;
+	struct amd8111e_coalesce_conf * coal_conf = &lp->coal_conf;
+	int tx_pkt_rate;
+	int rx_pkt_rate;
+	int tx_data_rate;
+	int rx_data_rate;
+	int rx_pkt_size;
+	int tx_pkt_size;
+
+	tx_pkt_rate = coal_conf->tx_packets - coal_conf->tx_prev_packets;
+	coal_conf->tx_prev_packets =  coal_conf->tx_packets;
+	
+	tx_data_rate = coal_conf->tx_bytes - coal_conf->tx_prev_bytes;
+	coal_conf->tx_prev_bytes =  coal_conf->tx_bytes;
+	
+	rx_pkt_rate = coal_conf->rx_packets - coal_conf->rx_prev_packets;
+	coal_conf->rx_prev_packets =  coal_conf->rx_packets;
+	
+	rx_data_rate = coal_conf->rx_bytes - coal_conf->rx_prev_bytes;
+	coal_conf->rx_prev_bytes =  coal_conf->rx_bytes;
+	
+	if(rx_pkt_rate < 800){
+		if(coal_conf->rx_coal_type != NO_COALESCE){
+			
+			coal_conf->rx_timeout = 0x0;
+			coal_conf->rx_event_count = 0;
+			amd8111e_set_coalesce(dev,RX_INTR_COAL);
+			coal_conf->rx_coal_type = NO_COALESCE;
+		}
+	}
+	else{
+	
+		rx_pkt_size = rx_data_rate/rx_pkt_rate;
+		if (rx_pkt_size < 128){
+			if(coal_conf->rx_coal_type != NO_COALESCE){
+			
+				coal_conf->rx_timeout = 0;
+				coal_conf->rx_event_count = 0;
+				amd8111e_set_coalesce(dev,RX_INTR_COAL);
+				coal_conf->rx_coal_type = NO_COALESCE;
+			}
 
+		}
+		else if ( (rx_pkt_size >= 128) && (rx_pkt_size < 512) ){
+	
+			if(coal_conf->rx_coal_type !=  LOW_COALESCE){
+				coal_conf->rx_timeout = 1;
+				coal_conf->rx_event_count = 4;
+				amd8111e_set_coalesce(dev,RX_INTR_COAL);
+				coal_conf->rx_coal_type = LOW_COALESCE;
+			}
+		}
+		else if ((rx_pkt_size >= 512) && (rx_pkt_size < 1024)){
+			
+			if(coal_conf->rx_coal_type !=  MEDIUM_COALESCE){
+				coal_conf->rx_timeout = 1;
+				coal_conf->rx_event_count = 4;
+				amd8111e_set_coalesce(dev,RX_INTR_COAL);
+				coal_conf->rx_coal_type = MEDIUM_COALESCE;
+			}		
+				
+		}
+		else if(rx_pkt_size >= 1024){
+			if(coal_conf->rx_coal_type !=  HIGH_COALESCE){
+				coal_conf->rx_timeout = 2;
+				coal_conf->rx_event_count = 3;
+				amd8111e_set_coalesce(dev,RX_INTR_COAL);
+				coal_conf->rx_coal_type = HIGH_COALESCE;
+			}		
+		}
+	}
+    	/* NOW FOR TX INTR COALESC */
+	if(tx_pkt_rate < 800){
+		if(coal_conf->tx_coal_type != NO_COALESCE){
+			
+			coal_conf->tx_timeout = 0x0;
+			coal_conf->tx_event_count = 0;
+			amd8111e_set_coalesce(dev,TX_INTR_COAL);
+			coal_conf->tx_coal_type = NO_COALESCE;
+		}
+	}
+	else{
+	
+		tx_pkt_size = tx_data_rate/tx_pkt_rate;
+		if (tx_pkt_size < 128){
+		
+			if(coal_conf->tx_coal_type != NO_COALESCE){
+			
+				coal_conf->tx_timeout = 0;
+				coal_conf->tx_event_count = 0;
+				amd8111e_set_coalesce(dev,TX_INTR_COAL);
+				coal_conf->tx_coal_type = NO_COALESCE;
+			}
+
+		}
+		else if ( (tx_pkt_size >= 128) && (tx_pkt_size < 512) ){
+	
+			if(coal_conf->tx_coal_type !=  LOW_COALESCE){
+				coal_conf->tx_timeout = 1;
+				coal_conf->tx_event_count = 2;
+				amd8111e_set_coalesce(dev,TX_INTR_COAL);
+				coal_conf->tx_coal_type = LOW_COALESCE;
+
+			}
+		}
+		else if ((tx_pkt_size >= 512) && (tx_pkt_size < 1024)){
+			
+			if(coal_conf->tx_coal_type !=  MEDIUM_COALESCE){
+				coal_conf->tx_timeout = 2;
+				coal_conf->tx_event_count = 5;
+				amd8111e_set_coalesce(dev,TX_INTR_COAL);
+				coal_conf->tx_coal_type = MEDIUM_COALESCE;
+			}		
+				
+		}
+		else if(tx_pkt_size >= 1024){
+			if (tx_pkt_size >= 1024){
+				if(coal_conf->tx_coal_type !=  HIGH_COALESCE){
+					coal_conf->tx_timeout = 4;
+					coal_conf->tx_event_count = 8;
+					amd8111e_set_coalesce(dev,TX_INTR_COAL);
+					coal_conf->tx_coal_type = HIGH_COALESCE;
+				}		
+			}
+		}
+	}
+	return 0;
+
+}
 /*
-This is device interrupt function. It handles transmit, receive and link change interrupts.
+This is device interrupt function. It handles transmit, receive,link change and hardware timer interrupts.
 */
-static irqreturn_t
-amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 
 	struct net_device * dev = (struct net_device *) dev_id;
 	struct amd8111e_priv *lp = dev->priv;
 	void * mmio = lp->mmio;
 	unsigned int intr0;
-	int handled = 0;
+	unsigned int handled = 1;
 
 	if(dev == NULL)
 		return IRQ_NONE;
 
-	spin_lock (&lp->lock);
+	if (regs) spin_lock (&lp->lock);
 	/* disabling interrupt */
 	writel(INTREN, mmio + CMD0);
 
@@ -802,10 +1117,11 @@
 
 	/* Process all the INT event until INTR bit is clear. */
 
-	if (!(intr0 & INTR))
+	if (!(intr0 & INTR)) {
+		handled = 0;
 		goto err_no_interrupt;
-
-	handled = 1;
+	}
+		 
 	/* Current driver processes 3 interrupts : RINT,TINT,LCINT */
 	writel(intr0, mmio + INT0);
 
@@ -822,15 +1138,21 @@
 	/* Check if  Link Change Interrupt has occurred. */
 	if (intr0 & LCINT)
 		amd8111e_link_change(dev);
-	
+
+	/* Check if Hardware Timer Interrupt has occurred. */
+	if (intr0 & STINT)
+		amd8111e_calc_coalesce(dev);
+
 err_no_interrupt:
 	writel( VAL0 | INTREN,mmio + CMD0);
-	spin_unlock(&lp->lock);
+	
+	if (regs) spin_unlock(&lp->lock);
+	
 	return IRQ_RETVAL(handled);
-
 }
+
 /*
-This function closes the network interface and copies the new set of statistics into the previous statistics structure so that most recent statistics will be available after the interface is down.
+This function closes the network interface and updates the statistics so that most recent statistics will be available after the interface is down.
 */
 static int amd8111e_close(struct net_device * dev)
 {
@@ -845,10 +1167,15 @@
 	
 	netif_carrier_off(lp->amd8111e_net_dev);
 
+	/* Delete ipg timer */
+	if(lp->options & OPTION_DYN_IPG_ENABLE)	        
+		del_timer_sync(&lp->ipg_data.ipg_timer);
+
+	/* Update the statistics before closing */
+	amd8111e_get_stats(dev);
 	spin_unlock_irq(&lp->lock);
 
 	free_irq(dev->irq, dev);
-	memcpy(&lp->prev_stats,amd8111e_get_stats(dev), sizeof(lp->prev_stats));
 	lp->opened = 0;
 	return 0;
 }
@@ -870,7 +1197,12 @@
 		spin_unlock_irq(&lp->lock);
 		return -ENOMEM;
 	}
-	
+	/* Start ipg timer */
+	if(lp->options & OPTION_DYN_IPG_ENABLE){	        
+		add_timer(&lp->ipg_data.ipg_timer);
+		printk(KERN_INFO "%s: Dynamic IPG Enabled.\n",dev->name);
+	}
+
 	lp->opened = 1;
 
 	spin_unlock_irq(&lp->lock);
@@ -908,11 +1240,10 @@
 	lp->tx_ring[tx_index].buff_count = cpu_to_le16(skb->len);
 
 	lp->tx_skbuff[tx_index] = skb;
-	lp->tx_ring[tx_index].tx_dr_offset2 = 0;
+	lp->tx_ring[tx_index].tx_flags = 0;
 
 #if AMD8111E_VLAN_TAG_USED
 	if((lp->vlgrp != NULL) && vlan_tx_tag_present(skb)){
-
 		lp->tx_ring[tx_index].tag_ctrl_cmd |= 
 				cpu_to_le32(TCC_VLAN_INSERT);	
 		lp->tx_ring[tx_index].tag_ctrl_info = 
@@ -926,7 +1257,7 @@
 	    (u32) cpu_to_le32(lp->tx_dma_addr[tx_index]);
 
 	/*  Set FCS and LTINT bits */
-	lp->tx_ring[tx_index].tx_dr_offset2 |=
+	lp->tx_ring[tx_index].tx_flags |=
 	    cpu_to_le16(OWN_BIT | STP_BIT | ENP_BIT|ADD_FCS_BIT|LTINT_BIT);
 
 	lp->tx_idx++;
@@ -949,16 +1280,54 @@
 static char* amd8111e_read_regs(struct amd8111e_priv* lp)
 {    	
 	void * mmio = lp->mmio;
-        unsigned char * reg_buff;
+        u32 * reg_buff;
 
-     	int i;
-     
      	reg_buff = kmalloc( AMD8111E_REG_DUMP_LEN,GFP_KERNEL);
 	if(NULL == reg_buff)
 		return NULL;
-    	for (i=0; i < AMD8111E_REG_DUMP_LEN; i+=4)
-		reg_buff[i]= readl(mmio + i);	
-	return reg_buff;
+
+	/* Read only necessary registers */
+	reg_buff[0] = readl(mmio + XMT_RING_BASE_ADDR0);
+	reg_buff[1] = readl(mmio + XMT_RING_LEN0);
+	reg_buff[2] = readl(mmio + RCV_RING_BASE_ADDR0);
+	reg_buff[3] = readl(mmio + RCV_RING_LEN0);
+	reg_buff[4] = readl(mmio + CMD0);
+	reg_buff[5] = readl(mmio + CMD2);
+	reg_buff[6] = readl(mmio + CMD3);
+	reg_buff[7] = readl(mmio + CMD7);
+	reg_buff[8] = readl(mmio + INT0);
+	reg_buff[9] = readl(mmio + INTEN0);
+	reg_buff[10] = readl(mmio + LADRF);
+	reg_buff[11] = readl(mmio + LADRF+4);
+	reg_buff[12] = readl(mmio + STAT0);
+
+	return (char *)reg_buff;
+}
+/*
+amd8111e crc generator implementation is different from the kernel
+ether_crc() function.
+*/
+int amd8111e_ether_crc(int len, char* mac_addr)
+{
+	int i,byte;
+	unsigned char octet;
+	u32 crc= INITCRC;
+
+	for(byte=0; byte < len; byte++){
+		octet = mac_addr[byte];
+		for( i=0;i < 8; i++){
+			/*If the next bit form the input stream is 1,subtract				 the divisor (CRC32) from the dividend(crc).*/
+			if( (octet & 0x1) ^ (crc & 0x1) ){
+				crc >>= 1;
+				crc ^= CRC32;
+			}
+			else
+				crc >>= 1;
+			
+			octet >>= 1;
+		}
+	}	
+	return crc; 
 }
 /*
 This function sets promiscuos mode, all-multi mode or the multicast address 
@@ -970,9 +1339,8 @@
 	struct amd8111e_priv *lp = dev->priv;
 	u32 mc_filter[2] ;
 	int i,bit_num;
-
 	if(dev->flags & IFF_PROMISC){
-		printk("%s: Setting  promiscuous mode.\n",dev->name);
+		printk(KERN_INFO "%s: Setting  promiscuous mode.\n",dev->name);
 		writel( VAL2 | PROM, lp->mmio + CMD2);
 		return;
 	}
@@ -983,7 +1351,7 @@
 		mc_filter[1] = mc_filter[0] = 0xffffffff;
 		lp->mc_list = dev->mc_list;
 		lp->options |= OPTION_MULTICAST_ENABLE;
-		AMD8111E_WRITE_REG64(lp->mmio, LADRF,mc_filter);
+		amd8111e_writeq(*(u64*)mc_filter,lp->mmio + LADRF);
 		return;
 	}
 	if( dev->mc_count == 0 ){
@@ -991,7 +1359,7 @@
 		mc_filter[1] = mc_filter[0] = 0;
 		lp->mc_list = 0;
 		lp->options &= ~OPTION_MULTICAST_ENABLE;
-		AMD8111E_WRITE_REG64(lp->mmio, LADRF,mc_filter);
+		amd8111e_writeq(*(u64*)mc_filter,lp->mmio + LADRF);
 		/* disable promiscous mode */
 		writel(PROM, lp->mmio + CMD2);
 		return;
@@ -1002,14 +1370,16 @@
 	mc_filter[1] = mc_filter[0] = 0;
 	for (i = 0, mc_ptr = dev->mc_list; mc_ptr && i < dev->mc_count;
 		     i++, mc_ptr = mc_ptr->next) {
-		bit_num = ether_crc(ETH_ALEN, mc_ptr->dmi_addr) >> 26;
-			
+		bit_num = ( amd8111e_ether_crc(ETH_ALEN,mc_ptr->dmi_addr)							 >> 26 ) & 0x3f;
 		mc_filter[bit_num >> 5] |= 1 << (bit_num & 31);
 	}	
+	amd8111e_writeq(*(u64*)mc_filter,lp->mmio+ LADRF);
+
+	/* To eliminate PCI posting bug */
+	readl(lp->mmio + CMD2);
 
-	AMD8111E_WRITE_REG64(lp->mmio, LADRF, mc_filter);
-	return;
 }
+
 /*
 This function handles all the  ethtool ioctls. It gives driver info, gets/sets driver speed, gets memory mapped register values, forces auto negotiation, sets/gets WOL options for ethtool application. 
 */
@@ -1032,6 +1402,7 @@
 		strcpy (info.driver, MODULE_NAME);
 		strcpy (info.version, MODULE_VERSION);
 		memset(&info.fw_version, 0, sizeof(info.fw_version));
+		sprintf(info.fw_version,"%u",chip_version);
 		strcpy (info.bus_info, pci_dev->slot_name);
 		info.eedump_len = 0;
 		info.regdump_len = AMD8111E_REG_DUMP_LEN;
@@ -1039,85 +1410,27 @@
 			return -EFAULT;
 		return 0;
 	}
-	case ETHTOOL_GSET:{
-		struct ethtool_cmd cmd = { ETHTOOL_GSET };
-
-		if (!lp->opened) 
-			return -EAGAIN;
-
-		cmd.supported = SUPPORTED_Autoneg |
-				SUPPORTED_100baseT_Half |
-				SUPPORTED_100baseT_Full |
-			  	SUPPORTED_10baseT_Half |
-			        SUPPORTED_10baseT_Full |
-			        SUPPORTED_MII;
-
-		cmd.advertising = ADVERTISED_Autoneg |
-				ADVERTISED_100baseT_Half |
-				ADVERTISED_100baseT_Full |
-			  	ADVERTISED_10baseT_Half |
-			        ADVERTISED_10baseT_Full |
-			        ADVERTISED_MII;
-		cmd.speed = lp->link_config.speed;
-		cmd.duplex = lp->link_config.duplex;
-		cmd.port = 0;
-		cmd.phy_address = PHY_ID;
-		cmd.transceiver = XCVR_EXTERNAL;
-		cmd.autoneg = lp->link_config.autoneg;
-		cmd.maxtxpkt = 0; /* not implemented interrupt coalasing */
-		cmd.maxrxpkt = 0; /* not implemented interrupt coalasing */
-		if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&lp->lock);
+		mii_ethtool_gset(&lp->mii_if, &ecmd);
+		spin_unlock_irq(&lp->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
 			return -EFAULT;
 		return 0;
-		}
+	}
+	/* set settings */
 	case ETHTOOL_SSET: {
-	
-		struct ethtool_cmd cmd;
-
-		if (!lp->opened)
-			return -EAGAIN;
-		if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+		int r;
+		struct ethtool_cmd ecmd;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
 			return -EFAULT;
 
 		spin_lock_irq(&lp->lock);
-
-		if(cmd.autoneg == AUTONEG_ENABLE){
-			/* keeping the original speeds */
-			if((lp->link_config.speed != SPEED_INVALID)&&
-				(lp->link_config.duplex != DUPLEX_INVALID)){
-			lp->link_config.orig_speed = lp->link_config.speed;
-			lp->link_config.orig_duplex = lp->link_config.duplex;
-			lp->link_config.orig_phy_option = lp->ext_phy_option;
-			}
-
-			lp->ext_phy_option = XPHYANE;
-		}
-		else if(cmd.speed == SPEED_100 && cmd.duplex ==  DUPLEX_HALF)
-			lp->ext_phy_option = XPHYSP;
-		else if(cmd.speed == SPEED_100 && cmd.duplex ==  DUPLEX_FULL)
-			lp->ext_phy_option = XPHYSP |XPHYFD;
-		else if(cmd.speed == SPEED_10 && cmd.duplex ==  DUPLEX_HALF)
-			lp->ext_phy_option = 0;
-		else if(cmd.speed == SPEED_10 && cmd.duplex ==  DUPLEX_FULL)
-			lp->ext_phy_option = XPHYFD;
-		else {	
-			/* setting the original speed */
-			cmd.speed = lp->link_config.orig_speed;
-			cmd.duplex = lp->link_config.orig_duplex;
-			lp->ext_phy_option = lp->link_config.orig_phy_option;
-		}
-		lp->link_config.autoneg = cmd.autoneg;
-		if (cmd.autoneg == AUTONEG_ENABLE) {
-			
-			lp->link_config.speed = SPEED_INVALID;
-			lp->link_config.duplex = DUPLEX_INVALID;
-		} else {
-			lp->link_config.speed = cmd.speed;
-			lp->link_config.duplex = cmd.duplex;
-		}
-		amd8111e_set_ext_phy(dev);
+		r = mii_ethtool_sset(&lp->mii_if, &ecmd);
 		spin_unlock_irq(&lp->lock);
-		return 0;
+		return r;
 	}
 	case ETHTOOL_GREGS: {
 		struct ethtool_regs regs;
@@ -1143,24 +1456,17 @@
 		kfree(regbuf);
 		return ret;
 	}
+	/* restart autonegotiation */
 	case ETHTOOL_NWAY_RST: {
-		int ret;
-		spin_lock_irq(&lp->lock);
-		if(lp->link_config.autoneg == AUTONEG_ENABLE){
-			lp->ext_phy_option = XPHYANE;
-			amd8111e_set_ext_phy(dev);
-			ret = 0;
-		}else
-			ret =  -EINVAL;
-		spin_unlock_irq(&lp->lock);
-		return ret;
+		return mii_nway_restart(&lp->mii_if);
 	}
+	/* get link status */
 	case ETHTOOL_GLINK: {
-		struct ethtool_value val = { ETHTOOL_GLINK };
-
-		val.data = netif_carrier_ok(dev) ? 1 : 0;
+		struct ethtool_value val = {ETHTOOL_GLINK};
+		val.data = mii_link_ok(&lp->mii_if);
 		if (copy_to_user(useraddr, &val, sizeof(val)))
 			return -EFAULT;
+		return 0;
 	}
 	case ETHTOOL_GWOL: {
 		struct ethtool_wolinfo wol_info = { ETHTOOL_GWOL };
@@ -1199,60 +1505,6 @@
 	}
 		return -EOPNOTSUPP;
 }
-static int amd8111e_read_phy(struct amd8111e_priv* lp, int phy_id, int reg, u32* val)
-{
-	void * mmio = lp->mmio;
-	unsigned int reg_val;
-	unsigned int repeat= REPEAT_CNT;
-
-	reg_val = readl(mmio + PHY_ACCESS);
-	while (reg_val & PHY_CMD_ACTIVE)
-		reg_val = readl( mmio + PHY_ACCESS );
-
-	writel( PHY_RD_CMD | ((phy_id & 0x1f) << 21) |
-			   ((reg & 0x1f) << 16),  mmio +PHY_ACCESS);
-	do{
-		reg_val = readl(mmio + PHY_ACCESS);
-		udelay(30);  /* It takes 30 us to read/write data */
-	} while (--repeat && (reg_val & PHY_CMD_ACTIVE));
-	if(reg_val & PHY_RD_ERR)
-		goto err_phy_read;
-	
-	*val = reg_val & 0xffff;
-	return 0;
-err_phy_read:	
-	*val = 0;
-	return -EINVAL;
-	
-}
-static int amd8111e_write_phy(struct amd8111e_priv* lp,int phy_id, int reg, u32 val)
-{
-	unsigned int repeat = REPEAT_CNT
-	void * mmio = lp->mmio;
-	unsigned int reg_val;
-	
-
-	reg_val = readl(mmio + PHY_ACCESS);
-	while (reg_val & PHY_CMD_ACTIVE)
-		reg_val = readl( mmio + PHY_ACCESS );
-
-	writel( PHY_WR_CMD | ((phy_id & 0x1f) << 21) |
-			   ((reg & 0x1f) << 16)|val, mmio + PHY_ACCESS);
-
-	do{
-		reg_val = readl(mmio + PHY_ACCESS);
-		udelay(30);  /* It takes 30 us to read/write the data */
-	} while (--repeat && (reg_val & PHY_CMD_ACTIVE));
-	
-	if(reg_val & PHY_RD_ERR)
-		goto err_phy_write;
-	
-	return 0;
-
-err_phy_write:	
-	return -EINVAL;
-	
-}
 static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd)
 {
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
@@ -1320,15 +1572,10 @@
 
 	dev->mtu = new_mtu;
 
-	/* if (new_mtu > ETH_DATA_LEN)
-		lp->options |= OPTION_JUMBO_ENABLE;
-	else
-		lp->options &= ~OPTION_JUMBO_ENABLE;
-	*/
 	err = amd8111e_restart(dev);
 	spin_unlock_irq(&lp->lock);
-
-	netif_start_queue(dev);
+	if(!err)
+		netif_start_queue(dev);
 	return err;
 }
 
@@ -1354,73 +1601,41 @@
 {
 	writel( VAL1|MPPLBA, lp->mmio + CMD3);
 	writel( VAL0|MPEN_SW, lp->mmio + CMD7);
+
+	/* To eliminate PCI posting bug */
+	readl(lp->mmio + CMD7);
 	return 0;
 }
 
 static int amd8111e_enable_link_change(struct amd8111e_priv* lp)
 {
+
 	/* Adapter is already stoped/suspended/interrupt-disabled */
 	writel(VAL0|LCMODE_SW,lp->mmio + CMD7);
-	return 0;
-}	
-
-/* 
-This function sets the power state of the device. When the device go to lower power states 1,2, and 3 it enables the wake on lan 
-*/  	
-static int amd8111e_set_power_state(struct amd8111e_priv* lp, u32 state)
-{
-	u16 power_control;
-	int pm = lp->pm_cap;
-
-	pci_read_config_word(lp->pci_dev,
-			     pm + PCI_PM_CTRL,
-			     &power_control);
-
-	power_control |= PCI_PM_CTRL_PME_STATUS;
-	power_control &= ~(PCI_PM_CTRL_STATE_MASK);
-	switch (state) {
-	case 0:
-		power_control |= 0;
-		pci_write_config_word(lp->pci_dev,
-				      pm + PCI_PM_CTRL,
-				      power_control);
-		return 0;
-
-	case 1:
-		power_control |= 1;
-		break;
-
-	case 2:
-		power_control |= 2;
-		break;
-
-	case 3:
-		power_control |= 3;
-		break;
-	default:
-
-		printk(KERN_WARNING "%s: Invalid power state (%d) requested.\n",
-		       lp->amd8111e_net_dev->name, state);
-		return -EINVAL;
-	}
 	
-	if(lp->options & OPTION_WAKE_MAGIC_ENABLE)
-		amd8111e_enable_magicpkt(lp);	
-	if(lp->options & OPTION_WAKE_PHY_ENABLE)
-		amd8111e_enable_link_change(lp);	
-
-	/*  Setting new power state. */
-	pci_write_config_word(lp->pci_dev, pm + PCI_PM_CTRL, power_control);
-
+	/* To eliminate PCI posting bug */
+	readl(lp->mmio + CMD7);
 	return 0;
+}	
+/* This function is called when a packet transmission fails to complete within a  resonable period, on the assumption that an interrupts have been failed or the  interface is locked up. This function will reinitialize the hardware */
 
+static void amd8111e_tx_timeout(struct net_device *dev)
+{
+	struct amd8111e_priv* lp = dev->priv;
+	int err;
 
+	printk(KERN_ERR "%s: transmit timed out, resetting\n",
+	 					      dev->name);
+	spin_lock_irq(&lp->lock);
+	err = amd8111e_restart(dev);
+	spin_unlock_irq(&lp->lock);
+	if(!err)
+		netif_wake_queue(dev);
 }
 static int amd8111e_suspend(struct pci_dev *pci_dev, u32 state)
 {	
 	struct net_device *dev = pci_get_drvdata(pci_dev);
 	struct amd8111e_priv *lp = dev->priv;
-	int err;
 	
 	if (!netif_running(dev))
 		return 0;
@@ -1434,37 +1649,54 @@
 	
 	/* stop chip */
 	spin_lock_irq(&lp->lock);
+	if(lp->options & OPTION_DYN_IPG_ENABLE)	        
+		del_timer_sync(&lp->ipg_data.ipg_timer);
 	amd8111e_stop_chip(lp);
 	spin_unlock_irq(&lp->lock);
 
-	err = amd8111e_set_power_state(lp, state);
-	if (err) {
+	if(lp->options & OPTION_WOL_ENABLE){
+		 /* enable wol */
+		if(lp->options & OPTION_WAKE_MAGIC_ENABLE)
+			amd8111e_enable_magicpkt(lp);	
+		if(lp->options & OPTION_WAKE_PHY_ENABLE)
+			amd8111e_enable_link_change(lp);	
 		
-		spin_lock_irq(&lp->lock);
-		amd8111e_restart(dev);
-		spin_unlock_irq(&lp->lock);
+		pci_enable_wake(pci_dev, 3, 1);
+		pci_enable_wake(pci_dev, 4, 1); /* D3 cold */
 
-		netif_device_attach(dev);
 	}
-	return err;
+	else{		
+		pci_enable_wake(pci_dev, 3, 0);
+		pci_enable_wake(pci_dev, 4, 0); /* 4 == D3 cold */
+	}
+	
+	pci_save_state(pci_dev, lp->pm_state);
+	pci_set_power_state(pci_dev, 3);
+
+	return 0;
 }
 static int amd8111e_resume(struct pci_dev *pci_dev)
 {
 	struct net_device *dev = pci_get_drvdata(pci_dev);
 	struct amd8111e_priv *lp = dev->priv;
-	int err;
 	
 	if (!netif_running(dev))
 		return 0;
 
-	err = amd8111e_set_power_state(lp, 0);
-	if (err)
-		return err;
+	pci_set_power_state(pci_dev, 0);
+	pci_restore_state(pci_dev, lp->pm_state);
+
+	pci_enable_wake(pci_dev, 3, 0);
+	pci_enable_wake(pci_dev, 4, 0); /* D3 cold */
 
 	netif_device_attach(dev);
 
 	spin_lock_irq(&lp->lock);
 	amd8111e_restart(dev);
+	/* Restart ipg timer */
+	if(lp->options & OPTION_DYN_IPG_ENABLE)	        
+		mod_timer(&lp->ipg_data.ipg_timer, 
+				jiffies + (IPG_CONVERGE_TIME * HZ));
 	spin_unlock_irq(&lp->lock);
 
 	return 0;
@@ -1483,6 +1715,65 @@
 		pci_set_drvdata(pdev, NULL);
 	}
 }
+static void amd8111e_config_ipg(struct net_device* dev)
+{
+	struct amd8111e_priv *lp = dev->priv;
+	struct ipg_info* ipg_data = &lp->ipg_data;
+	void * mmio = lp->mmio;
+	unsigned int prev_col_cnt = ipg_data->col_cnt;
+	unsigned int total_col_cnt;
+	unsigned int tmp_ipg;
+	
+	if(lp->link_config.duplex == DUPLEX_FULL){
+		ipg_data->ipg = DEFAULT_IPG;
+		return;
+	}
+
+	if(ipg_data->ipg_state == SSTATE){
+		
+		if(ipg_data->timer_tick == IPG_STABLE_TIME){
+			
+			ipg_data->timer_tick = 0;
+			ipg_data->ipg = MIN_IPG - IPG_STEP;
+			ipg_data->current_ipg = MIN_IPG;
+			ipg_data->diff_col_cnt = 0xFFFFFFFF;
+			ipg_data->ipg_state = CSTATE;
+		}
+		else
+			ipg_data->timer_tick++;
+	}
+
+	if(ipg_data->ipg_state == CSTATE){
+		
+		/* Get the current collision count */
+
+		total_col_cnt = ipg_data->col_cnt = 
+				amd8111e_read_mib(mmio, xmt_collisions);
+
+		if ((total_col_cnt - prev_col_cnt) < 
+				(ipg_data->diff_col_cnt)){
+			
+			ipg_data->diff_col_cnt =
+				total_col_cnt - prev_col_cnt ;
+
+			ipg_data->ipg = ipg_data->current_ipg;
+		}
+
+		ipg_data->current_ipg += IPG_STEP;
+
+		if (ipg_data->current_ipg <= MAX_IPG)
+			tmp_ipg = ipg_data->current_ipg;
+		else{
+			tmp_ipg = ipg_data->ipg;
+			ipg_data->ipg_state = SSTATE;
+		}
+		writew((u32)tmp_ipg, mmio + IPG); 
+		writew((u32)(tmp_ipg - IFS1_DELTA), mmio + IFS1); 
+	}
+	 mod_timer(&lp->ipg_data.ipg_timer, jiffies + (IPG_CONVERGE_TIME * HZ));
+	return;
+
+}
 
 static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
 				  const struct pci_device_id *ent)
@@ -1491,7 +1782,6 @@
 	unsigned long reg_addr,reg_len;
 	struct amd8111e_priv* lp;
 	struct net_device* dev;
-	unsigned int chip_version;
 
 	err = pci_enable_device(pdev);
 	if(err){
@@ -1542,7 +1832,6 @@
 	}
 
 	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 ;
@@ -1551,11 +1840,16 @@
 #endif	
 	
 	lp = dev->priv;
-	memset (lp, 0, sizeof (*lp));
 	lp->pci_dev = pdev;
 	lp->amd8111e_net_dev = dev;
 	lp->pm_cap = pm_cap;
 
+	/* setting mii default values */
+	lp->mii_if.dev = dev;
+	lp->mii_if.mdio_read = amd8111e_mdio_read;
+	lp->mii_if.mdio_write = amd8111e_mdio_write;
+	lp->mii_if.phy_id = PHY_ID;
+
 	spin_lock_init(&lp->lock);
 
 	lp->mmio = ioremap(reg_addr, reg_len);
@@ -1569,12 +1863,14 @@
 	/* Initializing MAC address */
 	for(i = 0; i < ETH_ADDR_LEN; i++)
 			dev->dev_addr[i] =readb(lp->mmio + PADR + i);
-	/* Setting user defined speed */
-	if (speed_duplex[card_idx] > sizeof(speed_duplex_mapping))
-		lp->ext_phy_option = XPHYANE;
-	else
-		lp->ext_phy_option = 
-				speed_duplex_mapping[speed_duplex[card_idx]];
+	
+	/* Setting user defined parametrs */
+	lp->ext_phy_option = speed_duplex[card_idx];
+	if(coalesce[card_idx])
+		lp->options |= OPTION_INTR_COAL_ENABLE;		
+	if(dynamic_ipg[card_idx++])
+		lp->options |= OPTION_DYN_IPG_ENABLE;	        	
+
 	/* Initialize driver entry points */
 	dev->open = amd8111e_open;
 	dev->hard_start_xmit = amd8111e_start_xmit;
@@ -1584,6 +1880,8 @@
 	dev->do_ioctl = amd8111e_ioctl;
 	dev->change_mtu = amd8111e_change_mtu;
 	dev->irq =pdev->irq;
+	dev->tx_timeout = amd8111e_tx_timeout; 
+	dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; 
 
 #if AMD8111E_VLAN_TAG_USED
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
@@ -1593,10 +1891,6 @@
 	
 	/* Set receive buffer length and set jumbo option*/
 	amd8111e_set_rx_buff_len(dev);
-	
-
-	/* dev->tx_timeout = tg3_tx_timeout; */
-	/* dev->watchdog_timeo = TG3_TX_TIMEOUT; */
 
 	err = register_netdev(dev);
 	if (err) {
@@ -1607,15 +1901,26 @@
 
 	pci_set_drvdata(pdev, dev);
 	
+	/* Initialize software ipg timer */
+	if(lp->options & OPTION_DYN_IPG_ENABLE){	        
+		init_timer(&lp->ipg_data.ipg_timer);
+		lp->ipg_data.ipg_timer.data = (unsigned long) dev;
+		lp->ipg_data.ipg_timer.function = (void *)&amd8111e_config_ipg;
+		lp->ipg_data.ipg_timer.expires = jiffies + 
+						 IPG_CONVERGE_TIME * HZ;
+		lp->ipg_data.ipg = DEFAULT_IPG;
+		lp->ipg_data.ipg_state = CSTATE;
+	};
+
 	/*  display driver and device information */
 
-    chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28;
-    printk("%s: AMD-8111e Driver Version: %s\n",dev->name,MODULE_VERSION);
-    printk("%s: [ Rev %x ] PCI 10/100BaseT Ethernet ", dev->name, chip_version);
-    for (i = 0; i < 6; i++)
-	printk("%2.2x%c", dev->dev_addr[i],i == 5 ? ' ' : ':');
-     printk("\n");	
-	return 0;
+    	chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28;
+    	printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n",								 dev->name,MODULE_VERSION);
+    	printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet ",							dev->name, chip_version);
+    	for (i = 0; i < 6; i++)
+		printk("%2.2x%c",dev->dev_addr[i],i == 5 ? ' ' : ':');
+    	printk( "\n");	
+    	return 0;
 err_iounmap:
 	iounmap((void *) lp->mmio);
 
diff -Nru a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h
--- a/drivers/net/amd8111e.h	Fri Jan  3 12:01:30 2003
+++ b/drivers/net/amd8111e.h	Thu May 29 13:46:33 2003
@@ -1,4 +1,7 @@
 /*
+ * Advanced  Micro Devices Inc. AMD8111E Linux Network Driver 
+ * Copyright (C) 2003 Advanced Micro Devices 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -27,73 +30,14 @@
 	Kernel Mode
 
 Revision History:
-
+ 	3.0.0
+	   Initial Revision.
+	3.0.1
 */
 
 #ifndef _AMD811E_H
 #define _AMD811E_H
 
-/* Hardware definitions */
-
-#define B31_MASK	0x80000000
-#define B30_MASK	0X40000000
-#define B29_MASK	0x20000000
-#define B28_MASK	0x10000000
-#define B27_MASK	0x08000000
-#define B26_MASK	0x04000000
-#define B25_MASK	0x02000000
-#define B24_MASK	0x01000000
-#define B23_MASK	0x00800000
-#define B22_MASK	0x00400000
-#define B21_MASK	0x00200000
-#define B20_MASK	0x00100000
-#define B19_MASK	0x00080000
-#define B18_MASK	0x00040000
-#define B17_MASK	0x00020000
-#define B16_MASK	0x00010000
-
-#define B15_MASK	0x8000
-#define B14_MASK	0x4000
-#define B13_MASK	0x2000
-#define B12_MASK	0x1000
-#define B11_MASK	0x0800
-#define B10_MASK	0x0400
-#define B9_MASK		0x0200
-#define B8_MASK		0x0100
-#define B7_MASK		0x0080
-#define B6_MASK		0x0040
-#define B5_MASK		0x0020
-#define B4_MASK		0x0010
-#define B3_MASK		0x0008
-#define B2_MASK		0x0004
-#define B1_MASK		0x0002
-#define B0_MASK		0x0001
-
-/* PCI register offset */
-#define PCI_ID_REG		0x00
-#define PCI_COMMAND_REG		0x04
-/* #define MEMEN_BIT		B1_MASK */
-/* #define IOEN_BIT		B0_MASK */
-#define PCI_REV_ID_REG		0x08
-#define PCI_MEM_BASE_REG	0x10
-/* #define MEMBASE_MASK		0xFFFFF000 */
-/* #define MEMBASE_SIZE		4096 */
-#define PCI_INTR_REG		0x3C
-#define PCI_STATUS_REG		0x06
-#define PCI_CAP_ID_REG_OFFSET	0x34
-#define PCI_PMC_REG_OFFSET	0x36
-#define PCI_PMCSR_REG_OFFSET	0x38
-
-/* #define NEW_CAP		0x0010  */
-#define PME_EN			0x0100
-
-#define PARTID_MASK		0xFFFFF000
-#define PARTID_START_BIT	12
-
-/* #define LANCE_DWIO_RESET_PORT	0x18
-#define LANCE_WIO_RESET_PORT	0x14 */
-#define MIB_OFFSET		0x28
-
 /* Command style register access
 
 Registers CMD0, CMD2, CMD3,CMD7 and INTEN0 uses a write access technique called command style access. It allows the write to selected bits of this register without altering the bits that are not selected. Command style registers are divided into 4 bytes that can be written independently. Higher order bit of each byte is the  value bit that specifies the value that will be written into the selected bits of register. 
@@ -155,7 +99,7 @@
 #define XMT_RING_LEN2		0x148 	/* Transmit Ring2 length register */
 #define XMT_RING_LEN3		0x14C	/* Transmit Ring3 length register */
 
-#define RCV_RING_LEN0		0x150	/* Transmit Ring0 length register */
+#define RCV_RING_LEN0		0x150	/* Receive Ring0 length register */
 
 #define SRAM_SIZE		0x178	/* SRAM size register */
 #define SRAM_BOUNDARY		0x17A	/* SRAM boundary register */
@@ -164,391 +108,398 @@
 
 #define PADR			0x160	/* Physical address register */
 
+#define IFS1			0x18C	/* Inter-frame spacing Part1 register */
+#define IFS			0x18D	/* Inter-frame spacing register */
+#define IPG			0x18E	/* Inter-frame gap register */
 /* 64bit register */
 
 #define LADRF			0x168	/* Logical address filter register */
 
-/* 8bit regsisters */
-
-#define IFS1			0x18C	/* Inter-frame spacing Part1 register */
-#define IFS			0x18D	/* Inter-frame spacing register */
 
 /* Register Bit Definitions */
+typedef enum {
+
+	ASF_INIT_DONE		= (1 << 1),
+	ASF_INIT_PRESENT	= (1 << 0),
+
+}STAT_ASF_BITS; 
+   
+typedef enum {
+
+	MIB_CMD_ACTIVE		= (1 << 15 ),
+	MIB_RD_CMD		= (1 << 13 ),
+	MIB_CLEAR		= (1 << 12 ),
+	MIB_ADDRESS		= (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)|
+					(1 << 4) | (1 << 5),
+}MIB_ADDR_BITS;
+
+
+typedef enum {
+	
+	PMAT_DET		= (1 << 12),
+	MP_DET		        = (1 << 11),
+	LC_DET			= (1 << 10),
+	SPEED_MASK		= (1 << 9)|(1 << 8)|(1 << 7),
+	FULL_DPLX		= (1 << 6),
+	LINK_STATS		= (1 << 5),
+	AUTONEG_COMPLETE	= (1 << 4),
+	MIIPD			= (1 << 3),
+	RX_SUSPENDED		= (1 << 2),
+	TX_SUSPENDED		= (1 << 1),
+	RUNNING			= (1 << 0),
+
+}STAT0_BITS;
 
-/* STAT_ASF			0x00, 32bit register */
-#define ASF_INIT_DONE		B1_MASK
-#define ASF_INIT_PRESENT	B0_MASK
-
-/* MIB_ADDR			0x14, 16bit register */
-#define	MIB_CMD_ACTIVE		B15_MASK
-#define	MIB_RD_CMD		B13_MASK
-#define	MIB_CLEAR		B12_MASK
-#define	MIB_ADDRESS		0x0000003F	/* 5:0 */
-
-/* QOS_ADDR			0x1C, 16bit register */
-#define QOS_CMD_ACTIVE		B15_MASK
-#define QOS_WR_CMD		B14_MASK
-#define QOS_RD_CMD		B13_MASK
-#define QOS_ADDRESS		0x0000001F	/* 4:0 */
-
-/* STAT0			0x30, 32bit register */
-#define PAUSE_PEND		B14_MASK
-#define PAUSING			B13_MASK
-#define PMAT_DET		B12_MASK
-#define MP_DET			B11_MASK
-#define LC_DET			B10_MASK
-#define SPEED_MASK		0x0380	/* 9:7 */
-#define FULL_DPLX		B6_MASK
-#define LINK_STATS		B5_MASK
-#define AUTONEG_COMPLETE	B4_MASK
-#define MIIPD			B3_MASK
-#define RX_SUSPENDED		B2_MASK
-#define TX_SUSPENDED		B1_MASK
-#define RUNNING			B0_MASK
 #define PHY_SPEED_10		0x2
 #define PHY_SPEED_100		0x3
 
 /* INT0				0x38, 32bit register */
-#define INTR			B31_MASK
-#define PCSINT			B28_MASK
-#define LCINT			B27_MASK
-#define APINT5			B26_MASK
-#define APINT4			B25_MASK
-#define APINT3			B24_MASK
-#define TINT_SUM		B23_MASK
-#define APINT2			B22_MASK
-#define APINT1			B21_MASK
-#define APINT0			B20_MASK
-#define MIIPDTINT		B19_MASK
-#define MCCIINT			B18_MASK
-#define MCCINT			B17_MASK
-#define MREINT			B16_MASK
-#define RINT_SUM		B15_MASK
-#define SPNDINT			B14_MASK
-#define MPINT			B13_MASK
-#define SINT			B12_MASK
-#define TINT3			B11_MASK
-#define TINT2			B10_MASK
-#define TINT1			B9_MASK
-#define TINT0			B8_MASK
-#define UINT			B7_MASK
-#define STINT			B4_MASK
-#define RINT3			B3_MASK
-#define RINT2			B2_MASK
-#define RINT1			B1_MASK
-#define RINT0			B0_MASK
-
-/* INTEN0			0x40, 32bit register */
-#define VAL3			B31_MASK   /* VAL bit for byte 3 */
-#define VAL2			B23_MASK   /* VAL bit for byte 2 */
-#define VAL1			B15_MASK   /* VAL bit for byte 1 */
-#define VAL0			B7_MASK    /* VAL bit for byte 0 */
-/* VAL3 */
-#define PSCINTEN		B28_MASK
-#define LCINTEN			B27_MASK
-#define APINT5EN		B26_MASK
-#define APINT4EN		B25_MASK
-#define APINT3EN		B24_MASK
-/* VAL2 */
-#define APINT2EN		B22_MASK
-#define APINT1EN		B21_MASK
-#define APINT0EN		B20_MASK
-#define MIIPDTINTEN		B19_MASK
-#define MCCIINTEN		B18_MASK
-#define MCCINTEN		B17_MASK
-#define MREINTEN		B16_MASK
-/* VAL1 */
-#define SPNDINTEN		B14_MASK
-#define MPINTEN			B13_MASK
-#define SINTEN			B12_MASK
-#define TINTEN3			B11_MASK
-#define TINTEN2			B10_MASK
-#define TINTEN1			B9_MASK
-#define TINTEN0			B8_MASK
-/* VAL0 */
-#define STINTEN			B4_MASK
-#define RINTEN3			B3_MASK
-#define RINTEN2			B2_MASK
-#define RINTEN1			B1_MASK
-#define RINTEN0			B0_MASK
-
-#define INTEN0_CLEAR 		0x1F7F7F1F /* Command style register */		
-
-/* CMD0				0x48, 32bit register */
-/* VAL2 */
-#define RDMD3			B19_MASK
-#define RDMD2			B18_MASK
-#define RDMD1			B17_MASK
-#define RDMD0			B16_MASK
-/* VAL1 */
-#define TDMD3			B11_MASK
-#define TDMD2			B10_MASK
-#define TDMD1			B9_MASK
-#define TDMD0			B8_MASK
-/* VAL0 */
-#define UINTCMD			B6_MASK
-#define RX_FAST_SPND		B5_MASK
-#define TX_FAST_SPND		B4_MASK
-#define RX_SPND			B3_MASK
-#define TX_SPND			B2_MASK
-#define INTREN			B1_MASK
-#define RUN			B0_MASK
-
-#define CMD0_CLEAR 		0x000F0F7F   /* Command style register */	
-
-/* CMD2 			0x50, 32bit register */
-/* VAL3 */
-#define CONDUIT_MODE		B29_MASK
-/* VAL2 */
-#define RPA			B19_MASK
-#define DRCVPA			B18_MASK
-#define DRCVBC			B17_MASK
-#define PROM			B16_MASK
-/* VAL1 */
-#define ASTRP_RCV		B13_MASK
-#define FCOLL			B12_MASK
-#define EMBA			B11_MASK
-#define DXMT2PD			B10_MASK
-#define LTINTEN			B9_MASK
-#define DXMTFCS			B8_MASK
-/* VAL0 */
-#define APAD_XMT		B6_MASK
-#define DRTY			B5_MASK
-#define INLOOP			B4_MASK
-#define EXLOOP			B3_MASK
-#define REX_RTRY		B2_MASK
-#define REX_UFLO		B1_MASK
-#define REX_LCOL		B0_MASK
-
-#define CMD2_CLEAR 		0x3F7F3F7F   /* Command style register */
-
-/* CMD3				0x54, 32bit register */
-/* VAL3 */
-#define ASF_INIT_DONE_ALIAS	B29_MASK
-/* VAL2 */
-#define JUMBO			B21_MASK
-#define VSIZE			B20_MASK
-#define VLONLY			B19_MASK
-#define VL_TAG_DEL		B18_MASK
-/* VAL1 */
-#define EN_PMGR			B14_MASK
-#define INTLEVEL		B13_MASK
-#define FORCE_FULL_DUPLEX	B12_MASK
-#define FORCE_LINK_STATUS	B11_MASK
-#define APEP			B10_MASK
-#define MPPLBA			B9_MASK
-/* VAL0 */
-#define RESET_PHY_PULSE		B2_MASK
-#define RESET_PHY		B1_MASK
-#define PHY_RST_POL		B0_MASK
-/* CMD7				0x64, 32bit register */
-/* VAL0 */
-#define PMAT_SAVE_MATCH		B4_MASK
-#define PMAT_MODE		B3_MASK
-#define MPEN_SW			B1_MASK
-#define LCMODE_SW		B0_MASK
-
-#define CMD7_CLEAR  		0x0000001B		/* Command style register */
-/* CTRL0			0x68, 32bit register */
-#define PHY_SEL			0x03000000	/* 25:24 */
-#define RESET_PHY_WIDTH		0x00FF0000	/* 23:16 */
-#define BSWP_REGS		B10_MASK
-#define BSWP_DESC		B9_MASK
-#define BSWP_DATA		B8_MASK
-#define CACHE_ALIGN		B4_MASK
-#define BURST_LIMIT		0x0000000F	/* 3:0 */
-
-/* CTRL1			0x6C, 32bit register */
-#define SLOTMOD_MASK		0x03000000	/* 25:24 */
-#define XMTSP_MASK		0x300	/* 17:16 */
-#define XMTSP_128		0x200
-#define XMTSP_64		0x100
-#define CRTL1_DEFAULT		0x00000017
-
-/* CTRL2			0x70, 32bit register */
-#define FS_MASK			0x00070000	/* 18:16 */
-#define FMDC_MASK		0x00000300	/* 9:8 */
-#define XPHYRST			B7_MASK
-#define XPHYANE			B6_MASK
-#define XPHYFD			B5_MASK
-#define XPHYSP			B3_MASK	/* 4:3 */
-#define APDW_MASK		0x00000007	/* 2:0 */
-
-/* RCV_RING_CFG			0x78, 16bit register */
-#define RCV_DROP3		B11_MASK
-#define RCV_DROP2		B10_MASK
-#define RCV_DROP1		B9_MASK
-#define RCV_DROP0		B8_MASK
-#define RCV_RING_DEFAULT	0x0030	/* 5:4 */
-#define RCV_RING3_EN		B3_MASK
-#define RCV_RING2_EN		B2_MASK
-#define RCV_RING1_EN		B1_MASK
-#define RCV_RING0_EN		B0_MASK
+typedef enum {
+
+	INTR			= (1 << 31),
+	PCSINT			= (1 << 28), 
+	LCINT			= (1 << 27),
+	APINT5			= (1 << 26),
+	APINT4			= (1 << 25),
+	APINT3			= (1 << 24),
+	TINT_SUM		= (1 << 23),
+	APINT2			= (1 << 22),
+	APINT1			= (1 << 21),
+	APINT0			= (1 << 20),
+	MIIPDTINT		= (1 << 19),
+	MCCINT			= (1 << 17),
+	MREINT			= (1 << 16),
+	RINT_SUM		= (1 << 15),
+	SPNDINT			= (1 << 14),
+	MPINT			= (1 << 13),
+	SINT			= (1 << 12),
+	TINT3			= (1 << 11),
+	TINT2			= (1 << 10),
+	TINT1			= (1 << 9),
+	TINT0			= (1 << 8),
+	UINT			= (1 << 7),
+	STINT			= (1 << 4),
+	RINT0			= (1 << 0),
+
+}INT0_BITS;
+
+typedef enum {
+
+	VAL3			= (1 << 31),   /* VAL bit for byte 3 */
+	VAL2			= (1 << 23),   /* VAL bit for byte 2 */
+	VAL1			= (1 << 15),   /* VAL bit for byte 1 */
+	VAL0			= (1 << 7),    /* VAL bit for byte 0 */
+
+}VAL_BITS;
+
+typedef enum {
+
+	/* VAL3 */
+	LCINTEN			= (1 << 27),
+	APINT5EN		= (1 << 26),
+	APINT4EN		= (1 << 25),
+	APINT3EN		= (1 << 24),
+	/* VAL2 */
+	APINT2EN		= (1 << 22),
+	APINT1EN		= (1 << 21),
+	APINT0EN		= (1 << 20),
+	MIIPDTINTEN		= (1 << 19),
+	MCCIINTEN		= (1 << 18),
+	MCCINTEN		= (1 << 17),
+	MREINTEN		= (1 << 16),
+	/* VAL1 */
+	SPNDINTEN		= (1 << 14),
+	MPINTEN			= (1 << 13),
+	TINTEN3			= (1 << 11),
+	SINTEN			= (1 << 12),
+	TINTEN2			= (1 << 10),
+	TINTEN1			= (1 << 9),
+	TINTEN0			= (1 << 8),
+	/* VAL0 */
+	STINTEN			= (1 << 4),
+	RINTEN0			= (1 << 0),
+
+	INTEN0_CLEAR 		= 0x1F7F7F1F, /* Command style register */
+
+}INTEN0_BITS;		
+
+typedef enum {
+	/* VAL2 */
+	RDMD0			= (1 << 16),
+	/* VAL1 */
+	TDMD3			= (1 << 11),
+	TDMD2			= (1 << 10),
+	TDMD1			= (1 << 9),
+	TDMD0			= (1 << 8),
+	/* VAL0 */
+	UINTCMD			= (1 << 6),
+	RX_FAST_SPND		= (1 << 5),
+	TX_FAST_SPND		= (1 << 4),
+	RX_SPND			= (1 << 3),
+	TX_SPND			= (1 << 2),
+	INTREN			= (1 << 1),
+	RUN			= (1 << 0),
+
+	CMD0_CLEAR 		= 0x000F0F7F,   /* Command style register */	
+
+}CMD0_BITS;
+
+typedef enum {
+
+	/* VAL3 */
+	CONDUIT_MODE		= (1 << 29),
+	/* VAL2 */
+	RPA			= (1 << 19),
+	DRCVPA			= (1 << 18),
+	DRCVBC			= (1 << 17),
+	PROM			= (1 << 16),
+	/* VAL1 */
+	ASTRP_RCV		= (1 << 13),
+	RCV_DROP0	  	= (1 << 12),
+	EMBA			= (1 << 11),
+	DXMT2PD			= (1 << 10),
+	LTINTEN			= (1 << 9),
+	DXMTFCS			= (1 << 8),
+	/* VAL0 */
+	APAD_XMT		= (1 << 6),
+	DRTY			= (1 << 5),
+	INLOOP			= (1 << 4),
+	EXLOOP			= (1 << 3),
+	REX_RTRY		= (1 << 2),
+	REX_UFLO		= (1 << 1),
+	REX_LCOL		= (1 << 0),
+
+	CMD2_CLEAR 		= 0x3F7F3F7F,   /* Command style register */
+
+}CMD2_BITS;
+
+typedef enum {
+
+	/* VAL3 */
+	ASF_INIT_DONE_ALIAS	= (1 << 29),
+	/* VAL2 */
+	JUMBO			= (1 << 21),
+	VSIZE			= (1 << 20),	
+	VLONLY			= (1 << 19),
+	VL_TAG_DEL		= (1 << 18),	
+	/* VAL1 */
+	EN_PMGR			= (1 << 14),			
+	INTLEVEL		= (1 << 13),
+	FORCE_FULL_DUPLEX	= (1 << 12),	
+	FORCE_LINK_STATUS	= (1 << 11),	
+	APEP			= (1 << 10),	
+	MPPLBA			= (1 << 9),	
+	/* VAL0 */
+	RESET_PHY_PULSE		= (1 << 2),	
+	RESET_PHY		= (1 << 1),	
+	PHY_RST_POL		= (1 << 0),	
+
+}CMD3_BITS;
+
+
+typedef enum {
+
+	/* VAL0 */
+	PMAT_SAVE_MATCH		= (1 << 4),
+	PMAT_MODE		= (1 << 3),
+	MPEN_SW			= (1 << 1),
+	LCMODE_SW		= (1 << 0),
+
+	CMD7_CLEAR  		= 0x0000001B	/* Command style register */
+
+}CMD7_BITS;
+
+
+typedef enum {
+
+	RESET_PHY_WIDTH		= (0xF << 16) | (0xF<< 20), /* 0x00FF0000 */
+	XMTSP_MASK		= (1 << 9) | (1 << 8),	/* 9:8 */
+	XMTSP_128		= (1 << 9),	/* 9 */	
+	XMTSP_64		= (1 << 8),
+	CACHE_ALIGN		= (1 << 4),
+	BURST_LIMIT_MASK	= (0xF << 0 ),
+	CTRL1_DEFAULT		= 0x00010111,
+
+}CTRL1_BITS;
+
+typedef enum {
+
+	FMDC_MASK		= (1 << 9)|(1 << 8),	/* 9:8 */
+	XPHYRST			= (1 << 7),
+	XPHYANE			= (1 << 6),
+	XPHYFD			= (1 << 5),
+	XPHYSP			= (1 << 4) | (1 << 3),	/* 4:3 */
+	APDW_MASK		= (1 <<	2) | (1 << 1) | (1 << 0), /* 2:0 */
+
+}CTRL2_BITS;
 
 /* XMT_RING_LIMIT		0x7C, 32bit register */
-#define XMT_RING2_LIMIT		0x00FF0000	/* 23:16 */
-#define XMT_RING1_LIMIT		0x0000FF00	/* 15:8 */
-#define XMT_RING0_LIMIT		0x000000FF	/* 7:0 */
-
-/* AUTOPOLL0			0x88, 16bit register */
-#define AP_REG0_EN		B15_MASK
-#define AP_REG0_ADDR_MASK	0x1F00	/* 12:8 */
-#define AP_PHY0_ADDR_MASK	0x001F	/* 4:0 */
+typedef enum {
+
+	XMT_RING2_LIMIT		= (0xFF << 16),	/* 23:16 */
+	XMT_RING1_LIMIT		= (0xFF << 8),	/* 15:8 */
+	XMT_RING0_LIMIT		= (0xFF << 0), 	/* 7:0 */
+
+}XMT_RING_LIMIT_BITS;
+
+typedef enum {
+
+	AP_REG0_EN		= (1 << 15),
+	AP_REG0_ADDR_MASK	= (0xF << 8) |(1 << 12),/* 12:8 */
+	AP_PHY0_ADDR_MASK	= (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL0_BITS;
 
 /* AUTOPOLL1			0x8A, 16bit register */
-#define AP_REG1_EN		B15_MASK
-#define AP_REG1_ADDR_MASK	0x1F00	/* 12:8 */
-#define AP_PRE_SUP1		B6_MASK
-#define AP_PHY1_DFLT		B5_MASK
-#define AP_PHY1_ADDR_MASK	0x001F	/* 4:0 */
-
-/* AUTOPOLL2			0x8C, 16bit register */
-#define AP_REG2_EN		B15_MASK
-#define AP_REG2_ADDR_MASK	0x1F00	/* 12:8 */
-#define AP_PRE_SUP2		B6_MASK
-#define AP_PHY2_DFLT		B5_MASK
-#define AP_PHY2_ADDR_MASK	0x001F	/* 4:0 */
-
-/* AUTOPOLL3			0x8E, 16bit register */
-#define AP_REG3_EN		B15_MASK
-#define AP_REG3_ADDR_MASK	0x1F00	/* 12:8 */
-#define AP_PRE_SUP3		B6_MASK
-#define AP_PHY3_DFLT		B5_MASK
-#define AP_PHY3_ADDR_MASK	0x001F	/* 4:0 */
-
-/* AUTOPOLL4			0x90, 16bit register */
-#define AP_REG4_EN		B15_MASK
-#define AP_REG4_ADDR_MASK	0x1F00	/* 12:8 */
-#define AP_PRE_SUP4		B6_MASK
-#define AP_PHY4_DFLT		B5_MASK
-#define AP_PHY4_ADDR_MASK	0x001F	/* 4:0 */
-
-/* AUTOPOLL5			0x92, 16bit register */
-#define AP_REG5_EN		B15_MASK
-#define AP_REG5_ADDR_MASK	0x1F00	/* 12:8 */
-#define AP_PRE_SUP5		B6_MASK
-#define AP_PHY5_DFLT		B5_MASK
-#define AP_PHY5_ADDR_MASK	0x001F	/* 4:0 */
+typedef enum {
+
+	AP_REG1_EN		= (1 << 15),
+	AP_REG1_ADDR_MASK	= (0xF << 8) |(1 << 12),/* 12:8 */
+	AP_PRE_SUP1		= (1 << 6),
+	AP_PHY1_DFLT		= (1 << 5),
+	AP_PHY1_ADDR_MASK	= (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL1_BITS;
+
+
+typedef enum {
+
+	AP_REG2_EN		= (1 << 15),
+	AP_REG2_ADDR_MASK	= (0xF << 8) |(1 << 12),/* 12:8 */
+	AP_PRE_SUP2		= (1 << 6),
+	AP_PHY2_DFLT		= (1 << 5),
+	AP_PHY2_ADDR_MASK	= (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL2_BITS;
+
+typedef enum {
+
+	AP_REG3_EN		= (1 << 15),
+	AP_REG3_ADDR_MASK	= (0xF << 8) |(1 << 12),/* 12:8 */
+	AP_PRE_SUP3		= (1 << 6),
+	AP_PHY3_DFLT		= (1 << 5),
+	AP_PHY3_ADDR_MASK	= (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL3_BITS;
+
+
+typedef enum {
+
+	AP_REG4_EN		= (1 << 15),
+	AP_REG4_ADDR_MASK	= (0xF << 8) |(1 << 12),/* 12:8 */
+	AP_PRE_SUP4		= (1 << 6),
+	AP_PHY4_DFLT		= (1 << 5),
+	AP_PHY4_ADDR_MASK	= (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL4_BITS;
+
+
+typedef enum {
+
+	AP_REG5_EN		= (1 << 15),
+	AP_REG5_ADDR_MASK	= (0xF << 8) |(1 << 12),/* 12:8 */
+	AP_PRE_SUP5		= (1 << 6),
+	AP_PHY5_DFLT		= (1 << 5),
+	AP_PHY5_ADDR_MASK	= (0xF << 0) |(1 << 4),/* 4:0 */
+
+}AUTOPOLL5_BITS;
+
+
+
 
 /* AP_VALUE 			0x98, 32bit ragister */
-#define AP_VAL_ACTIVE		B31_MASK
-#define AP_VAL_RD_CMD		B29_MASK
-#define AP_ADDR			0x00070000	/* 18:16 */
-#define AP_VAL			0x0000FFFF	/* 15:0 */
-
-/* PCS_ANEG			0x9C, 32bit register */
-#define SYNC_LOST		B10_MASK
-#define IMATCH			B9_MASK
-#define CMATCH			B8_MASK
-#define PCS_AN_IDLE		B1_MASK
-#define PCS_AN_CFG		B0_MASK
-
-/* DLY_INT_A			0xA8, 32bit register */
-#define DLY_INT_A_R3		B31_MASK
-#define DLY_INT_A_R2		B30_MASK
-#define DLY_INT_A_R1		B29_MASK
-#define DLY_INT_A_R0		B28_MASK
-#define DLY_INT_A_T3		B27_MASK
-#define DLY_INT_A_T2		B26_MASK
-#define DLY_INT_A_T1		B25_MASK
-#define DLY_INT_A_T0		B24_MASK
-#define EVENT_COUNT_A		0x00FF0000	/* 20:16 */
-#define MAX_DELAY_TIME_A	0x000007FF	/* 10:0 */
-
-/* DLY_INT_B			0xAC, 32bit register */
-#define DLY_INT_B_R3		B31_MASK
-#define DLY_INT_B_R2		B30_MASK
-#define DLY_INT_B_R1		B29_MASK
-#define DLY_INT_B_R0		B28_MASK
-#define DLY_INT_B_T3		B27_MASK
-#define DLY_INT_B_T2		B26_MASK
-#define DLY_INT_B_T1		B25_MASK
-#define DLY_INT_B_T0		B24_MASK
-#define EVENT_COUNT_B		0x00FF0000	/* 20:16 */
-#define MAX_DELAY_TIME_B	0x000007FF	/* 10:0 */
-
-/* DFC_THRESH2			0xC0, 16bit register */
-#define DFC_THRESH2_HIGH	0xFF00	/* 15:8 */
-#define DFC_THRESH2_LOW		0x00FF	/* 7:0 */
-
-/* DFC_THRESH3			0xC2, 16bit register */
-#define DFC_THRESH3_HIGH	0xFF00	/* 15:8 */
-#define DFC_THRESH3_LOW		0x00FF	/* 7:0 */
-
-/* DFC_THRESH0			0xC4, 16bit register */
-#define DFC_THRESH0_HIGH	0xFF00	/* 15:8 */
-#define DFC_THRESH0_LOW		0x00FF	/* 7:0 */
-
-/* DFC_THRESH1			0xC6, 16bit register */
-#define DFC_THRESH1_HIGH	0xFF00	/* 15:8 */
-#define DFC_THRESH1_LOW		0x00FF	/* 7:0 */
+typedef enum {
+
+	AP_VAL_ACTIVE		= (1 << 31),
+	AP_VAL_RD_CMD		= ( 1 << 29),
+	AP_ADDR			= (1 << 18)|(1 << 17)|(1 << 16), /* 18:16 */
+	AP_VAL			= (0xF << 0) | (0xF << 4) |( 0xF << 8) |
+				  (0xF << 12),	/* 15:0 */
+
+}AP_VALUE_BITS;
+
+typedef enum {
+
+	DLY_INT_A_R3		= (1 << 31),
+	DLY_INT_A_R2		= (1 << 30),
+	DLY_INT_A_R1		= (1 << 29),
+	DLY_INT_A_R0		= (1 << 28),
+	DLY_INT_A_T3		= (1 << 27),
+	DLY_INT_A_T2		= (1 << 26),
+	DLY_INT_A_T1		= (1 << 25),
+	DLY_INT_A_T0		= ( 1 << 24),
+	EVENT_COUNT_A		= (0xF << 16) | (0x1 << 20),/* 20:16 */
+	MAX_DELAY_TIME_A	= (0xF << 0) | (0xF << 4) | (1 << 8)|
+				  (1 << 9) | (1 << 10),	/* 10:0 */
+
+}DLY_INT_A_BITS;
+
+typedef enum {
+
+	DLY_INT_B_R3		= (1 << 31),
+	DLY_INT_B_R2		= (1 << 30),
+	DLY_INT_B_R1		= (1 << 29),
+	DLY_INT_B_R0		= (1 << 28),
+	DLY_INT_B_T3		= (1 << 27),
+	DLY_INT_B_T2		= (1 << 26),
+	DLY_INT_B_T1		= (1 << 25),
+	DLY_INT_B_T0		= ( 1 << 24),
+	EVENT_COUNT_B		= (0xF << 16) | (0x1 << 20),/* 20:16 */
+	MAX_DELAY_TIME_B	= (0xF << 0) | (0xF << 4) | (1 << 8)| 
+				  (1 << 9) | (1 << 10),	/* 10:0 */
+}DLY_INT_B_BITS;
+
 
 /* FLOW_CONTROL 		0xC8, 32bit register */
-#define PAUSE_LEN_CHG		B30_MASK
-#define	FFC_EN			B28_MASK
-#define DFC_RING3_EN		B27_MASK
-#define DFC_RING2_EN		B26_MASK
-#define DFC_RING1_EN		B25_MASK
-#define DFC_RING0_EN		B24_MASK
-#define FIXP_CONGEST		B21_MASK
-#define FPA			B20_MASK
-#define NPA			B19_MASK
-#define FIXP			B18_MASK
-#define FCPEN			B17_MASK
-#define FCCMD			B16_MASK
-#define PAUSE_LEN		0x0000FFFF	/* 15:0 */
-
-/* FFC THRESH			0xCC, 32bit register */
-#define FFC_HIGH		0xFFFF0000	/* 31:16 */
-#define FFC_LOW			0x0000FFFF	/* 15:0 */
+typedef enum {
+
+	PAUSE_LEN_CHG		= (1 << 30),
+	FTPE			= (1 << 22),
+	FRPE			= (1 << 21),
+	NAPA			= (1 << 20),
+	NPA			= (1 << 19),
+	FIXP			= ( 1 << 18),
+	FCCMD			= ( 1 << 16),
+	PAUSE_LEN		= (0xF << 0) | (0xF << 4) |( 0xF << 8) |	 				  (0xF << 12),	/* 15:0 */
+
+}FLOW_CONTROL_BITS;
 
 /* PHY_ ACCESS			0xD0, 32bit register */
-#define	PHY_CMD_ACTIVE		B31_MASK
-#define PHY_WR_CMD		B30_MASK
-#define PHY_RD_CMD		B29_MASK
-#define PHY_RD_ERR		B28_MASK
-#define PHY_PRE_SUP		B27_MASK
-#define PHY_ADDR		0x03E00000	/* 25:21 */
-#define PHY_REG_ADDR		0x001F0000	/* 20:16 */
-#define PHY_DATA		0x0000FFFF	/* 15:0 */
-
-/* LED0..3			0xE0..0xE6, 16bit register */
-#define LEDOUT			B15_MASK
-#define LEDPOL			B14_MASK
-#define LEDDIS			B13_MASK
-#define LEDSTRETCH		B12_MASK
-#define LED1000			B8_MASK
-#define LED100			B7_MASK
-#define LEDMP			B6_MASK
-#define LEDFD			B5_MASK
-#define LEDLINK			B4_MASK
-#define LEDRCVMAT		B3_MASK
-#define LEDXMT			B2_MASK
-#define LEDRCV			B1_MASK
-#define LEDCOLOUT		B0_MASK
-
-/* EEPROM_ACC			0x17C, 16bit register */
-#define PVALID			B15_MASK
-#define PREAD			B14_MASK
-#define EEDET			B13_MASK
-#define	EEN			B4_MASK
-#define ECS			B2_MASK
-#define EESK			B1_MASK
-#define edi_edo			b0_MASK
+typedef enum {
+
+	PHY_CMD_ACTIVE		= (1 << 31),
+	PHY_WR_CMD		= (1 << 30),
+	PHY_RD_CMD		= (1 << 29),
+	PHY_RD_ERR		= (1 << 28),
+	PHY_PRE_SUP		= (1 << 27),
+	PHY_ADDR		= (1 << 21) | (1 << 22) | (1 << 23)|
+				  	(1 << 24) |(1 << 25),/* 25:21 */
+	PHY_REG_ADDR		= (1 << 16) | (1 << 17) | (1 << 18)|	 			  	   	  	(1 << 19) | (1 << 20),/* 20:16 */
+	PHY_DATA		= (0xF << 0)|(0xF << 4) |(0xF << 8)|
+					(0xF << 12),/* 15:0 */
+
+}PHY_ACCESS_BITS;
+
 
 /* PMAT0			0x190,	 32bit register */
-#define PMR_ACTIVE		B31_MASK
-#define PMR_WR_CMD		B30_MASK
-#define PMR_RD_CMD		B29_MASK
-#define PMR_BANK		B28_MASK
-#define PMR_ADDR		0x007F0000	/* 22:16 */
-#define PMR_B4			0x000000FF	/* 15:0 */
+typedef enum {
+	PMR_ACTIVE		= (1 << 31),
+	PMR_WR_CMD		= (1 << 30),
+	PMR_RD_CMD		= (1 << 29),
+	PMR_BANK		= (1 <<28),
+	PMR_ADDR		= (0xF << 16)|(1 << 20)|(1 << 21)|
+				  	(1 << 22),/* 22:16 */
+	PMR_B4			= (0xF << 0) | (0xF << 4),/* 15:0 */
+}PMAT0_BITS;
+
 
 /* PMAT1			0x194,	 32bit register */
-#define PMR_B3			0xFF000000	/* 31:24 */
-#define PMR_B2			0x00FF0000	/* 23:16 */
-#define PMR_B1			0x0000FF00	/* 15:8 */
-#define PMR_B0			0x000000FF	/* 7:0 */
+typedef enum {
+	PMR_B3			= (0xF << 24) | (0xF <<28),/* 31:24 */
+	PMR_B2			= (0xF << 16) |(0xF << 20),/* 23:16 */
+	PMR_B1			= (0xF << 8) | (0xF <<12), /* 15:8 */
+	PMR_B0			= (0xF << 0)|(0xF << 4),/* 7:0 */
+}PMAT1_BITS;
 
 /************************************************************************/
 /*                                                                      */
@@ -615,7 +566,7 @@
 #define	 PCI_VENDOR_ID_AMD		0x1022
 #define  PCI_DEVICE_ID_AMD8111E_7462	0x7462
 
-#define MAX_UNITS			16 /* Maximum number of devices possible */
+#define MAX_UNITS			8 /* Maximum number of devices possible */
 
 #define NUM_TX_BUFFERS			32 /* Number of transmit buffers */
 #define NUM_RX_BUFFERS			32 /* Number of receive buffers */	
@@ -637,45 +588,73 @@
 #define MIN_PKT_LEN			60
 #define ETH_ADDR_LEN			6
 
+#define  AMD8111E_TX_TIMEOUT		(3 * HZ)/* 3 sec */
+#define SOFT_TIMER_FREQ 		0xBEBC  /* 0.5 sec */
+#define DELAY_TIMER_CONV		50    /* msec to 10 usec conversion.
+						 Only 500 usec resolution */ 						 
 #define OPTION_VLAN_ENABLE		0x0001
 #define OPTION_JUMBO_ENABLE		0x0002
 #define OPTION_MULTICAST_ENABLE		0x0004
 #define OPTION_WOL_ENABLE		0x0008
 #define OPTION_WAKE_MAGIC_ENABLE	0x0010
 #define OPTION_WAKE_PHY_ENABLE		0x0020
+#define OPTION_INTR_COAL_ENABLE		0x0040
+#define OPTION_DYN_IPG_ENABLE	        0x0080
 
 #define PHY_REG_ADDR_MASK		0x1f
 
+/* ipg parameters */
+#define DEFAULT_IPG			0x60
+#define IFS1_DELTA			36
+#define	IPG_CONVERGE_TIME 0.5
+#define	IPG_STABLE_TIME	5
+#define	MIN_IPG	96
+#define	MAX_IPG	255
+#define IPG_STEP	16
+#define CSTATE  1 
+#define SSTATE  2 
+
 /* Assume contoller gets data 10 times the maximum processing time */
 #define  REPEAT_CNT			10; 
      
 /* amd8111e decriptor flag definitions */
+typedef enum {
 
-#define OWN_BIT			B15_MASK
-#define ADD_FCS_BIT		B13_MASK
-#define LTINT_BIT		B12_MASK
-#define STP_BIT			B9_MASK
-#define ENP_BIT			B8_MASK
-#define KILL_BIT		B6_MASK
-#define TCC_MASK		0x0003
-#define TCC_VLAN_INSERT		B1_MASK
-#define TCC_VLAN_REPLACE	0x0003
-#define RESET_RX_FLAGS		0x0000
+	OWN_BIT		=	(1 << 15),
+	ADD_FCS_BIT	=	(1 << 13),
+	LTINT_BIT	=	(1 << 12),
+	STP_BIT		=	(1 << 9),
+	ENP_BIT		=	(1 << 8),
+	KILL_BIT	= 	(1 << 6),
+	TCC_VLAN_INSERT	=	(1 << 1),
+	TCC_VLAN_REPLACE =	(1 << 1) |( 1<< 0),
+
+}TX_FLAG_BITS;
+
+typedef enum {
+	ERR_BIT 	=	(1 << 14),
+	FRAM_BIT	=  	(1 << 13),
+	OFLO_BIT	=       (1 << 12),
+	CRC_BIT		=	(1 << 11),
+	PAM_BIT		=	(1 << 6),
+	LAFM_BIT	= 	(1 << 5),
+	BAM_BIT		=	(1 << 4),
+	TT_VLAN_TAGGED	= 	(1 << 3) |(1 << 2),/* 0x000 */
+	TT_PRTY_TAGGED	=	(1 << 3),/* 0x0008 */
+
+}RX_FLAG_BITS;
 
-#define ERR_BIT 		B14_MASK
-#define FRAM_BIT		B13_MASK
-#define OFLO_BIT		B12_MASK
-#define CRC_BIT			B11_MASK
-#define PAM_BIT			B6_MASK
-#define LAFM_BIT		B5_MASK
-#define BAM_BIT			B4_MASK
+#define RESET_RX_FLAGS		0x0000
 #define TT_MASK			0x000c
-#define TT_VLAN_TAGGED		0x000c
-#define TT_PRTY_TAGGED		0x0008
+#define TCC_MASK		0x0003
 
 /* driver ioctl parameters */
 #define PHY_ID 			0x01	/* currently it is fixed */
-#define AMD8111E_REG_DUMP_LEN	4096	/* Memory mapped register length */
+#define AMD8111E_REG_DUMP_LEN	 13*sizeof(u32) 
+
+/* crc generator constants */
+#define CRC32 0xedb88320
+#define INITCRC 0xFFFFFFFF
 
 /* amd8111e desriptor format */
 
@@ -683,7 +662,7 @@
 
 	u16 buff_count; /* Size of the buffer pointed by this descriptor */
 
-	u16 tx_dr_offset2;
+	u16 tx_flags;
 
 	u16 tag_ctrl_info;
 
@@ -704,7 +683,7 @@
 
 	u16 buff_count;  /* Len of the buffer pointed by descriptor. */
 
-	u16 rx_dr_offset10;
+	u16 rx_flags;
 
 	u32 buff_phy_addr;
 
@@ -719,10 +698,58 @@
 	u16				speed;
 	u8				duplex;
 	u8				autoneg;
-	u16 				orig_speed;
-	u8				orig_duplex;
 	u8				reserved;  /* 32bit alignment */
 };
+
+enum coal_type{
+
+	NO_COALESCE,
+	LOW_COALESCE,
+	MEDIUM_COALESCE,
+	HIGH_COALESCE,
+
+};
+
+enum coal_mode{ 
+       	RX_INTR_COAL,
+	TX_INTR_COAL,
+	DISABLE_COAL,
+	ENABLE_COAL,
+
+};
+#define MAX_TIMEOUT	40
+#define MAX_EVENT_COUNT 31
+struct amd8111e_coalesce_conf{
+
+	unsigned int rx_timeout;
+	unsigned int rx_event_count;
+	unsigned long rx_packets;
+	unsigned long rx_prev_packets;
+	unsigned long rx_bytes;
+	unsigned long rx_prev_bytes;
+	unsigned int rx_coal_type;
+	
+	unsigned int tx_timeout;
+	unsigned int tx_event_count;
+	unsigned long tx_packets;
+	unsigned long tx_prev_packets;
+	unsigned long tx_bytes;
+	unsigned long tx_prev_bytes;
+	unsigned int tx_coal_type;
+
+};
+struct ipg_info{
+	
+	unsigned int ipg_state;
+	unsigned int ipg;
+	unsigned int current_ipg;
+	unsigned int col_cnt;
+	unsigned int diff_col_cnt;
+	unsigned int timer_tick;
+	unsigned int prev_ipg;
+	struct timer_list ipg_timer;
+};
+
 struct amd8111e_priv{
 	
 	struct amd8111e_tx_dr*  tx_ring;
@@ -742,45 +769,54 @@
 	void *  mmio;
 	
 	spinlock_t lock;	/* Guard lock */
-	unsigned long  rx_idx, tx_idx;	/* The next free ring entry */
-	unsigned long  tx_complete_idx;
+	unsigned long rx_idx, tx_idx;	/* The next free ring entry */
+	unsigned long tx_complete_idx;
 	unsigned long tx_ring_complete_idx;
 	unsigned long tx_ring_idx;
-	int rx_buff_len;	/* Buffer length of rx buffers */
+	unsigned int rx_buff_len;	/* Buffer length of rx buffers */
 	int options;		/* Options enabled/disabled for the device */
+
 	unsigned long ext_phy_option;
+	
 	struct amd8111e_link_config link_config;
 	int pm_cap;
+	u32 pm_state[12];
 
 	struct net_device *next;
+	int mii;
+	struct mii_if_info mii_if;
 #if AMD8111E_VLAN_TAG_USED
 	struct vlan_group		*vlgrp;
 #endif	
 	char opened;
 	struct net_device_stats stats;
-	struct net_device_stats prev_stats;
 	struct dev_mc_list* mc_list;
+	struct amd8111e_coalesce_conf coal_conf;
+
+	struct ipg_info  ipg_data;	
 	
 };
-#define AMD8111E_READ_REG64(_memMapBase, _offset, _pUlData)	\
-			*(u32*)(_pUlData) = readl(_memMapBase + (_offset));	\
-			*((u32*)(_pUlData))+1) = readl(_memMapBase + ((_offset)+4))
-
-#define AMD8111E_WRITE_REG64(_memMapBase, _offset, _pUlData)	\
-			writel(*(u32*)(_pUlData), _memMapBase + (_offset));	\
-			writel(*(u32*)((u8*)(_pUlData)+4), _memMapBase + ((_offset)+4))	\
+
+/* kernel provided writeq does not write 64 bits into the amd8111e device register instead writes only higher 32bits data into lower 32bits of the register.
+BUG? */
+#define  amd8111e_writeq(_UlData,_memMap)   \
+		writel(*(u32*)(&_UlData), _memMap);	\
+		writel(*(u32*)((u8*)(&_UlData)+4), _memMap+4)	
 
 /* maps the external speed options to internal value */
-static unsigned char speed_duplex_mapping[] = {
+typedef enum {
+	SPEED_AUTONEG,
+	SPEED10_HALF,
+	SPEED10_FULL,
+	SPEED100_HALF,
+	SPEED100_FULL,
+}EXT_PHY_OPTION;
 
-	XPHYANE,		/* Auto-negotiation, speed_duplex option 0 */
-	0,			/* 10M Half,  speed_duplex option 1 */
-	XPHYFD,			/* 10M Full,  speed_duplex option 2 */
-	XPHYSP,			/* 100M Half, speed_duplex option 3 */
-	XPHYFD | XPHYSP		/* 100M Full, speed_duplex option 4 */
-};
 static int card_idx;
 static int speed_duplex[MAX_UNITS] = { 0, };
+static int coalesce[MAX_UNITS] = {1,1,1,1,1,1,1,1};
+static int dynamic_ipg[MAX_UNITS] = {0,0,0,0,0,0,0,0};
+static unsigned int chip_version;
 
 #endif /* _AMD8111E_H */
 
diff -Nru a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
--- a/drivers/net/bonding/bond_3ad.c	Sun May 25 21:26:17 2003
+++ b/drivers/net/bonding/bond_3ad.c	Mon May 26 21:40:16 2003
@@ -721,7 +721,7 @@
 }
 
 /**
- * __detach_bond_to_agg
+ * __detach_bond_from_agg
  * @port: the port we're looking at
  *
  * Handle the detaching of the port's control parser/multiplexer from the
@@ -828,6 +828,55 @@
 	return retval;
 }
 
+/**
+ * __update_lacpdu_from_port - update a port's lacpdu fields
+ * @port: the port we're looking at
+ *
+ */
+static inline void __update_lacpdu_from_port(struct port *port)
+{
+	struct lacpdu *lacpdu = &port->lacpdu;
+
+	/* update current actual Actor parameters */
+	/* lacpdu->subtype                   initialized
+	 * lacpdu->version_number            initialized
+	 * lacpdu->tlv_type_actor_info       initialized
+	 * lacpdu->actor_information_length  initialized
+	 */
+
+	lacpdu->actor_system_priority = port->actor_system_priority;
+	lacpdu->actor_system = port->actor_system;
+	lacpdu->actor_key = port->actor_oper_port_key;
+	lacpdu->actor_port_priority = port->actor_port_priority;
+	lacpdu->actor_port = port->actor_port_number;
+	lacpdu->actor_state = port->actor_oper_port_state;
+
+	/* lacpdu->reserved_3_1              initialized
+	 * lacpdu->tlv_type_partner_info     initialized
+	 * lacpdu->partner_information_length initialized
+	 */
+
+	lacpdu->partner_system_priority = port->partner_oper_system_priority;
+	lacpdu->partner_system = port->partner_oper_system;
+	lacpdu->partner_key = port->partner_oper_key;
+	lacpdu->partner_port_priority = port->partner_oper_port_priority;
+	lacpdu->partner_port = port->partner_oper_port_number;
+	lacpdu->partner_state = port->partner_oper_port_state;
+
+	/* lacpdu->reserved_3_2              initialized
+	 * lacpdu->tlv_type_collector_info   initialized
+	 * lacpdu->collector_information_length initialized
+	 * collector_max_delay                initialized
+	 * reserved_12[12]                   initialized
+	 * tlv_type_terminator               initialized
+	 * terminator_length                 initialized
+	 * reserved_50[50]                   initialized
+	 */
+
+	/* Convert all non u8 parameters to Big Endian for transmit */
+	__ntohs_lacpdu(lacpdu);
+}
+
 //////////////////////////////////////////////////////////////////////////////////////
 // ================= main 802.3ad protocol code ======================================
 //////////////////////////////////////////////////////////////////////////////////////
@@ -1177,43 +1226,11 @@
  */
 static void ad_tx_machine(struct port *port)
 {
-	struct lacpdu *lacpdu = &port->lacpdu;
-
 	// check if tx timer expired, to verify that we do not send more than 3 packets per second
 	if (port->sm_tx_timer_counter && !(--port->sm_tx_timer_counter)) {
 		// check if there is something to send
 		if (port->ntt && (port->sm_vars & AD_PORT_LACP_ENABLED)) {
-			//update current actual Actor parameters
-			//lacpdu->subtype                   initialized
-			//lacpdu->version_number            initialized
-			//lacpdu->tlv_type_actor_info       initialized
-			//lacpdu->actor_information_length  initialized
-			lacpdu->actor_system_priority = port->actor_system_priority;
-			lacpdu->actor_system = port->actor_system;
-			lacpdu->actor_key = port->actor_oper_port_key;
-			lacpdu->actor_port_priority = port->actor_port_priority;
-			lacpdu->actor_port = port->actor_port_number;
-			lacpdu->actor_state = port->actor_oper_port_state;
-			//lacpdu->reserved_3_1              initialized
-			//lacpdu->tlv_type_partner_info     initialized
-			//lacpdu->partner_information_length initialized
-			lacpdu->partner_system_priority = port->partner_oper_system_priority;
-			lacpdu->partner_system = port->partner_oper_system;
-			lacpdu->partner_key = port->partner_oper_key;
-			lacpdu->partner_port_priority = port->partner_oper_port_priority;
-			lacpdu->partner_port = port->partner_oper_port_number;
-			lacpdu->partner_state = port->partner_oper_port_state;
-			//lacpdu->reserved_3_2              initialized
-			//lacpdu->tlv_type_collector_info   initialized
-			//lacpdu->collector_information_length initialized
-			//collector_max_delay                initialized
-			//reserved_12[12]                   initialized
-			//tlv_type_terminator               initialized
-			//terminator_length                 initialized
-			//reserved_50[50]                   initialized
-
-			// We need to convert all non u8 parameters to Big Endian for transmit
-			__ntohs_lacpdu(lacpdu);
+			__update_lacpdu_from_port(port);
 			// send the lacpdu
 			if (ad_lacpdu_send(port) >= 0) {
 				BOND_PRINT_DBG(("Sent LACPDU on port %d", port->actor_port_number));
@@ -1971,13 +1988,13 @@
 		return;
 	}
 
-	// disable the port
-	ad_disable_collecting_distributing(port);
+	BOND_PRINT_DBG(("Unbinding Link Aggregation Group %d", aggregator->aggregator_identifier));
 
-	// deinitialize port's locks if necessary(os-specific)
-	__deinitialize_port_locks(port);
+	/* Tell the partner that this port is not suitable for aggregation */
+	port->actor_oper_port_state &= ~AD_STATE_AGGREGATION;
+	__update_lacpdu_from_port(port);
+	ad_lacpdu_send(port);
 
-	BOND_PRINT_DBG(("Unbinding Link Aggregation Group %d", aggregator->aggregator_identifier));
 	// check if this aggregator is occupied
 	if (aggregator->lag_ports) {
 		// check if there are other ports related to this aggregator except
diff -Nru a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
--- a/drivers/net/bonding/bond_main.c	Sun May 25 21:37:30 2003
+++ b/drivers/net/bonding/bond_main.c	Mon May 26 21:45:02 2003
@@ -2220,7 +2220,7 @@
 					}
 					printk(KERN_INFO
 						"%s: link status definitely down "
-						"for interface %s, disabling it\n",
+						"for interface %s, disabling it",
 						master->name,
 						dev->name);
 
@@ -2994,6 +2994,7 @@
 	struct ifbond *u_binfo = NULL, k_binfo;
 	struct ifslave *u_sinfo = NULL, k_sinfo;
 	struct mii_ioctl_data *mii = NULL;
+	int prev_abi_ver = orig_app_abi_ver;
 	int ret = 0;
 
 #ifdef BONDING_DEBUG
@@ -3112,6 +3113,15 @@
 		}
 		dev_put(slave_dev);
 	}
+
+	if (ret < 0) {
+		/* The ioctl failed, so there's no point in changing the
+		 * orig_app_abi_ver. We'll restore it's value just in case
+		 * we've changed it earlier in this function.
+		 */
+		orig_app_abi_ver = prev_abi_ver;
+	}
+
 	return ret;
 }
 
diff -Nru a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c
--- a/drivers/net/e100/e100_main.c	Thu May  8 20:18:49 2003
+++ b/drivers/net/e100/e100_main.c	Thu May 29 18:07:08 2003
@@ -614,10 +614,6 @@
 		goto err_dealloc;
 	}
 
-	if ((rc = register_netdev(dev)) != 0) {
-		goto err_pci;
-	}
-
 	if (((bdp->pdev->device > 0x1030)
 	       && (bdp->pdev->device < 0x103F))
 	    || ((bdp->pdev->device >= 0x1050)
@@ -641,6 +637,28 @@
 	} else {
 		bdp->rfd_size = 16;
 	}
+
+	dev->vlan_rx_register = e100_vlan_rx_register;
+	dev->vlan_rx_add_vid = e100_vlan_rx_add_vid;
+	dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid;
+	dev->irq = pcid->irq;
+	dev->open = &e100_open;
+	dev->hard_start_xmit = &e100_xmit_frame;
+	dev->stop = &e100_close;
+	dev->change_mtu = &e100_change_mtu;
+	dev->get_stats = &e100_get_stats;
+	dev->set_multicast_list = &e100_set_multi;
+	dev->set_mac_address = &e100_set_mac;
+	dev->do_ioctl = &e100_ioctl;
+
+	if (bdp->flags & USE_IPCB)
+	dev->features = NETIF_F_SG | NETIF_F_HW_CSUM |
+			NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+		
+	if ((rc = register_netdev(dev)) != 0) {
+		goto err_pci;
+	}
+
 	e100_check_options(e100nics, bdp);
 
 	if (!e100_init(bdp)) {
@@ -660,23 +678,6 @@
                 goto err_unregister_netdev;
 	}
 	
-	dev->vlan_rx_register = e100_vlan_rx_register;
-	dev->vlan_rx_add_vid = e100_vlan_rx_add_vid;
-	dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid;
-	dev->irq = pcid->irq;
-	dev->open = &e100_open;
-	dev->hard_start_xmit = &e100_xmit_frame;
-	dev->stop = &e100_close;
-	dev->change_mtu = &e100_change_mtu;
-	dev->get_stats = &e100_get_stats;
-	dev->set_multicast_list = &e100_set_multi;
-	dev->set_mac_address = &e100_set_mac;
-	dev->do_ioctl = &e100_ioctl;
-
-	if (bdp->flags & USE_IPCB)
-	dev->features = NETIF_F_SG | NETIF_F_HW_CSUM |
-			NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-		
 	e100nics++;
 
 	e100_get_speed_duplex_caps(bdp);
diff -Nru a/drivers/net/eepro.c b/drivers/net/eepro.c
--- a/drivers/net/eepro.c	Sun Apr 20 23:39:11 2003
+++ b/drivers/net/eepro.c	Mon May 26 22:13:57 2003
@@ -1715,7 +1715,7 @@
 static int n_eepro;
 /* For linux 2.1.xx */
 
-MODULE_AUTHOR("Pascal Dupuis <dupuis@lei.ucl.ac.be> for the 2.1 stuff (locking,...)");
+MODULE_AUTHOR("Pascal Dupuis, and aris@cathedrallabs.org");
 MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver");
 MODULE_LICENSE("GPL");
 
diff -Nru a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
--- a/drivers/net/hamradio/dmascc.c	Mon May 19 23:22:51 2003
+++ b/drivers/net/hamradio/dmascc.c	Thu May 29 23:50:31 2003
@@ -324,11 +324,8 @@
 
     /* Unregister devices */
     for (i = 0; i < 2; i++) {
-      if (info->dev[i].name) {
-	rtnl_lock();
-	unregister_netdevice(&info->dev[i]);
-	rtnl_unlock();
-      }
+      if (info->dev[i].name)
+	unregister_netdev(&info->dev[i]);
     }
 
     /* Reset board */
diff -Nru a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
--- a/drivers/net/irda/ali-ircc.c	Mon May 12 11:05:59 2003
+++ b/drivers/net/irda/ali-ircc.c	Thu May 29 23:50:31 2003
@@ -390,11 +390,8 @@
         iobase = self->io.fir_base;
 
 	/* Remove netdevice */
-	if (self->netdev) {
-		rtnl_lock();
-		unregister_netdevice(self->netdev);
-		rtnl_unlock();
-	}
+	if (self->netdev)
+		unregister_netdev(self->netdev);
 
 	/* Release the PORT that this driver is using */
 	IRDA_DEBUG(4, "%s(), Releasing Region %03x\n", __FUNCTION__, self->io.fir_base);
diff -Nru a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
--- a/drivers/net/irda/donauboe.c	Mon May 12 11:05:59 2003
+++ b/drivers/net/irda/donauboe.c	Thu May 29 23:50:31 2003
@@ -1579,12 +1579,7 @@
     }
 
   if (self->netdev)
-    {
-      /* Remove netdevice */
-      rtnl_lock ();
-      unregister_netdevice (self->netdev);
-      rtnl_unlock ();
-    }
+      unregister_netdev(self->netdev);
 
   kfree (self->ringbuf);
   self->ringbuf = NULL;
diff -Nru a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
--- a/drivers/net/irda/irda-usb.c	Mon May 19 23:22:52 2003
+++ b/drivers/net/irda/irda-usb.c	Thu May 29 23:50:31 2003
@@ -1231,12 +1231,10 @@
 	ASSERT(self != NULL, return -1;);
 
 	/* Remove netdevice */
-	if (self->netdev) {
-		rtnl_lock();
-		unregister_netdevice(self->netdev);
-		self->netdev = NULL;
-		rtnl_unlock();
-	}
+	if (self->netdev)
+		unregister_netdev(self->netdev);
+	self->netdev = NULL;
+
 	/* Remove the speed buffer */
 	if (self->speed_buff != NULL) {
 		kfree(self->speed_buff);
diff -Nru a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
--- a/drivers/net/irda/irport.c	Tue May 13 06:07:43 2003
+++ b/drivers/net/irda/irport.c	Thu May 29 23:50:31 2003
@@ -267,11 +267,8 @@
 	self->dongle = NULL;
 	
 	/* Remove netdevice */
-	if (self->netdev) {
-		rtnl_lock();
-		unregister_netdevice(self->netdev);
-		rtnl_unlock();
-	}
+	if (self->netdev)
+		unregister_netdev(self->netdev);
 
 	/* Release the IO-port that this driver is using */
 	IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n", 
diff -Nru a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c
--- a/drivers/net/irda/irtty.c	Mon May 19 23:22:52 2003
+++ b/drivers/net/irda/irtty.c	Thu May 29 23:50:31 2003
@@ -282,11 +282,8 @@
 	self->dongle = NULL;
 
 	/* Remove netdevice */
-	if (self->netdev) {
-		rtnl_lock();
-		unregister_netdevice(self->netdev);
-		rtnl_unlock();
-	}
+	if (self->netdev)
+		unregister_netdev(self->netdev);
 	
 	self = hashbin_remove(irtty, (int) self, NULL);
 
diff -Nru a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
--- a/drivers/net/irda/nsc-ircc.c	Mon May 12 11:05:59 2003
+++ b/drivers/net/irda/nsc-ircc.c	Thu May 29 23:50:31 2003
@@ -391,11 +391,8 @@
         iobase = self->io.fir_base;
 
 	/* Remove netdevice */
-	if (self->netdev) {
-		rtnl_lock();
-		unregister_netdevice(self->netdev);
-		rtnl_unlock();
-	}
+	if (self->netdev)
+		unregister_netdev(self->netdev);
 
 	/* Release the PORT that this driver is using */
 	IRDA_DEBUG(4, "%s(), Releasing Region %03x\n", 
diff -Nru a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
--- a/drivers/net/irda/sa1100_ir.c	Tue May 20 20:08:17 2003
+++ b/drivers/net/irda/sa1100_ir.c	Thu May 29 23:50:31 2003
@@ -1122,11 +1122,8 @@
 {
 	struct net_device *dev = dev_get_drvdata(&sa1100ir_device.dev);
 
-	if (dev) {
-		rtnl_lock();
-		unregister_netdevice(dev);
-		rtnl_unlock();
-	}
+	if (dev)
+		unregister_netdev(dev);
 
 	sys_device_unregister(&sa1100ir_device);
 	driver_unregister(&sa1100ir_driver);
diff -Nru a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c
--- a/drivers/net/irda/toshoboe.c	Mon May 19 23:22:52 2003
+++ b/drivers/net/irda/toshoboe.c	Thu May 29 23:50:31 2003
@@ -679,12 +679,8 @@
       self->recv_bufs[i] = NULL;
     }
 
-  if (self->netdev) {
-	  /* Remove netdevice */
-	  rtnl_lock();
-	  unregister_netdevice(self->netdev);
-	  rtnl_unlock();
-  }
+  if (self->netdev)
+	  unregister_netdev(self->netdev);
 
   kfree (self->taskfilebuf);
   self->taskfilebuf = NULL;
diff -Nru a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
--- a/drivers/net/irda/w83977af_ir.c	Mon May 12 11:05:59 2003
+++ b/drivers/net/irda/w83977af_ir.c	Thu May 29 23:50:31 2003
@@ -299,11 +299,8 @@
 #endif /* CONFIG_USE_W977_PNP */
 
 	/* Remove netdevice */
-	if (self->netdev) {
-		rtnl_lock();
-		unregister_netdevice(self->netdev);
-		rtnl_unlock();
-	}
+	if (self->netdev)
+		unregister_netdev(self->netdev);
 
 	/* Release the PORT that this driver is using */
 	IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n", 
diff -Nru a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
--- a/drivers/net/pci-skeleton.c	Tue May 20 20:02:19 2003
+++ b/drivers/net/pci-skeleton.c	Wed May 28 20:51:49 2003
@@ -602,7 +602,7 @@
 	*ioaddr_out = NULL;
 	*dev_out = NULL;
 
-	/* dev zeroed in init_etherdev */
+	/* dev zeroed in alloc_etherdev */
 	dev = alloc_etherdev (sizeof (*tp));
 	if (dev == NULL) {
 		printk (KERN_ERR PFX "unable to alloc new ethernet\n");
@@ -790,7 +790,7 @@
 	dev->irq = pdev->irq;
 	dev->base_addr = (unsigned long) ioaddr;
 
-	/* dev->priv/tp zeroed and aligned in init_etherdev */
+	/* dev->priv/tp zeroed and aligned in alloc_etherdev */
 	tp = dev->priv;
 
 	/* note: tp->chipset set in netdrv_init_board */
diff -Nru a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
--- a/drivers/net/pcmcia/pcnet_cs.c	Sat Apr 26 09:16:22 2003
+++ b/drivers/net/pcmcia/pcnet_cs.c	Sun May 18 13:57:38 2003
@@ -1620,16 +1620,7 @@
 
 static int __init init_pcnet_cs(void)
 {
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "pcnet_cs: Card Services release "
-	       "does not match!\n");
-	return -EINVAL;
-    }
-    pcmcia_register_driver(&pcnet_driver);
-    return 0;
+    return pcmcia_register_driver(&pcnet_driver);
 }
 
 static void __exit exit_pcnet_cs(void)
diff -Nru a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
--- a/drivers/net/pcnet32.c	Tue May 20 20:02:19 2003
+++ b/drivers/net/pcnet32.c	Mon May 26 22:37:07 2003
@@ -1002,7 +1002,9 @@
 	    }
 	    skb_reserve (rx_skbuff, 2);
 	}
-        lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, rx_skbuff->len, PCI_DMA_FROMDEVICE);
+
+	if (lp->rx_dma_addr[i] == NULL) 
+		lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, rx_skbuff->len, PCI_DMA_FROMDEVICE);
 	lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]);
 	lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ);
 	lp->rx_ring[i].status = le16_to_cpu(0x8000);
@@ -1037,7 +1039,7 @@
     /* ReInit Ring */
     lp->a.write_csr (ioaddr, 0, 1);
     i = 0;
-    while (i++ < 100)
+    while (i++ < 1000)
 	if (lp->a.read_csr (ioaddr, 0) & 0x0100)
 	    break;
 
@@ -1128,6 +1130,7 @@
     lp->tx_skbuff[entry] = skb;
     lp->tx_dma_addr[entry] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
     lp->tx_ring[entry].base = (u32)le32_to_cpu(lp->tx_dma_addr[entry]);
+    wmb(); /* Make sure owner changes after all others are visible */
     lp->tx_ring[entry].status = le16_to_cpu(status);
 
     lp->cur_tx++;
diff -Nru a/drivers/net/pppoe.c b/drivers/net/pppoe.c
--- a/drivers/net/pppoe.c	Fri May  2 23:00:55 2003
+++ b/drivers/net/pppoe.c	Thu May 29 23:50:31 2003
@@ -530,7 +530,7 @@
 	if (!sk)
 		return 0;
 
-	if (test_bit(SOCK_DEAD, &sk->flags))
+	if (sock_flag(sk, SOCK_DEAD))
 		return -EBADF;
 
 	pppox_unbind_sock(sk);
@@ -780,7 +780,7 @@
 	struct net_device *dev;
 	char *start;
 
-	if (test_bit(SOCK_DEAD, &sk->flags) || !(sk->state & PPPOX_CONNECTED)) {
+	if (sock_flag(sk, SOCK_DEAD) || !(sk->state & PPPOX_CONNECTED)) {
 		error = -ENOTCONN;
 		goto end;
 	}
@@ -856,7 +856,7 @@
 	int data_len = skb->len;
 	struct sk_buff *skb2;
 
-	if (test_bit(SOCK_DEAD, &sk->flags)  || !(sk->state & PPPOX_CONNECTED))
+	if (sock_flag(sk, SOCK_DEAD)  || !(sk->state & PPPOX_CONNECTED))
 		goto abort;
 
 	hdr.ver	= 1;
@@ -1129,7 +1129,9 @@
 	dev_remove_pack(&pppoes_ptype);
 	dev_remove_pack(&pppoed_ptype);
 	unregister_netdevice_notifier(&pppoe_notifier);
+#ifdef CONFIG_PROC_FS
 	remove_proc_entry("pppoe", proc_net);
+#endif
 }
 
 module_init(pppoe_init);
diff -Nru a/drivers/net/r8169.c b/drivers/net/r8169.c
--- a/drivers/net/r8169.c	Tue May 20 20:02:19 2003
+++ b/drivers/net/r8169.c	Wed May 28 22:07:19 2003
@@ -365,8 +365,8 @@
 	*ioaddr_out = NULL;
 	*dev_out = NULL;
 
-	// dev zeroed in init_etherdev 
-	dev = init_etherdev(NULL, sizeof (*tp));
+	// dev zeroed in alloc_etherdev 
+	dev = alloc_etherdev(sizeof (*tp));
 	if (dev == NULL) {
 		printk(KERN_ERR PFX "unable to alloc new ethernet\n");
 		return -ENOMEM;
@@ -391,18 +391,18 @@
 		printk(KERN_ERR PFX
 		       "region #1 not an MMIO resource, aborting\n");
 		rc = -ENODEV;
-		goto err_out;
+		goto err_out_disable;
 	}
 	// check for weird/broken PCI region reporting
 	if (mmio_len < RTL_MIN_IO_SIZE) {
 		printk(KERN_ERR PFX "Invalid PCI region size(s), aborting\n");
 		rc = -ENODEV;
-		goto err_out;
+		goto err_out_disable;
 	}
 
 	rc = pci_request_regions(pdev, dev->name);
 	if (rc)
-		goto err_out;
+		goto err_out_disable;
 
 	// enable PCI bus-mastering
 	pci_set_master(pdev);
@@ -450,8 +450,10 @@
 err_out_free_res:
 	pci_release_regions(pdev);
 
+err_out_disable:
+	pci_disable_device(pdev);
+
 err_out:
-	unregister_netdev(dev);
 	kfree(dev);
 	return rc;
 }
@@ -464,7 +466,7 @@
 	void *ioaddr = NULL;
 	static int board_idx = -1;
 	static int printed_version = 0;
-	int i;
+	int i, rc;
 	int option = -1, Cap10_100 = 0, Cap1000 = 0;
 
 	assert(pdev != NULL);
@@ -477,20 +479,18 @@
 		printed_version = 1;
 	}
 
-	i = rtl8169_init_board(pdev, &dev, &ioaddr);
-	if (i < 0) {
-		return i;
-	}
+	rc = rtl8169_init_board(pdev, &dev, &ioaddr);
+	if (rc)
+		return rc;
 
 	tp = dev->priv;
 	assert(ioaddr != NULL);
 	assert(dev != NULL);
 	assert(tp != NULL);
 
-	// Get MAC address //
-	for (i = 0; i < MAC_ADDR_LEN; i++) {
+	// Get MAC address.  FIXME: read EEPROM
+	for (i = 0; i < MAC_ADDR_LEN; i++)
 		dev->dev_addr[i] = RTL_R8(MAC0 + i);
-	}
 
 	dev->open = rtl8169_open;
 	dev->hard_start_xmit = rtl8169_start_xmit;
@@ -507,11 +507,20 @@
 	tp->pci_dev = pdev;
 	tp->mmio_addr = ioaddr;
 
+	spin_lock_init(&tp->lock);
+
+	rc = register_netdev(dev);
+	if (rc) {
+		iounmap(ioaddr);
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		kfree(dev);
+		return rc;
+	}
+
 	printk(KERN_DEBUG "%s: Identified chip type is '%s'.\n", dev->name,
 	       rtl_chip_info[tp->chipset].name);
 
-	spin_lock_init(&tp->lock);
-
 	pci_set_drvdata(pdev, dev);
 
 	printk(KERN_INFO "%s: %s at 0x%lx, "
@@ -623,7 +632,7 @@
 rtl8169_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct rtl8169_private *tp = (struct rtl8169_private *) (dev->priv);
+	struct rtl8169_private *tp = dev->priv;
 
 	assert(dev != NULL);
 	assert(tp != NULL);
@@ -636,6 +645,7 @@
 	memset(dev, 0xBC,
 	       sizeof (struct net_device) + sizeof (struct rtl8169_private));
 
+	pci_disable_device(pdev);
 	kfree(dev);
 	pci_set_drvdata(pdev, NULL);
 }
diff -Nru a/drivers/net/setup.c b/drivers/net/setup.c
--- a/drivers/net/setup.c	Fri May 23 00:50:54 2003
+++ b/drivers/net/setup.c	Thu May 29 02:57:13 2003
@@ -13,9 +13,6 @@
 
 extern int scc_enet_init(void); 
 extern int fec_enet_init(void); 
-extern int sdla_setup(void); 
-extern int sdla_c_setup(void); 
-extern int lmc_setup(void);
 
 /*
  *	Devices in this list must do new style probing. That is they must
@@ -36,17 +33,11 @@
 #if defined(CONFIG_DMASCC)
 	{dmascc_init, 0},
 #endif	
-#if defined(CONFIG_SDLA)
-	{sdla_c_setup, 0},
-#endif
 #if defined(CONFIG_SCC_ENET)
         {scc_enet_init, 0},
 #endif
 #if defined(CONFIG_FEC_ENET)
         {fec_enet_init, 0},
-#endif
-#if defined(CONFIG_LANMEDIA)
-	{lmc_setup, 0},
 #endif
 	{NULL, 0},
 };
diff -Nru a/drivers/net/sundance.c b/drivers/net/sundance.c
--- a/drivers/net/sundance.c	Tue May 20 20:02:20 2003
+++ b/drivers/net/sundance.c	Mon May 26 22:05:38 2003
@@ -84,11 +84,14 @@
 	- Fix bug of custom mac address 
 	(StationAddr register only accept word write) 
 
+	Version LK1.09 (D-Link):
+	- Fix the flowctrl bug.	
+	- Set Pause bit in MII ANAR if flow control enabled.	
 */
 
 #define DRV_NAME	"sundance"
-#define DRV_VERSION	"1.01+LK1.08a"
-#define DRV_RELDATE	"23-Apr-2003"
+#define DRV_VERSION	"1.01+LK1.09a"
+#define DRV_RELDATE	"16-May-2003"
 
 
 /* The user-configurable values.
@@ -671,8 +674,8 @@
 				np->an_enable = 1;
 			}
 		}
-		if (flowctrl == 0)
-			np->flowctrl = 0;
+		if (flowctrl == 1)
+			np->flowctrl = 1;
 	}
 
 	/* Fibre PHY? */
@@ -687,6 +690,9 @@
 	/* Reset PHY */
 	mdio_write (dev, np->phys[0], MII_BMCR, BMCR_RESET);
 	mdelay (300);
+	/* If flow control enabled, we need to advertise it.*/
+	if (np->flowctrl)
+		mdio_write (dev, np->phys[0], MII_ADVERTISE, np->mii_if.advertising | 0x0400);
 	mdio_write (dev, np->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART);
 	/* Force media type */
 	if (!np->an_enable) {
@@ -935,7 +941,7 @@
 			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d "
 				   "negotiated capability %4.4x.\n", dev->name,
 				   duplex ? "full" : "half", np->phys[0], negotiated);
-		writew(duplex ? 0x20 : 0, ioaddr + MACCtrl0);
+		writew(readw(ioaddr + MACCtrl0) | duplex ? 0x20 : 0, ioaddr + MACCtrl0);
 	}
 }
 
@@ -1455,9 +1461,12 @@
 				"full" : "half");
 		}
 		check_duplex (dev);
-		if (np->flowctrl == 0)
-			writew(readw(ioaddr + MACCtrl0) & ~EnbFlowCtrl,
+		if (np->flowctrl && np->mii_if.full_duplex) {
+			writew(readw(ioaddr + MulticastFilter1+2) | 0x0200,
+				ioaddr + MulticastFilter1+2);
+			writew(readw(ioaddr + MACCtrl0) | EnbFlowCtrl,
 				ioaddr + MACCtrl0);
+		}
 	}
 	if (intr_status & StatsMax) {
 		get_stats(dev);
@@ -1500,6 +1509,7 @@
 static void set_rx_mode(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
+	struct netdev_private *np = dev->priv;
 	u16 mc_filter[4];			/* Multicast hash filter */
 	u32 rx_mode;
 	int i;
@@ -1532,6 +1542,9 @@
 		writeb(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode);
 		return;
 	}
+	if (np->mii_if.full_duplex && np->flowctrl)
+		mc_filter[3] |= 0x0200;
+
 	for (i = 0; i < 4; i++)
 		writew(mc_filter[i], ioaddr + MulticastFilter0 + i*2);
 	writeb(rx_mode, ioaddr + RxMode);
diff -Nru a/drivers/net/sunqe.c b/drivers/net/sunqe.c
--- a/drivers/net/sunqe.c	Sun May 11 19:48:01 2003
+++ b/drivers/net/sunqe.c	Tue May 27 00:50:01 2003
@@ -124,7 +124,6 @@
 		qb->qe_rxd[i].rx_flags =
 			(RXD_OWN | ((RXD_PKT_SZ) & RXD_LENGTH));
 	}
-	return IRQ_HANDLED;
 }
 
 static int qe_init(struct sunqe *qep, int from_irq)
diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c
--- a/drivers/net/tg3.c	Tue May 20 20:02:20 2003
+++ b/drivers/net/tg3.c	Thu May 29 22:42:44 2003
@@ -6400,8 +6400,7 @@
 	tw32(BUFMGR_MODE, 0);
 	tw32(FTQ_RESET, 0);
 
-	/* pci_alloc_consistent gives only non-DAC addresses */
-	test_desc.addr_hi = 0;
+	test_desc.addr_hi = ((u64) buf_dma) >> 32;
 	test_desc.addr_lo = buf_dma & 0xffffffff;
 	test_desc.nic_mbuf = 0x00002100;
 	test_desc.len = size;
@@ -6743,6 +6742,12 @@
 	/* Configure DMA attributes. */
 	if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) {
 		pci_using_dac = 1;
+		if (pci_set_consistent_dma_mask(pdev,
+						(u64) 0xffffffffffffffff)) {
+			printk(KERN_ERR PFX "Unable to obtain 64 bit DMA "
+			       "for consistent allocations\n");
+			goto err_out_free_res;
+		}
 	} else {
 		err = pci_set_dma_mask(pdev, (u64) 0xffffffff);
 		if (err) {
diff -Nru a/drivers/net/tlan.c b/drivers/net/tlan.c
--- a/drivers/net/tlan.c	Mon Apr 21 17:23:14 2003
+++ b/drivers/net/tlan.c	Thu May 29 09:34:49 2003
@@ -346,6 +346,27 @@
 static int	TLan_EeReadByte( struct net_device *, u8, u8 * );
 
 
+static void 
+TLan_StoreSKB( struct tlan_list_tag *tag, struct sk_buff *skb)
+{
+	unsigned long addr = (unsigned long)skb;
+	tag->buffer[9].address = (u32)addr;
+	addr >>= 31;	/* >>= 32 is undefined for 32bit arch, stupid C */
+	addr >>= 1;
+	tag->buffer[8].address = (u32)addr;
+}
+
+static struct sk_buff *
+TLan_GetSKB( struct tlan_list_tag *tag)
+{
+	unsigned long addr = tag->buffer[8].address;
+	addr <<= 31;
+	addr <<= 1;
+	addr |= tag->buffer[9].address;
+	return (struct sk_buff *) addr;
+}
+
+
 static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = {
 	TLan_HandleInvalid,
 	TLan_HandleTxEOF,
@@ -424,7 +445,7 @@
 		pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage, priv->dmaStorageDMA );
 	}
 
-	release_region( dev->base_addr, 0x10 );
+	pci_release_regions(pdev);
 	
 	kfree( dev );
 		
@@ -510,15 +531,25 @@
 	TLanPrivateInfo    *priv;
 	u8		   pci_rev;
 	u16		   device_id;
-	int		   reg;
+	int		   reg, rc = -ENODEV;
+
+	if (pdev) {
+		rc = pci_enable_device(pdev);
+		if (rc)
+			return rc;
 
-	if (pdev && pci_enable_device(pdev))
-		return -EIO;
+		rc = pci_request_regions(pdev, TLanSignature);
+		if (rc) {
+			printk(KERN_ERR "TLAN: Could not reserve IO regions\n");
+			goto err_out;
+		}
+	}
 
-	dev = init_etherdev(NULL, sizeof(TLanPrivateInfo));
+	dev = alloc_etherdev(sizeof(TLanPrivateInfo));
 	if (dev == NULL) {
 		printk(KERN_ERR "TLAN: Could not allocate memory for device.\n");
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto err_out_regions;
 	}
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
@@ -533,12 +564,10 @@
 
 		priv->adapter = &board_info[ent->driver_data];
 
-		if(pci_set_dma_mask(pdev, 0xFFFFFFFF))
-		{
+		rc = pci_set_dma_mask(pdev, 0xFFFFFFFF);
+		if (rc) {
 			printk(KERN_ERR "TLAN: No suitable PCI mapping available.\n");
-			unregister_netdev(dev);
-			kfree(dev);
-			return -ENODEV;
+			goto err_out_free_dev;
 		}
 
 		pci_read_config_byte ( pdev, PCI_REVISION_ID, &pci_rev);
@@ -553,9 +582,8 @@
 		}
 		if (!pci_io_base) {
 			printk(KERN_ERR "TLAN: No IO mappings available\n");
-			unregister_netdev(dev);
-			kfree(dev);
-			return -ENODEV;
+			rc = -EIO;
+			goto err_out_free_dev;
 		}
 		
 		dev->base_addr = pci_io_base;
@@ -605,12 +633,18 @@
 
 	spin_lock_init(&priv->lock);
 	
-	if (TLan_Init(dev)) {
+	rc = TLan_Init(dev);
+	if (rc) {
+		printk(KERN_ERR "TLAN: Could not set up device.\n");
+		goto err_out_free_dev;
+	}
+
+	rc = register_netdev(dev);
+	if (rc) {
 		printk(KERN_ERR "TLAN: Could not register device.\n");
-		unregister_netdev(dev);
-		kfree(dev);
-		return -EAGAIN;
-	} else {
+		goto err_out_uninit;
+	}
+
 	
 	TLanDevicesInstalled++;
 	boards_found++;
@@ -631,8 +665,19 @@
 			priv->adapter->deviceLabel,
 			priv->adapterRev);
 	return 0;
-	}
 
+err_out_uninit:
+	pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage,
+			    priv->dmaStorageDMA );
+err_out_free_dev:
+	kfree(dev);
+err_out_regions:
+	if (pdev)
+		pci_release_regions(pdev);
+err_out:
+	if (pdev)
+		pci_disable_device(pdev);
+	return rc;
 }
 
 
@@ -798,15 +843,6 @@
 
 	priv = dev->priv;
 	
-	if (!priv->is_eisa)	/* EISA devices have already requested IO */
-		if (!request_region( dev->base_addr, 0x10, TLanSignature )) {
-			printk(KERN_ERR "TLAN: %s: IO port region 0x%lx size 0x%x in use.\n",
-				dev->name,
-				dev->base_addr,
-				0x10 );
-			return -EIO;
-		}
-	
 	if ( bbuf ) {
 		dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
 	           * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE );
@@ -820,7 +856,6 @@
 	if ( priv->dmaStorage == NULL ) {
 		printk(KERN_ERR "TLAN:  Could not allocate lists and buffers for %s.\n",
 			dev->name );
-		release_region( dev->base_addr, 0x10 );
 		return -ENOMEM;
 	}
 	memset( priv->dmaStorage, 0, dma_size );
@@ -1039,7 +1074,7 @@
 		memcpy( tail_buffer, skb->data, skb->len );
 	} else {
 		tail_list->buffer[0].address = pci_map_single(priv->pciDev, skb->data, skb->len, PCI_DMA_TODEVICE);
-		tail_list->buffer[9].address = (u32) skb;
+		TLan_StoreSKB(tail_list, skb);
 	}
 
 	pad = TLAN_MIN_FRAME_SIZE - skb->len;
@@ -1365,9 +1400,10 @@
 	while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) {
 		ack++;
 		if ( ! bbuf ) {
-			struct sk_buff *skb = (struct sk_buff *) head_list->buffer[9].address;
+			struct sk_buff *skb = TLan_GetSKB(head_list);
 			pci_unmap_single(priv->pciDev, head_list->buffer[0].address, skb->len, PCI_DMA_TODEVICE);
 			dev_kfree_skb_any(skb);
+			head_list->buffer[8].address = 0;
 			head_list->buffer[9].address = 0;
 		}
 	
@@ -1523,7 +1559,7 @@
 			new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );
 			
 			if ( new_skb != NULL ) {
-				skb = (struct sk_buff *) head_list->buffer[9].address;
+				skb = TLan_GetSKB(head_list);
 				pci_unmap_single(priv->pciDev, head_list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
 				skb_trim( skb, frameSize );
 
@@ -1537,10 +1573,7 @@
 				t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE );
 				head_list->buffer[0].address = pci_map_single(priv->pciDev, new_skb->data, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
 				head_list->buffer[8].address = (u32) t;
-#if BITS_PER_LONG==64
-#error "Not 64bit clean"
-#endif				
-				head_list->buffer[9].address = (u32) new_skb;
+				TLan_StoreSKB(head_list, new_skb);
 			} else 
 				printk(KERN_WARNING "TLAN:  Couldn't allocate memory for received data.\n" );
 		}
@@ -1926,6 +1959,7 @@
 		}
 		list->buffer[2].count = 0;
 		list->buffer[2].address = 0;
+		list->buffer[8].address = 0;
 		list->buffer[9].address = 0;
 	}
 
@@ -1951,7 +1985,7 @@
 			}
 			list->buffer[0].address = pci_map_single(priv->pciDev, t, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
 			list->buffer[8].address = (u32) t;
-			list->buffer[9].address = (u32) skb;
+			TLan_StoreSKB(list, skb);
 		}
 		list->buffer[1].count = 0;
 		list->buffer[1].address = 0;
@@ -1974,20 +2008,22 @@
 	if ( ! bbuf ) {
 		for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) {
 			list = priv->txList + i;
-			skb = (struct sk_buff *) list->buffer[9].address;
+			skb = TLan_GetSKB(list);
 			if ( skb ) {
 				pci_unmap_single(priv->pciDev, list->buffer[0].address, skb->len, PCI_DMA_TODEVICE);
 				dev_kfree_skb_any( skb );
+				list->buffer[8].address = 0;
 				list->buffer[9].address = 0;
 			}
 		}
 
 		for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) {
 			list = priv->rxList + i;
-			skb = (struct sk_buff *) list->buffer[9].address;
+			skb = TLan_GetSKB(list);
 			if ( skb ) {
 				pci_unmap_single(priv->pciDev, list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
 				dev_kfree_skb_any( skb );
+				list->buffer[8].address = 0;
 				list->buffer[9].address = 0;
 			}
 		}
diff -Nru a/drivers/net/wan/lmc/lmc_debug.c b/drivers/net/wan/lmc/lmc_debug.c
--- a/drivers/net/wan/lmc/lmc_debug.c	Thu Nov 21 14:45:10 2002
+++ b/drivers/net/wan/lmc/lmc_debug.c	Mon May 26 22:01:35 2003
@@ -2,9 +2,7 @@
 #include <linux/types.h>
 #include <linux/netdevice.h>
 #include <linux/interrupt.h>
-#include <linux/version.h>
 
-#include "lmc_ver.h"
 #include "lmc_debug.h"
 
 /*
diff -Nru a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
--- a/drivers/net/wan/lmc/lmc_main.c	Sun May 11 19:48:01 2003
+++ b/drivers/net/wan/lmc/lmc_main.c	Mon May 26 23:59:35 2003
@@ -11,7 +11,7 @@
   * With Help By:
   * David Boggs
   * Ron Crane
-  * Allan Cox
+  * Alan Cox
   *
   * This software may be used and distributed according to the terms
   * of the GNU General Public License version 2, incorporated herein by reference.
@@ -38,7 +38,6 @@
 
 /* $Id: lmc_main.c,v 1.36 2000/04/11 05:25:25 asj Exp $ */
 
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/string.h>
@@ -51,9 +50,6 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/init.h>
-#if LINUX_VERSION_CODE < 0x20155
-#include <linux/bios32.h>
-#endif
 #include <linux/in.h>
 #include <linux/if_arp.h>
 #include <linux/netdevice.h>
@@ -67,12 +63,8 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
-#if LINUX_VERSION_CODE >= 0x20200
 #include <asm/uaccess.h>
 //#include <asm/spinlock.h>
-#else				/* 2.0 kernel */
-#define ARPHRD_HDLC 513
-#endif
 
 #define DRIVER_MAJOR_VERSION     1
 #define DRIVER_MINOR_VERSION    34
@@ -80,7 +72,6 @@
 
 #define DRIVER_VERSION  ((DRIVER_MAJOR_VERSION << 8) + DRIVER_MINOR_VERSION)
 
-#include "lmc_ver.h"
 #include "lmc.h"
 #include "lmc_var.h"
 #include "lmc_ioctl.h"
@@ -127,10 +118,8 @@
 static int lmc_init(struct net_device * const);
 static void lmc_reset(lmc_softc_t * const sc);
 static void lmc_dec_reset(lmc_softc_t * const sc);
-#if LINUX_VERSION_CODE >= 0x20363
 static void lmc_driver_timeout(struct net_device *dev);
 int lmc_setup(void);
-#endif
 
 
 /*
@@ -165,7 +154,8 @@
          * To date internally, just copy this out to the user.
          */
     case LMCIOCGINFO: /*fold01*/
-        LMC_COPY_TO_USER(ifr->ifr_data, &sc->ictl, sizeof (lmc_ctl_t));
+        if (copy_to_user(ifr->ifr_data, &sc->ictl, sizeof (lmc_ctl_t)))
+            return -EFAULT;
         ret = 0;
         break;
 
@@ -181,7 +171,8 @@
             break;
         }
 
-        LMC_COPY_FROM_USER(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t));
+        if (copy_from_user(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t)))
+            return -EFAULT;
 
         sc->lmc_media->set_status (sc, &ctl);
 
@@ -211,7 +202,8 @@
 		break;
 	    }
 
-	    LMC_COPY_FROM_USER(&new_type, ifr->ifr_data, sizeof(u_int16_t));
+	    if (copy_from_user(&new_type, ifr->ifr_data, sizeof(u_int16_t)))
+                return -EFAULT;
 
             
 	    if (new_type == old_type)
@@ -248,8 +240,9 @@
 
         sc->lmc_xinfo.Magic1 = 0xDEADBEEF;
 
-        LMC_COPY_TO_USER(ifr->ifr_data, &sc->lmc_xinfo,
-                         sizeof (struct lmc_xinfo));
+        if (copy_to_user(ifr->ifr_data, &sc->lmc_xinfo,
+                         sizeof (struct lmc_xinfo)))
+            return -EFAULT;
         ret = 0;
 
         break;
@@ -279,8 +272,9 @@
                 regVal & T1FRAMER_SEF_MASK;
         }
 
-        LMC_COPY_TO_USER(ifr->ifr_data, &sc->stats,
-                         sizeof (struct lmc_statistics));
+        if (copy_to_user(ifr->ifr_data, &sc->stats,
+                         sizeof (struct lmc_statistics)))
+            return -EFAULT;
 
         ret = 0;
         break;
@@ -310,7 +304,8 @@
             break;
         }
 
-        LMC_COPY_FROM_USER(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t));
+        if (copy_from_user(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t)))
+            return -EFAULT;
         sc->lmc_media->set_circuit_type(sc, ctl.circuit_type);
         sc->ictl.circuit_type = ctl.circuit_type;
         ret = 0;
@@ -335,8 +330,10 @@
 
 #ifdef DEBUG
     case LMCIOCDUMPEVENTLOG:
-        LMC_COPY_TO_USER(ifr->ifr_data, &lmcEventLogIndex, sizeof (u32));
-        LMC_COPY_TO_USER(ifr->ifr_data + sizeof (u32), lmcEventLogBuf, sizeof (lmcEventLogBuf));
+        if (copy_to_user(ifr->ifr_data, &lmcEventLogIndex, sizeof (u32)))
+            return -EFAULT;
+        if (copy_to_user(ifr->ifr_data + sizeof (u32), lmcEventLogBuf, sizeof (lmcEventLogBuf)))
+            return -EFAULT;
 
         ret = 0;
         break;
@@ -359,9 +356,10 @@
             /*
              * Stop the xwitter whlie we restart the hardware
              */
-            LMC_XMITTER_BUSY(dev);
+            netif_stop_queue(dev);
 
-            LMC_COPY_FROM_USER(&xc, ifr->ifr_data, sizeof (struct lmc_xilinx_control));
+            if (copy_from_user(&xc, ifr->ifr_data, sizeof (struct lmc_xilinx_control)))
+                return -EFAULT;
             switch(xc.command){
             case lmc_xilinx_reset: /*fold02*/
                 {
@@ -620,7 +618,7 @@
                 break;
             }
 
-            LMC_XMITTER_FREE(dev);
+            netif_wake_queue(dev);
             sc->lmc_txfull = 0;
 
         }
@@ -646,7 +644,7 @@
     lmc_softc_t *sc;
     int link_status;
     u_int32_t ticks;
-    LMC_SPIN_FLAGS;
+    unsigned long flags;
 
     sc = dev->priv;
 
@@ -836,11 +834,7 @@
      * Allocate our own device structure
      */
 
-#if LINUX_VERSION_CODE < 0x20363
-    dev = kmalloc (sizeof (struct ppp_device)+8, GFP_KERNEL);
-#else
     dev = kmalloc (sizeof (struct net_device)+8, GFP_KERNEL);
-#endif
     if (dev == NULL){
         printk (KERN_ERR "lmc: kmalloc for device failed\n");
         return NULL;
@@ -909,10 +903,8 @@
     dev->get_stats = lmc_get_stats;
     dev->do_ioctl = lmc_ioctl;
     dev->set_config = lmc_set_config;
-#if LINUX_VERSION_CODE >= 0x20363
     dev->tx_timeout = lmc_driver_timeout;
     dev->watchdog_timeo = (HZ); /* 1 second */
-#endif
     
     /*
      * Why were we changing this???
@@ -923,8 +915,6 @@
 
     spin_lock_init(&sc->lmc_lock);
 
-    LMC_SETUP_20_DEV;
-
     printk ("%s: detected at %lx, irq %d\n", dev->name, ioaddr, dev->irq);
 
     if (register_netdev (dev) != 0) {
@@ -1048,7 +1038,7 @@
      * PCI bus, we are in trouble.
      */
 
-    if (!LMC_PCI_PRESENT()) {
+    if (!pci_present()) {
 /*        printk ("%s: We really want a pci bios!\n", dev->name);*/
         return -1;
     }
@@ -1124,11 +1114,7 @@
     if (cards_found < 1)
         return -1;
 
-#if LINUX_VERSION_CODE >= 0x20200
     return foundaddr;
-#else
-    return 0;
-#endif
 }
 
 /* After this is called, packets can be sent.
@@ -1199,11 +1185,7 @@
     dev->do_ioctl = lmc_ioctl;
 
 
-    LMC_XMITTER_INIT(dev);
-    
-#if LINUX_VERSION_CODE < 0x20363
-    dev->start = 1;
-#endif
+    netif_start_queue(dev);
     
     sc->stats.tx_tbusy0++ ;
 
@@ -1277,7 +1259,7 @@
 
     //dev->flags |= IFF_RUNNING;
     
-    LMC_XMITTER_FREE(dev);
+    netif_wake_queue(dev);
 
     sc->lmc_txfull = 0;
     sc->stats.tx_tbusy0++ ;
@@ -1327,7 +1309,7 @@
     
     /* Don't let anything else go on right now */
     //    dev->start = 0;
-    LMC_XMITTER_BUSY(dev);
+    netif_stop_queue(dev);
     sc->stats.tx_tbusy1++ ;
 
     /* stop interrupts */
@@ -1360,23 +1342,20 @@
         sc->lmc_rxring[i].length = 0;
         sc->lmc_rxring[i].buffer1 = 0xDEADBEEF;
         if (skb != NULL)
-        {
-            LMC_SKB_FREE(skb, 1);
-            LMC_DEV_KFREE_SKB (skb);
-        }
+            dev_kfree_skb(skb);
         sc->lmc_rxq[i] = NULL;
     }
 
     for (i = 0; i < LMC_TXDESCS; i++)
     {
         if (sc->lmc_txq[i] != NULL)
-            LMC_DEV_KFREE_SKB (sc->lmc_txq[i]);
+            dev_kfree_skb(sc->lmc_txq[i]);
         sc->lmc_txq[i] = NULL;
     }
 
     lmc_led_off (sc, LMC_MII16_LED_ALL);
 
-    LMC_XMITTER_FREE(dev);
+    netif_wake_queue(dev);
     sc->stats.tx_tbusy0++ ;
 
     lmc_trace(dev, "lmc_ifdown out");
@@ -1496,14 +1475,12 @@
                 }
                 else {
                     
-#if LINUX_VERSION_CODE >= 0x20200
                     sc->stats.tx_bytes += sc->lmc_txring[i].length & 0x7ff;
-#endif
                     
                     sc->stats.tx_packets++;
                 }
                 
-                //                LMC_DEV_KFREE_SKB (sc->lmc_txq[i]);
+                //                dev_kfree_skb(sc->lmc_txq[i]);
                 dev_kfree_skb_irq(sc->lmc_txq[i]);
                 sc->lmc_txq[i] = 0;
 
@@ -1518,20 +1495,14 @@
             }
             LMC_EVENT_LOG(LMC_EVENT_TBUSY0, n_compl, 0);
             sc->lmc_txfull = 0;
-            LMC_XMITTER_FREE(dev);
+            netif_wake_queue(dev);
             sc->stats.tx_tbusy0++ ;
-#if LINUX_VERSION_CODE < 0x20363
-            mark_bh (NET_BH);	/* Tell Linux to give me more packets */
-#endif
 
 
 #ifdef DEBUG
             sc->stats.dirtyTx = badtx;
             sc->stats.lmc_next_tx = sc->lmc_next_tx;
             sc->stats.lmc_txfull = sc->lmc_txfull;
-#if LINUX_VERSION_CODE < 0x20363
-            sc->stats.tbusy = dev->tbusy;
-#endif
 #endif
             sc->lmc_taint_tx = badtx;
 
@@ -1592,7 +1563,7 @@
     u32 flag;
     int entry;
     int ret = 0;
-    LMC_SPIN_FLAGS;
+    unsigned long flags;
 
     lmc_trace(dev, "lmc_start_xmit in");
 
@@ -1600,60 +1571,6 @@
 
     spin_lock_irqsave(&sc->lmc_lock, flags);
 
-    /*
-     * If the transmitter is busy
-     * this must be the 5 second polling
-     * from the kernel which called us.
-     * Poke the chip and try to get it running
-     *
-     */
-#if LINUX_VERSION_CODE < 0x20363
-    if(dev->tbusy != 0){
-        u32 csr6;
-
-        printk("%s: Xmitter busy|\n", dev->name);
-
-	sc->stats.tx_tbusy_calls++ ;
-        if (jiffies - dev->trans_start < TX_TIMEOUT) {
-            ret = 1;
-            goto lmc_start_xmit_bug_out;
-        }
-
-        /*
-         * Chip seems to have locked up
-         * Reset it
-         * This whips out all our decriptor
-         * table and starts from scartch
-         */
-
-        LMC_EVENT_LOG(LMC_EVENT_XMTPRCTMO,
-                      LMC_CSR_READ (sc, csr_status),
-                      sc->stats.tx_ProcTimeout);
-
-        lmc_running_reset (dev);
-
-        LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0);
-        LMC_EVENT_LOG(LMC_EVENT_RESET2,
-                      lmc_mii_readreg (sc, 0, 16),
-                      lmc_mii_readreg (sc, 0, 17));
-
-        /* restart the tx processes */
-        csr6 = LMC_CSR_READ (sc, csr_command);
-        LMC_CSR_WRITE (sc, csr_command, csr6 | 0x0002);
-        LMC_CSR_WRITE (sc, csr_command, csr6 | 0x2002);
-
-        /* immediate transmit */
-        LMC_CSR_WRITE (sc, csr_txpoll, 0);
-
-        sc->stats.tx_errors++;
-        sc->stats.tx_ProcTimeout++;	/* -baz */
-
-        dev->trans_start = jiffies;
-
-        ret = 1;
-        goto lmc_start_xmit_bug_out;
-    }
-#endif
     /* normal path, tbusy known to be zero */
 
     entry = sc->lmc_next_tx % LMC_TXDESCS;
@@ -1669,26 +1586,26 @@
     {
         /* Do not interrupt on completion of this packet */
         flag = 0x60000000;
-        LMC_XMITTER_FREE(dev);
+        netif_wake_queue(dev);
     }
     else if (sc->lmc_next_tx - sc->lmc_taint_tx == LMC_TXDESCS / 2)
     {
         /* This generates an interrupt on completion of this packet */
         flag = 0xe0000000;
-        LMC_XMITTER_FREE(dev);
+        netif_wake_queue(dev);
     }
     else if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS - 1)
     {
         /* Do not interrupt on completion of this packet */
         flag = 0x60000000;
-        LMC_XMITTER_FREE(dev);
+        netif_wake_queue(dev);
     }
     else
     {
         /* This generates an interrupt on completion of this packet */
         flag = 0xe0000000;
         sc->lmc_txfull = 1;
-        LMC_XMITTER_BUSY(dev);
+        netif_stop_queue(dev);
     }
 #else
     flag = LMC_TDES_INTERRUPT_ON_COMPLETION;
@@ -1696,7 +1613,7 @@
     if (sc->lmc_next_tx - sc->lmc_taint_tx >= LMC_TXDESCS - 1)
     {				/* ring full, go busy */
         sc->lmc_txfull = 1;
-        LMC_XMITTER_BUSY(dev);
+        netif_stop_queue(dev);
         sc->stats.tx_tbusy1++ ;
         LMC_EVENT_LOG(LMC_EVENT_TBUSY1, entry, 0);
     }
@@ -1726,10 +1643,6 @@
 
     dev->trans_start = jiffies;
 
-#if LINUX_VERSION_CODE < 0x20363
-lmc_start_xmit_bug_out:
-#endif
-
     spin_unlock_irqrestore(&sc->lmc_lock, flags);
 
     lmc_trace(dev, "lmc_start_xmit_out");
@@ -1815,7 +1728,6 @@
         if(skb == 0x0){
             nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
             if (nsb) {
-                LMC_SKB_FREE(nsb, 1);
                 sc->lmc_rxq[i] = nsb;
                 nsb->dev = dev;
                 sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail);
@@ -1859,7 +1771,6 @@
              */
             nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2);
             if (nsb) {
-                LMC_SKB_FREE(nsb, 1);
                 sc->lmc_rxq[i] = nsb;
                 nsb->dev = dev;
                 sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail);
@@ -1948,7 +1859,7 @@
 static struct net_device_stats *lmc_get_stats (struct net_device *dev) /*fold00*/
 {
     lmc_softc_t *sc;
-    LMC_SPIN_FLAGS;
+    unsigned long flags;
 
     lmc_trace(dev, "lmc_get_stats in");
 
@@ -1965,9 +1876,7 @@
     return (struct net_device_stats *) &sc->stats;
 }
 
-#ifdef MODULE
-
-int init_module (void) /*fold00*/
+static int __init init_lmc(void)
 {
     printk ("lmc: module loaded\n");
 
@@ -1978,7 +1887,7 @@
     return 0;
 }
 
-void cleanup_module (void) /*fold00*/
+static void __exit exit_lmc(void)
 {
     struct net_device *dev, *next;
     lmc_softc_t *sc;
@@ -2020,7 +1929,9 @@
     Lmc_root_dev = NULL;
     printk ("lmc module unloaded\n");
 }
-#endif
+
+module_init(init_lmc);
+module_exit(exit_lmc);
 
 unsigned lmc_mii_readreg (lmc_softc_t * const sc, unsigned devaddr, unsigned regno) /*fold00*/
 {
@@ -2148,7 +2059,6 @@
         }
 
         skb->dev = sc->lmc_device;
-        LMC_SKB_FREE(skb, 1);
 
         /* owned by 21140 */
         sc->lmc_rxring[i].status = 0x80000000;
@@ -2367,11 +2277,10 @@
     lmc_trace(sc->lmc_device, "lmc_initcsrs out");
 }
 
-#if LINUX_VERSION_CODE >= 0x20363
 static void lmc_driver_timeout(struct net_device *dev) { /*fold00*/
     lmc_softc_t *sc;
     u32 csr6;
-    LMC_SPIN_FLAGS;
+    unsigned long flags;
 
     lmc_trace(dev, "lmc_driver_timeout in");
 
@@ -2430,4 +2339,3 @@
    return lmc_probe(NULL);
 }
 
-#endif
diff -Nru a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c
--- a/drivers/net/wan/lmc/lmc_media.c	Thu Nov 21 14:45:10 2002
+++ b/drivers/net/wan/lmc/lmc_media.c	Mon May 26 22:01:35 2003
@@ -1,6 +1,5 @@
 /* $Id: lmc_media.c,v 1.13 2000/04/11 05:25:26 asj Exp $ */
 
-#include <linux/version.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -11,9 +10,6 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-#if LINUX_VERSION_CODE < 0x20155
-#include <linux/bios32.h>
-#endif
 #include <linux/in.h>
 #include <linux/if_arp.h>
 #include <linux/netdevice.h>
@@ -28,11 +24,8 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 
-#if LINUX_VERSION_CODE >= 0x20200
 #include <asm/uaccess.h>
-#endif
 
-#include "lmc_ver.h"
 #include "lmc.h"
 #include "lmc_var.h"
 #include "lmc_ioctl.h"
diff -Nru a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c
--- a/drivers/net/wan/lmc/lmc_proto.c	Wed Nov 27 11:25:40 2002
+++ b/drivers/net/wan/lmc/lmc_proto.c	Mon May 26 22:01:35 2003
@@ -19,7 +19,6 @@
   * Driver for the LanMedia LMC5200, LMC5245, LMC1000, LMC1200 cards.
   */
 
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/timer.h>
@@ -46,7 +45,6 @@
 #include <asm/dma.h>
 #include <asm/smp.h>
 
-#include "lmc_ver.h"
 #include "lmc.h"
 #include "lmc_var.h"
 #include "lmc_debug.h"
@@ -66,14 +64,6 @@
 #define SPPP_attach(d)	(void)0
 #define SPPP_do_ioctl(d,i,c)	-EOPNOTSUPP
 #else
-#if LINUX_VERSION_CODE < 0x20363
-#define SPPP_attach(x)	sppp_attach((struct ppp_device *)(x)->lmc_device)
-#define SPPP_detach(x)	sppp_detach((x)->lmc_device)
-#define SPPP_open(x)	sppp_open((x)->lmc_device)
-#define SPPP_reopen(x)	sppp_reopen((x)->lmc_device)
-#define SPPP_close(x)	sppp_close((x)->lmc_device)
-#define SPPP_do_ioctl(x, y, z)	sppp_do_ioctl((x)->lmc_device, (y), (z))
-#else
 #define SPPP_attach(x)	sppp_attach((x)->pd)
 #define SPPP_detach(x)	sppp_detach((x)->pd->dev)
 #define SPPP_open(x)	sppp_open((x)->pd->dev)
@@ -81,7 +71,6 @@
 #define SPPP_close(x)	sppp_close((x)->pd->dev)
 #define SPPP_do_ioctl(x, y, z)	sppp_do_ioctl((x)->pd->dev, (y), (z))
 #endif
-#endif
 
 // init
 void lmc_proto_init(lmc_softc_t *sc) /*FOLD00*/
@@ -89,15 +78,12 @@
     lmc_trace(sc->lmc_device, "lmc_proto_init in");
     switch(sc->if_type){
     case LMC_PPP:
-        
-#if LINUX_VERSION_CODE >= 0x20363
         sc->pd = kmalloc(sizeof(struct ppp_device), GFP_KERNEL);
 	if (!sc->pd) {
 		printk("lmc_proto_init(): kmalloc failure!\n");
 		return;
 	}
         sc->pd->dev = sc->lmc_device;
-#endif
         sc->if_ptr = sc->pd;
         break;
     case LMC_RAW:
diff -Nru a/drivers/net/wan/lmc/lmc_var.h b/drivers/net/wan/lmc/lmc_var.h
--- a/drivers/net/wan/lmc/lmc_var.h	Sun Sep 29 15:26:50 2002
+++ b/drivers/net/wan/lmc/lmc_var.h	Mon May 26 22:01:35 2003
@@ -48,9 +48,6 @@
 #define u_int16_t	u16
 #define u_int8_t	u8
 #define tulip_uint32_t	u32
-#if LINUX_VERSION_CODE < 0x20155
-#define u_int32_t	u32
-#endif
 
 #define LMC_REG_RANGE 0x80
 
@@ -410,9 +407,7 @@
         u32                     last_int;
         u32                     num_int;
 
-#if LINUX_VERSION_CODE >= 0x20200
 	spinlock_t              lmc_lock;
-#endif
         u_int16_t               if_type;       /* PPP or NET */
         struct ppp_device       *pd;
 
@@ -549,10 +544,6 @@
 
 #define LMC_CRC_LEN_16 2  /* 16-bit CRC */
 #define LMC_CRC_LEN_32 4
-
-#if LINUX_VERSION_CODE < 0x20100
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-#endif
 
 #ifdef LMC_HDLC
 /* definition of an hdlc header. */
diff -Nru a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c
--- a/drivers/net/wan/pc300_tty.c	Mon Apr 21 20:58:42 2003
+++ b/drivers/net/wan/pc300_tty.c	Mon May 26 15:29:13 2003
@@ -113,7 +113,7 @@
 static struct tty_struct *cpc_tty_serial_table[CPC_TTY_NPORTS];
 static struct termios *cpc_tty_serial_termios[CPC_TTY_NPORTS];
 static struct termios *cpc_tty_serial_termios_locked[CPC_TTY_NPORTS];
-static struct tty_driver serial_drv, callout_drv;
+static struct tty_driver serial_drv;
 
 /* local variables */
 st_cpc_tty_area	cpc_tty_area[CPC_TTY_NPORTS];
@@ -244,15 +244,6 @@
 		serial_drv.flush_buffer = cpc_tty_flush_buffer; 
 		serial_drv.hangup = cpc_tty_hangup;
 
-		/* the callout device is just like normal device except for major */
-	   	/* number and the subtype code */ 
-		callout_drv = serial_drv; 
-		callout_drv.name = "cucp"; 
-		callout_drv.major = CPC_TTY_MAJOR + 1;
-		callout_drv.subtype = SERIAL_TYPE_CALLOUT;
-		callout_drv.read_proc = 0;
-		callout_drv.proc_entry = 0; 
-		
 		/* register the TTY driver */
 		if (tty_register_driver(&serial_drv)) { 
 			printk("%s-tty: Failed to register serial driver! ",
@@ -260,11 +251,6 @@
 		   	return;
 		} 
 
-		if (tty_register_driver(&callout_drv)) {
-			CPC_TTY_DBG("%s-tty: Failed to register callout driver! ",
-				((struct net_device*)(pc300dev->hdlc))->name);
-			return;
-		}
 		memset((void *)cpc_tty_area, 0,
 								sizeof(st_cpc_tty_area) * CPC_TTY_NPORTS);
 	}
@@ -436,10 +422,6 @@
 			CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",
 							cpc_tty->name,res);
 		}
-		if ((res=tty_unregister_driver(&callout_drv))) { 
-			CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",
-							cpc_tty->name,res);
-		}
 	}
 	return; 
 } 
@@ -688,10 +670,6 @@
 			CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",
 							cpc_tty->name,res);
 		}
-		if ((res=tty_unregister_driver(&callout_drv))) { 
-			CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",
-							cpc_tty->name,res);
-		}
 	}
 	cpc_tty_dtr_off(cpc_tty->pc300dev);
 }
@@ -1092,10 +1070,6 @@
 				CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",
 								cpc_tty->name,res);
 			}
-			if ((res=tty_unregister_driver(&callout_drv))) { 
-				CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n",
-								cpc_tty->name,res);
-			}
 		}
 	}
 	CPC_TTY_LOCK(pc300dev->chan->card,flags);
@@ -1130,7 +1104,6 @@
 	CPC_TTY_DBG("hdlcX-tty: reset variables\n");
 	/* reset  the tty_driver structure - serial_drv */ 
 	memset(&serial_drv, 0, sizeof(struct tty_driver));
-	memset(&callout_drv, 0, sizeof(struct tty_driver));
 	for (i=0; i < CPC_TTY_NPORTS; i++){
 		memset(&cpc_tty_area[i],0, sizeof(st_cpc_tty_area)); 
 	}
diff -Nru a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
--- a/drivers/net/wan/sdla.c	Sun May 18 08:18:07 2003
+++ b/drivers/net/wan/sdla.c	Thu May 29 02:57:13 2003
@@ -1667,20 +1667,20 @@
 	.name = "sdla0",
 	.init = sdla_init
 };
+#endif /* MODULE */
 
-MODULE_LICENSE("GPL");
-
-int init_module(void)
+static int __init init_sdla(void)
 {
-	int result;
+	int result = 0;
 
 	sdla_c_setup();
-	if ((result = register_netdev(&sdla0)) != 0)
-		return result;
-	return 0;
+#ifdef MODULE
+	result = register_netdev(&sdla0);
+#endif
+	return result;
 }
 
-void cleanup_module(void)
+static void __exit exit_sdla(void)
 {
 	unregister_netdev(&sdla0);
 	if (sdla0.priv)
@@ -1688,4 +1688,8 @@
 	if (sdla0.irq)
 		free_irq(sdla0.irq, &sdla0);
 }
-#endif /* MODULE */
+
+MODULE_LICENSE("GPL");
+
+module_init(init_sdla);
+module_exit(exit_sdla);
diff -Nru a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c
--- a/drivers/net/wan/sdla_chdlc.c	Mon May 19 23:52:15 2003
+++ b/drivers/net/wan/sdla_chdlc.c	Mon May 26 15:29:13 2003
@@ -284,7 +284,7 @@
 static void wanpipe_tty_receive(sdla_t *, unsigned, unsigned int);
 static void wanpipe_tty_trigger_poll(sdla_t *card);
 
-static struct tty_driver serial_driver, callout_driver;
+static struct tty_driver serial_driver;
 static int serial_refcount=1;
 static int tty_init_cnt=0;
 
@@ -1056,15 +1056,12 @@
 	if (card->tty_opt){
 		struct serial_state * state;
 		if (!(--tty_init_cnt)){
-			int e1,e2;
+			int e1;
 			*serial_driver.refcount=0;
 			
 			if ((e1 = tty_unregister_driver(&serial_driver)))
 				printk("SERIAL: failed to unregister serial driver (%d)\n",
 				       e1);
-			if ((e2 = tty_unregister_driver(&callout_driver)))
-				printk("SERIAL: failed to unregister callout driver (%d)\n", 
-				       e2);
 			printk(KERN_INFO "%s: Unregistering TTY Driver, Major %i\n",
 					card->devname,WAN_TTY_MAJOR);
 		}
@@ -4444,27 +4441,10 @@
 		serial_driver.wait_until_sent = wanpipe_tty_wait_until_sent;
 		serial_driver.read_proc = wanpipe_tty_read_proc;
 		
-		/*
-		 * The callout device is just like normal device except for
-		 * major number and the subtype code.
-		 */
-		callout_driver = serial_driver;
-		callout_driver.name = "cuw";
-		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(&serial_driver)){
 			printk(KERN_INFO "%s: Failed to register serial driver!\n",
 					card->devname);
 		}
-
-		if (tty_register_driver(&callout_driver)){
-			printk(KERN_INFO "%s: Failed to register callout driver!\n",
-					card->devname);
-		}
-
 	}
 
 
@@ -4493,7 +4473,6 @@
 	state->custom_divisor = 0;
 	state->close_delay = 5*HZ/10;
 	state->closing_wait = 30*HZ;
-	state->callout_termios = callout_driver.init_termios;
 	state->normal_termios = serial_driver.init_termios;
 	state->icount.cts = state->icount.dsr = 
 		state->icount.rng = state->icount.dcd = 0;
diff -Nru a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h
--- a/drivers/net/wan/z85230.h	Thu Apr 24 05:18:50 2003
+++ b/drivers/net/wan/z85230.h	Mon May 26 15:29:27 2003
@@ -334,14 +334,11 @@
 	struct tty_struct 	*tty;		/* Attached terminal */
 	int			line;		/* Minor number */
 	struct termios		normal_termios;	/* Terminal settings */
-	struct termios		callout_termios;
 	wait_queue_head_t	open_wait;	/* Tasks waiting to open */
 	wait_queue_head_t	close_wait;	/* and for close to end */
 	unsigned long		event;		/* Pending events */
 	int			fdcount;    	/* # of fd on device */
 	int			blocked_open;	/* # of blocked opens */
-	long			session; 	/* Session of opening process */
-	long			pgrp; 		/* pgrp of opening process */
 	int			x_char;		/* XON/XOF char */
 	unsigned char 		*xmit_buf;	/* Transmit pointer */
 	int			xmit_head;	/* Transmit ring */
diff -Nru a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
--- a/drivers/net/wireless/Kconfig	Sun Apr 20 12:56:51 2003
+++ b/drivers/net/wireless/Kconfig	Tue May 27 00:33:28 2003
@@ -203,11 +203,24 @@
 	depends on PCI && HERMES && EXPERIMENTAL
 	help
 	  Enable support for PCMCIA cards supported by the "Hermes" (aka
-	  orinoco_cs) driver when used in PLX9052 based PCI adaptors.  These
+	  orinoco) driver when used in PLX9052 based PCI adaptors.  These
 	  adaptors are not a full PCMCIA controller but act as a more limited
 	  PCI <-> PCMCIA bridge.  Several vendors sell such adaptors so that
 	  802.11b PCMCIA cards can be used in desktop machines.  The Netgear
 	  MA301 is such an adaptor.
+
+	  Support for these adaptors is so far still incomplete and buggy.
+	  You have been warned.
+
+config TMD_HERMES
+	tristate "Hermes in TMD7160 based PCI adaptor support (EXPERIMENTAL)"
+	depends on PCI && HERMES && EXPERIMENTAL
+	help
+	  Enable support for PCMCIA cards supported by the "Hermes" (aka
+	  orinoco) driver when used in TMD7160 based PCI adaptors.  These
+	  adaptors are not a full PCMCIA controller but act as a more limited
+	  PCI <-> PCMCIA bridge.  Several vendors sell such adaptors so that
+	  802.11b PCMCIA cards can be used in desktop machines.
 
 	  Support for these adaptors is so far still incomplete and buggy.
 	  You have been warned.
diff -Nru a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
--- a/drivers/net/wireless/Makefile	Tue Feb 18 17:26:57 2003
+++ b/drivers/net/wireless/Makefile	Tue May 27 00:31:56 2003
@@ -15,6 +15,7 @@
 obj-$(CONFIG_APPLE_AIRPORT)	+= airport.o
 obj-$(CONFIG_PLX_HERMES)	+= orinoco_plx.o
 obj-$(CONFIG_PCI_HERMES)	+= orinoco_pci.o
+obj-$(CONFIG_TMD_HERMES)	+= orinoco_tmd.o
 
 obj-$(CONFIG_AIRO)		+= airo.o
 obj-$(CONFIG_AIRO_CS)		+= airo_cs.o airo.o
diff -Nru a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
--- a/drivers/net/wireless/airport.c	Wed Apr 23 05:04:33 2003
+++ b/drivers/net/wireless/airport.c	Tue May 27 00:21:42 2003
@@ -1,4 +1,4 @@
-/* airport.c 0.13a
+/* airport.c 0.13e
  *
  * A driver for "Hermes" chipset based Apple Airport wireless
  * card.
@@ -12,6 +12,7 @@
  */
 
 #include <linux/config.h>
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -20,7 +21,6 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/ioport.h>
-#include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
@@ -95,7 +95,7 @@
 
 		netif_device_detach(dev);
 
-		priv->hw_unavailable = 1;
+		priv->hw_unavailable++;
 
 		orinoco_unlock(priv, &flags);
 
@@ -121,14 +121,15 @@
 
 		netif_device_attach(dev);
 
-		if (priv->open) {
+		priv->hw_unavailable--;
+
+		if (priv->open && (! priv->hw_unavailable)) {
 			err = __orinoco_up(dev);
 			if (err)
 				printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n",
 				       dev->name, err);
 		}
 
-		priv->hw_unavailable = 0;
 
 		spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -138,6 +139,37 @@
 }
 #endif /* CONFIG_PMAC_PBOOK */
 
+static int airport_hard_reset(struct orinoco_private *priv)
+{
+	/* It would be nice to power cycle the Airport for a real hard
+	 * reset, but for some reason although it appears to
+	 * re-initialize properly, it falls in a screaming heap
+	 * shortly afterwards. */
+#if 0
+	struct net_device *dev = priv->ndev;
+	struct airport *card = priv->card;
+
+	/* Vitally important.  If we don't do this it seems we get an
+	 * interrupt somewhere during the power cycle, since
+	 * hw_unavailable is already set it doesn't get ACKed, we get
+	 * into an interrupt loop and the the PMU decides to turn us
+	 * off. */
+	disable_irq(dev->irq);
+
+	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout(HZ);
+	pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1);
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout(HZ);
+
+	enable_irq(dev->irq);
+	schedule_timeout(HZ);
+#endif
+
+	return 0;
+}
+
 static struct net_device *
 airport_attach(struct device_node *of_node)
 {
@@ -153,7 +185,7 @@
 	}
 
 	/* Allocate space for private device-specific data */
-	dev = alloc_orinocodev(sizeof(*card), NULL);
+	dev = alloc_orinocodev(sizeof(*card), airport_hard_reset);
 	if (! dev) {
 		printk(KERN_ERR "airport: can't allocate device datas\n");
 		return NULL;
@@ -195,7 +227,7 @@
 	/* Reset it before we get the interrupt */
 	hermes_init(hw);
 
-	if (request_irq(dev->irq, orinoco_interrupt, 0, "Airport", (void *)priv)) {
+	if (request_irq(dev->irq, orinoco_interrupt, 0, "Airport", dev)) {
 		printk(KERN_ERR "airport: Couldn't get IRQ %d\n", dev->irq);
 		goto failed;
 	}
@@ -209,11 +241,6 @@
 	printk(KERN_DEBUG "airport: card registered for interface %s\n", dev->name);
 	card->ndev_registered = 1;
 
-	/* And give us the proc nodes for debugging */
-	if (orinoco_proc_dev_init(dev) != 0)
-		printk(KERN_ERR "airport: Failed to create /proc node for %s\n",
-		       dev->name);
-
 #ifdef CONFIG_PMAC_PBOOK
 	pmu_register_sleep_notifier(&airport_sleep_notifier);
 #endif
@@ -234,9 +261,6 @@
 	struct orinoco_private *priv = dev->priv;
 	struct airport *card = priv->card;
 
-	/* Unregister proc entry */
-	orinoco_proc_dev_cleanup(dev);
-
 #ifdef CONFIG_PMAC_PBOOK
 	pmu_unregister_sleep_notifier(&airport_sleep_notifier);
 #endif
@@ -245,7 +269,7 @@
 	card->ndev_registered = 0;
 
 	if (card->irq_requested)
-		free_irq(dev->irq, priv);
+		free_irq(dev->irq, dev);
 	card->irq_requested = 0;
 
 	if (card->vaddr)
@@ -263,7 +287,7 @@
 	kfree(dev);
 }				/* airport_detach */
 
-static char version[] __initdata = "airport.c 0.13a (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
+static char version[] __initdata = "airport.c 0.13e (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
 MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
 MODULE_LICENSE("Dual MPL/GPL");
diff -Nru a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c
--- a/drivers/net/wireless/hermes.c	Thu Sep 26 19:49:23 2002
+++ b/drivers/net/wireless/hermes.c	Tue May 27 00:17:28 2003
@@ -52,7 +52,6 @@
 
 #include "hermes.h"
 
-static char version[] __initdata = "hermes.c: 4 Jul 2002 David Gibson <hermes@gibson.dropbear.id.au>";
 MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller");
 MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
 #ifdef MODULE_LICENSE
@@ -226,7 +225,8 @@
  * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware
  *
  * Callable from any context, but locking is your problem. */
-int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp)
+int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
+		      hermes_response_t *resp)
 {
 	int err;
 	int k;
@@ -402,7 +402,7 @@
  *
  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
  */
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
+int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len,
 		     u16 id, u16 offset)
 {
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
@@ -428,7 +428,7 @@
  *
  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
  */
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
+int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len,
 		      u16 id, u16 offset)
 {
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
@@ -456,26 +456,30 @@
  * practice.
  *
  * Callable from user or bh context.  */
-int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, int bufsize,
+int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
 		    u16 *length, void *buf)
 {
 	int err = 0;
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 	u16 rlength, rtype;
-	int nwords;
+	unsigned nwords;
 
 	if ( (bufsize < 0) || (bufsize % 2) )
 		return -EINVAL;
 
 	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
 	if (err)
-		goto out;
+		return err;
 
 	err = hermes_bap_seek(hw, bap, rid, 0);
 	if (err)
-		goto out;
+		return err;
 
 	rlength = hermes_read_reg(hw, dreg);
+
+	if (! rlength)
+		return -ENOENT;
+
 	rtype = hermes_read_reg(hw, dreg);
 
 	if (length)
@@ -492,11 +496,10 @@
 		       IO_TYPE(hw), hw->iobase,
 		       HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
 
-	nwords = min_t(int, rlength - 1, bufsize / 2);
+	nwords = min((unsigned)rlength - 1, bufsize / 2);
 	hermes_read_words(hw, dreg, buf, nwords);
 
- out:
-	return err;
+	return 0;
 }
 
 int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, 
@@ -504,11 +507,14 @@
 {
 	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 	int err = 0;
-	int count;
-	
+	unsigned count;
+
+	if (length == 0)
+		return -EINVAL;
+
 	err = hermes_bap_seek(hw, bap, rid, 0);
 	if (err)
-		goto out;
+		return err;
 
 	hermes_write_reg(hw, dreg, length);
 	hermes_write_reg(hw, dreg, rid);
@@ -520,7 +526,6 @@
 	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, 
 				rid, NULL);
 
- out:
 	return err;
 }
 
@@ -536,9 +541,12 @@
 
 static int __init init_hermes(void)
 {
-	printk(KERN_DEBUG "%s\n", version);
-
 	return 0;
 }
 
+static void __exit exit_hermes(void)
+{
+}
+
 module_init(init_hermes);
+module_exit(exit_hermes);
diff -Nru a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h
--- a/drivers/net/wireless/hermes.h	Sun Sep 29 21:46:30 2002
+++ b/drivers/net/wireless/hermes.h	Tue May 27 00:17:28 2003
@@ -250,7 +250,6 @@
 	u16 scanreason;             /* ??? */
 	struct hermes_scan_apinfo aps[35];        /* Scan result */
 } __attribute__ ((packed));
-
 #define HERMES_LINKSTATUS_NOT_CONNECTED   (0x0000)  
 #define HERMES_LINKSTATUS_CONNECTED       (0x0001)
 #define HERMES_LINKSTATUS_DISCONNECTED    (0x0002)
@@ -278,7 +277,7 @@
 
 /* Basic control structure */
 typedef struct hermes {
-	ulong iobase;
+	unsigned long iobase;
 	int io_space; /* 1 if we IO-mapped IO, 0 for memory-mapped IO? */
 #define HERMES_IO	1
 #define HERMES_MEM	0
@@ -316,11 +315,11 @@
 int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp);
 int hermes_allocate(hermes_t *hw, u16 size, u16 *fid);
 
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
+int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len,
 		       u16 id, u16 offset);
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
+int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len,
 			u16 id, u16 offset);
-int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, int buflen,
+int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen,
 		    u16 *length, void *buf);
 int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
 		      u16 length, const void *value);
@@ -361,39 +360,58 @@
 #define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 )
 
 /* Note that for the next two, the count is in 16-bit words, not bytes */
-static inline void hermes_read_words(struct hermes *hw, int off, void *buf, int count)
+static inline void hermes_read_words(struct hermes *hw, int off, void *buf, unsigned count)
 {
 	off = off << hw->reg_spacing;;
 
 	if (hw->io_space) {
 		insw(hw->iobase + off, buf, count);
 	} else {
-		int i;
+		unsigned i;
 		u16 *p;
 
-		/* This need to *not* byteswap (like insw()) but
-		 * readw() does byteswap hence the conversion */
+		/* This needs to *not* byteswap (like insw()) but
+		 * readw() does byteswap hence the conversion.  I hope
+		 * gcc is smart enough to fold away the two swaps on
+		 * big-endian platforms. */
 		for (i = 0, p = buf; i < count; i++) {
 			*p++ = cpu_to_le16(readw(hw->iobase + off));
 		}
 	}
 }
 
-static inline void hermes_write_words(struct hermes *hw, int off, const void *buf, int count)
+static inline void hermes_write_words(struct hermes *hw, int off, const void *buf, unsigned count)
 {
 	off = off << hw->reg_spacing;;
 
 	if (hw->io_space) {
 		outsw(hw->iobase + off, buf, count);
 	} else {
-		int i;
+		unsigned i;
 		const u16 *p;
 
-		/* This need to *not* byteswap (like outsw()) but
-		 * writew() does byteswap hence the conversion */
+		/* This needs to *not* byteswap (like outsw()) but
+		 * writew() does byteswap hence the conversion.  I
+		 * hope gcc is smart enough to fold away the two swaps
+		 * on big-endian platforms. */
 		for (i = 0, p = buf; i < count; i++) {
 			writew(le16_to_cpu(*p++), hw->iobase + off);
 		}
+	}
+}
+
+static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count)
+{
+	unsigned i;
+
+	off = off << hw->reg_spacing;;
+
+	if (hw->io_space) {
+		for (i = 0; i < count; i++)
+			outw(0, hw->iobase + off);
+	} else {
+		for (i = 0; i < count; i++)
+			writew(0, hw->iobase + off);
 	}
 }
 
diff -Nru a/drivers/net/wireless/ieee802_11.h b/drivers/net/wireless/ieee802_11.h
--- a/drivers/net/wireless/ieee802_11.h	Thu Sep 26 19:49:23 2002
+++ b/drivers/net/wireless/ieee802_11.h	Tue May 27 00:17:28 2003
@@ -2,9 +2,15 @@
 #define _IEEE802_11_H
 
 #define IEEE802_11_DATA_LEN		2304
-/* Actually, the standard seems to be inconsistent about what the
-   maximum frame size really is.  Section 6.2.1.1.2 says 2304 octets,
-   but the figure in Section 7.1.2 says 2312 octects. */
+/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
+   6.2.1.1.2.
+
+   The figure in section 7.1.2 suggests a body size of up to 2312
+   bytes is allowed, which is a bit confusing, I suspect this
+   represents the 2304 bytes of real data, plus a possible 8 bytes of
+   WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+
+
 #define IEEE802_11_HLEN			30
 #define IEEE802_11_FRAME_LEN		(IEEE802_11_DATA_LEN + IEEE802_11_HLEN)
 
diff -Nru a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
--- a/drivers/net/wireless/orinoco.c	Sun Apr 20 23:39:12 2003
+++ b/drivers/net/wireless/orinoco.c	Tue May 27 00:17:28 2003
@@ -1,4 +1,4 @@
-/* orinoco.c 0.13a	- (formerly known as dldwd_cs.c and orinoco_cs.c)
+/* orinoco.c 0.13e	- (formerly known as dldwd_cs.c and orinoco_cs.c)
  *
  * A driver for Hermes or Prism 2 chipset based PCMCIA wireless
  * adaptors, with Lucent/Agere, Intersil or Symbol firmware.
@@ -323,7 +323,7 @@
  *	  the card from hard sleep.
  *
  * v0.13beta1 -> v0.13 - 27 Sep 2002 - David Gibson
- *	o Re-introduced full resets (via schedule_work()) on Tx
+ *	o Re-introduced full resets (via schedule_task()) on Tx
  *	  timeout.
  *
  * v0.13 -> v0.13a - 30 Sep 2002 - David Gibson
@@ -332,15 +332,70 @@
  *	o Include required kernel headers in orinoco.h, to avoid
  *	  compile problems.
  *
+ * v0.13a -> v0.13b - 10 Feb 2003 - David Gibson
+ *	o Implemented hard reset for Airport cards
+ *	o Experimental suspend/resume implementation for orinoco_pci
+ *	o Abolished /proc debugging support, replaced with a debugging
+ *	  iwpriv.  Now it's ugly and simple instead of ugly and complex.
+ *	o Bugfix in hermes.c if the firmware returned a record length
+ *	  of 0, we could go clobbering memory.
+ *	o Bugfix in orinoco_stop() - it used to fail if hw_unavailable
+ *	  was set, which was usually true on PCMCIA hot removes.
+ * 	o Track LINKSTATUS messages, silently drop Tx packets before
+ * 	  we are connected (avoids cofusing the firmware), and only
+ * 	  give LINKSTATUS printk()s if the status has changed.
+ *
+ * v0.13b -> v0.13c - 11 Mar 2003 - David Gibson
+ *	o Cleanup: use dev instead of priv in various places.
+ *	o Bug fix: Don't ReleaseConfiguration on RESET_PHYSICAL event
+ *	  if we're in the middle of a (driver initiated) hard reset.
+ *	o Bug fix: ETH_ZLEN is supposed to include the header
+ *	  (Dionysus Blazakis & Manish Karir)
+ *	o Convert to using workqueues instead of taskqueues (and
+ *	  backwards compatibility macros for pre 2.5.41 kernels).
+ *	o Drop redundant (I think...) MOD_{INC,DEC}_USE_COUNT in
+ *	  airport.c
+ *	o New orinoco_tmd.c init module from Joerg Dorchain for
+ *	  TMD7160 based PCI to PCMCIA bridges (similar to
+ *	  orinoco_plx.c).
+ *
+ * v0.13c -> v0.13d - 22 Apr 2003 - David Gibson
+ *	o Make hw_unavailable a counter, rather than just a flag, this
+ *	  is necessary to avoid some races (such as a card being
+ *	  removed in the middle of orinoco_reset().
+ *	o Restore Release/RequestConfiguration in the PCMCIA event handler
+ *	  when dealing with a driver initiated hard reset.  This is
+ *	  necessary to prevent hangs due to a spurious interrupt while
+ *	  the reset is in progress.
+ *	o Clear the 802.11 header when transmitting, even though we
+ *	  don't use it.  This fixes a long standing bug on some
+ *	  firmwares, which seem to get confused if that isn't done.
+ *	o Be less eager to de-encapsulate SNAP frames, only do so if
+ *	  the OUI is 00:00:00 or 00:00:f8, leave others alone.  The old
+ *	  behaviour broke CDP (Cisco Discovery Protocol).
+ *	o Use dev instead of priv for free_irq() as well as
+ *	  request_irq() (oops).
+ *	o Attempt to reset rather than giving up if we get too many
+ *	  IRQs.
+ *	o Changed semantics of __orinoco_down() so it can be called
+ *	  safely with hw_unavailable set.  It also now clears the
+ *	  linkstatus (since we're going to have to reassociate).
+ *
+ * v0.13d -> v0.13e - 12 May 2003 - David Gibson
+ *	o Support for post-2.5.68 return values from irq handler.
+ *	o Fixed bug where underlength packets would be double counted
+ *	  in the rx_dropped statistics.
+ *	o Provided a module parameter to suppress linkstatus messages.
+ *
  * TODO
- *	o New wireless extensions API (patch forthcoming from Moustafa
- *	  Youssef).
+ *	o New wireless extensions API (patch from Moustafa
+ *	  Youssef, updated by Jim Carter and Pavel Roskin).
  *	o Handle de-encapsulation within network layer, provide 802.11
  *	  headers (patch from Thomas 'Dent' Mirlacher)
+ *	o RF monitor mode support
  *	o Fix possible races in SPY handling.
  *	o Disconnect wireless extensions from fundamental configuration.
  *	o (maybe) Software WEP support (patch from Stano Meduna).
- *	o (maybe) Convert /proc debugging stuff to seqfile
  *	o (maybe) Use multiple Tx buffers - driver handling queue
  *	  rather than firmware. */
 
@@ -357,7 +412,9 @@
  * the middle of a hard reset).  This flag is protected by the
  * spinlock.  All code which touches the hardware should check the
  * flag after taking the lock, and if it is set, give up on whatever
- * they are doing and drop the lock again. */
+ * they are doing and drop the lock again.  The orinoco_lock()
+ * function handles this (it unlocks and returns -EBUSY if
+ * hw_unavailable is non-zero). */
 
 #include <linux/config.h>
 
@@ -369,12 +426,10 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/ioport.h>
-#include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
-#include <linux/workqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -402,6 +457,9 @@
 EXPORT_SYMBOL(orinoco_debug);
 #endif
 
+static int suppress_linkstatus; /* = 0 */
+MODULE_PARM(suppress_linkstatus, "i");
+
 /********************************************************************/
 /* Compile time configuration and compatibility stuff               */
 /********************************************************************/
@@ -429,8 +487,10 @@
 #define USER_BAP		0
 #define IRQ_BAP			1
 #define MAX_IRQLOOPS_PER_IRQ	10
-#define MAX_IRQLOOPS_PER_JIFFY	(20000/HZ)	/* Based on a guestimate of how many events the
-						   device can legitimately generate */
+#define MAX_IRQLOOPS_PER_JIFFY	(20000/HZ) /* Based on a guestimate of
+					    * how many events the
+					    * device could
+					    * legitimately generate */
 #define SMALL_KEY_SIZE		5
 #define LARGE_KEY_SIZE		13
 #define TX_NICBUF_SIZE_BUG	1585		/* Bug in Symbol firmware */
@@ -456,7 +516,7 @@
 
 /* This tables gives the actual meanings of the bitrate IDs returned by the firmware. */
 struct {
-	int bitrate; /* in 100s of kilbits */
+	int bitrate; /* in 100s of kilobits */
 	int automatic;
 	u16 agere_txratectrl;
 	u16 intersil_txratectrl;
@@ -466,8 +526,8 @@
 	{10,  1,  1,  1},
 	{20,  0,  2,  2},
 	{20,  1,  6,  3},
-	{55, 0,  4,  4},
-	{55, 1,  7,  7},
+	{55,  0,  4,  4},
+	{55,  1,  7,  7},
 	{110, 0,  5,  8},
 };
 #define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0]))
@@ -508,7 +568,7 @@
 
 /* Hardware control routines */
 
-static int __orinoco_program_rids(struct orinoco_private *priv);
+static int __orinoco_program_rids(struct net_device *dev);
 
 static int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
 static int __orinoco_hw_setup_wep(struct orinoco_private *priv);
@@ -521,39 +581,21 @@
 static void __orinoco_set_multicast_list(struct net_device *dev);
 
 /* Interrupt handling routines */
-static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw);
-static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw);
-static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw);
-static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw);
-static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw);
-static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw);
-static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw);
-static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw);
+static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw);
+static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw);
+static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw);
+static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw);
+static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw);
+static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw);
+static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw);
+static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw);
 
 /* ioctl() routines */
-static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq);
-static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq);
-static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq);
-static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq);
-static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq);
-static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq);
-static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq);
-static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq);
-static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq);
-static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq);
-static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq);
-static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq);
-static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq);
-static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *frq);
-static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *frq);
-static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq);
-static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq);
-static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq);
-static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq);
-
-/* /proc debugging stuff */
-static int orinoco_proc_init(void);
-static void orinoco_proc_cleanup(void);
+static int orinoco_debug_dump_recs(struct net_device *dev);
+
+/********************************************************************/
+/* Function prototypes                                              */
+/********************************************************************/
 
 int __orinoco_up(struct net_device *dev)
 {
@@ -561,7 +603,7 @@
 	struct hermes *hw = &priv->hw;
 	int err;
 
-	err = __orinoco_program_rids(priv);
+	err = __orinoco_program_rids(dev);
 	if (err) {
 		printk(KERN_ERR "%s: Error %d configuring card\n",
 		       dev->name, err);
@@ -590,14 +632,25 @@
 
 	netif_stop_queue(dev);
 
-	err = hermes_disable_port(hw, 0);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d disabling MAC port\n",
-		       dev->name, err);
-		return err;
+	if (! priv->hw_unavailable) {
+		if (! priv->broken_disableport) {
+			err = hermes_disable_port(hw, 0);
+			if (err) {
+				/* Some firmwares (e.g. Intersil 1.3.x) seem
+				 * to have problems disabling the port, oh
+				 * well, too bad. */
+				printk(KERN_WARNING "%s: Error %d disabling MAC port\n",
+				       dev->name, err);
+				priv->broken_disableport = 1;
+			}
+		}
+		hermes_set_irqmask(hw, 0);
+		hermes_write_regn(hw, EVACK, 0xffff);
 	}
-	hermes_set_irqmask(hw, 0);
-	hermes_write_regn(hw, EVACK, 0xffff);
+	
+	/* firmware will have to reassociate */
+	priv->last_linkstatus = 0xffff;
+	priv->connected = 0;
 
 	return 0;
 }
@@ -640,37 +693,38 @@
 	if (err)
 		return err;
 
-        priv->open = 1;
-
 	err = __orinoco_up(dev);
 
+	if (! err)
+		priv->open = 1;
+
 	orinoco_unlock(priv, &flags);
 
 	return err;
 }
 
-static int orinoco_stop(struct net_device *dev)
+int orinoco_stop(struct net_device *dev)
 {
 	struct orinoco_private *priv = dev->priv;
-	unsigned long flags;
-	int err;
+	int err = 0;
 
-	err = orinoco_lock(priv, &flags);
-	if (err)
-		return err;
+	/* We mustn't use orinoco_lock() here, because we need to be
+	   able to close the interface even if hw_unavailable is set
+	   (e.g. as we're released after a PC Card removal) */
+	spin_lock_irq(&priv->lock);
 
 	priv->open = 0;
 
 	err = __orinoco_down(dev);
 
-	orinoco_unlock(priv, &flags);
+	spin_unlock_irq(&priv->lock);
 
 	return err;
 }
 
-static int __orinoco_program_rids(struct orinoco_private *priv)
+static int __orinoco_program_rids(struct net_device *dev)
 {
-	struct net_device *dev = priv->ndev;
+	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
 	int err;
 	struct hermes_idstring idbuf;
@@ -856,33 +910,52 @@
 }
 
 /* xyzzy */
-static int orinoco_reconfigure(struct orinoco_private *priv)
+static int orinoco_reconfigure(struct net_device *dev)
 {
+	struct orinoco_private *priv = dev->priv;
 	struct hermes *hw = &priv->hw;
 	unsigned long flags;
 	int err = 0;
 
-	orinoco_lock(priv, &flags);
+	if (priv->broken_disableport) {
+		schedule_work(&priv->reset_work);
+		return 0;
+	}
+
+	err = orinoco_lock(priv, &flags);
+	if (err)
+		return err;
 
+		
 	err = hermes_disable_port(hw, 0);
 	if (err) {
-		printk(KERN_ERR "%s: Unable to disable port in orinco_reconfigure()\n",
-		       priv->ndev->name);
+		printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n",
+		       dev->name);
+		priv->broken_disableport = 1;
 		goto out;
 	}
 
-	err = __orinoco_program_rids(priv);
-	if (err)
+	err = __orinoco_program_rids(dev);
+	if (err) {
+		printk(KERN_WARNING "%s: Unable to reconfigure card\n",
+		       dev->name);
 		goto out;
+	}
 
 	err = hermes_enable_port(hw, 0);
 	if (err) {
-		printk(KERN_ERR "%s: Unable to enable port in orinco_reconfigure()\n",
-		       priv->ndev->name);
+		printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
+		       dev->name);
 		goto out;
 	}
 
  out:
+	if (err) {
+		printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
+		schedule_work(&priv->reset_work);
+		err = 0;
+	}
+
 	orinoco_unlock(priv, &flags);
 	return err;
 
@@ -893,16 +966,28 @@
 static void orinoco_reset(struct net_device *dev)
 {
 	struct orinoco_private *priv = dev->priv;
+	struct hermes *hw = &priv->hw;
 	int err;
 	unsigned long flags;
 
-	printk(KERN_INFO "%s: orinoco_reset()\n", dev->name);
-
 	err = orinoco_lock(priv, &flags);
 	if (err)
+		/* When the hardware becomes available again, whatever
+		 * detects that is responsible for re-initializing
+		 * it. So no need for anything further*/
 		return;
 
-	priv->hw_unavailable = 1;
+	netif_stop_queue(dev);
+
+	/* Shut off interrupts.  Depending on what state the hardware
+	 * is in, this might not work, but we'll try anyway */
+	hermes_set_irqmask(hw, 0);
+	hermes_write_regn(hw, EVACK, 0xffff);
+
+	priv->hw_unavailable++;
+	priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */
+	priv->connected = 0;
+
 	orinoco_unlock(priv, &flags);
 
 	if (priv->hard_reset)
@@ -921,18 +1006,22 @@
 		return;
 	}
 
-	spin_lock_irqsave(&priv->lock, flags);
+	spin_lock_irq(&priv->lock); /* This has to be called from user context */
 
-	priv->hw_unavailable = 0;
+	priv->hw_unavailable--;
 
-	err = __orinoco_up(dev);
-	if (err) {
-		printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
-		       dev->name, err);
-	} else
-		dev->trans_start = jiffies;
+	/* priv->open or priv->hw_unavailable might have changed while
+	 * we dropped the lock */
+	if (priv->open && (! priv->hw_unavailable)) {
+		err = __orinoco_up(dev);
+		if (err) {
+			printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
+			       dev->name, err);
+		} else
+			dev->trans_start = jiffies;
+	}
 
-	orinoco_unlock(priv, &flags);
+	spin_unlock_irq(&priv->lock);
 
 	return;
 }
@@ -964,10 +1053,18 @@
 	}
 }
 
+/* Does the frame have a SNAP header indicating it should be
+ * de-encapsulated to Ethernet-II? */
 static inline int
-is_snap(struct header_struct *hdr)
+is_ethersnap(struct header_struct *hdr)
 {
-	return (hdr->dsap == 0xAA) && (hdr->ssap == 0xAA) && (hdr->ctrl == 0x3);
+	/* We de-encapsulate all packets which, a) have SNAP headers
+	 * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header
+	 * and where b) the OUI of the SNAP header is 00:00:00 or
+	 * 00:00:f8 - we need both because different APs appear to use
+	 * different OUIs for some reason */
+	return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0)
+		&& ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) );
 }
 
 static void
@@ -1125,7 +1222,8 @@
 	return 0;
 }
 
-static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN])
+static int orinoco_hw_get_bssid(struct orinoco_private *priv,
+				char buf[ETH_ALEN])
 {
 	hermes_t *hw = &priv->hw;
 	int err = 0;
@@ -1144,7 +1242,7 @@
 }
 
 static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
-			      char buf[IW_ESSID_MAX_SIZE+1])
+				char buf[IW_ESSID_MAX_SIZE+1])
 {
 	hermes_t *hw = &priv->hw;
 	int err = 0;
@@ -1221,9 +1319,8 @@
 	}
 
 	if ( (channel < 1) || (channel > NUM_CHANNELS) ) {
-		struct net_device *dev = priv->ndev;
-
-		printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel);
+		printk(KERN_WARNING "%s: Channel out of range (%d)!\n",
+		       priv->ndev->name, channel);
 		err = -EBUSY;
 		goto out;
 
@@ -1238,8 +1335,8 @@
 	return err ? err : freq;
 }
 
-static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates,
-				    s32 *rates, int max)
+static int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
+				      int *numrates, s32 *rates, int max)
 {
 	hermes_t *hw = &priv->hw;
 	struct hermes_idstring list;
@@ -1272,9 +1369,6 @@
 }
 
 #if 0
-#ifndef ORINOCO_DEBUG
-static inline void show_rx_frame(struct orinoco_rxframe_hdr *frame) {}
-#else
 static void show_rx_frame(struct orinoco_rxframe_hdr *frame)
 {
 	printk(KERN_DEBUG "RX descriptor:\n");
@@ -1331,17 +1425,16 @@
 	       frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]);
 	printk(KERN_DEBUG "  ethertype  = 0x%04x\n", frame->ethertype);
 }
-#endif
-#endif
+#endif /* 0 */
 
 /*
  * Interrupt handler
  */
 irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	struct orinoco_private *priv = (struct orinoco_private *) dev_id;
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
-	struct net_device *dev = priv->ndev;
 	int count = MAX_IRQLOOPS_PER_IRQ;
 	u16 evstat, events;
 	/* These are used to detect a runaway interrupt situation */
@@ -1352,12 +1445,17 @@
 	unsigned long flags;
 
 	if (orinoco_lock(priv, &flags) != 0) {
-		/* If hw is unavailable */
-		return IRQ_NONE;
+		/* If hw is unavailable - we don't know if the irq was
+		 * for us or not */
+		return IRQ_HANDLED;
 	}
 
 	evstat = hermes_read_regn(hw, EVSTAT);
 	events = evstat & hw->inten;
+	if (! events) {
+		orinoco_unlock(priv, &flags);
+		return IRQ_NONE;
+	}
 	
 	if (jiffies != last_irq_jiffy)
 		loops_this_jiffy = 0;
@@ -1365,11 +1463,11 @@
 
 	while (events && count--) {
 		if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) {
-			printk(KERN_CRIT "%s: IRQ handler is looping too \
-much! Shutting down.\n",
-			       dev->name);
-			/* Perform an emergency shutdown */
+			printk(KERN_WARNING "%s: IRQ handler is looping too "
+			       "much! Resetting.\n", dev->name);
+			/* Disable interrupts for now */
 			hermes_set_irqmask(hw, 0);
+			schedule_work(&priv->reset_work);
 			break;
 		}
 
@@ -1380,21 +1478,21 @@
 		}
 
 		if (events & HERMES_EV_TICK)
-			__orinoco_ev_tick(priv, hw);
+			__orinoco_ev_tick(dev, hw);
 		if (events & HERMES_EV_WTERR)
-			__orinoco_ev_wterr(priv, hw);
+			__orinoco_ev_wterr(dev, hw);
 		if (events & HERMES_EV_INFDROP)
-			__orinoco_ev_infdrop(priv, hw);
+			__orinoco_ev_infdrop(dev, hw);
 		if (events & HERMES_EV_INFO)
-			__orinoco_ev_info(priv, hw);
+			__orinoco_ev_info(dev, hw);
 		if (events & HERMES_EV_RX)
-			__orinoco_ev_rx(priv, hw);
+			__orinoco_ev_rx(dev, hw);
 		if (events & HERMES_EV_TXEXC)
-			__orinoco_ev_txexc(priv, hw);
+			__orinoco_ev_txexc(dev, hw);
 		if (events & HERMES_EV_TX)
-			__orinoco_ev_tx(priv, hw);
+			__orinoco_ev_tx(dev, hw);
 		if (events & HERMES_EV_ALLOC)
-			__orinoco_ev_alloc(priv, hw);
+			__orinoco_ev_alloc(dev, hw);
 		
 		hermes_write_regn(hw, EVACK, events);
 
@@ -1403,31 +1501,67 @@
 	};
 
 	orinoco_unlock(priv, &flags);
-
 	return IRQ_HANDLED;
 }
 
-static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw)
+static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw)
 {
-	printk(KERN_DEBUG "%s: TICK\n", priv->ndev->name);
+	printk(KERN_DEBUG "%s: TICK\n", dev->name);
 }
 
-static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw)
+static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw)
 {
 	/* This seems to happen a fair bit under load, but ignoring it
 	   seems to work fine...*/
 	printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n",
-	       priv->ndev->name);
+	       dev->name);
 }
 
-static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw)
+static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
 {
-	printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev->name);
+	printk(KERN_WARNING "%s: Information frame lost.\n", dev->name);
+}
+
+static void print_linkstatus(struct net_device *dev, u16 status)
+{
+	char * s;
+
+	if (suppress_linkstatus)
+		return;
+
+	switch (status) {
+	case HERMES_LINKSTATUS_NOT_CONNECTED:
+		s = "Not Connected";
+		break;
+	case HERMES_LINKSTATUS_CONNECTED:
+		s = "Connected";
+		break;
+	case HERMES_LINKSTATUS_DISCONNECTED:
+		s = "Disconnected";
+		break;
+	case HERMES_LINKSTATUS_AP_CHANGE:
+		s = "AP Changed";
+		break;
+	case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:
+		s = "AP Out of Range";
+		break;
+	case HERMES_LINKSTATUS_AP_IN_RANGE:
+		s = "AP In Range";
+		break;
+	case HERMES_LINKSTATUS_ASSOC_FAILED:
+		s = "Association Failed";
+		break;
+	default:
+		s = "UNKNOWN";
+	}
+	
+	printk(KERN_INFO "%s: New link status: %s (%04x)\n",
+	       dev->name, s, status);
 }
 
-static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw)
+static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 {
-	struct net_device *dev = priv->ndev;
+	struct orinoco_private *priv = dev->priv;
 	u16 infofid;
 	struct {
 		u16 len;
@@ -1491,7 +1625,6 @@
 	case HERMES_INQ_LINKSTATUS: {
 		struct hermes_linkstatus linkstatus;
 		u16 newstatus;
-		const char *s;
 		
 		if (len != sizeof(linkstatus)) {
 			printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
@@ -1503,34 +1636,20 @@
 				  len / 2);
 		newstatus = le16_to_cpu(linkstatus.linkstatus);
 
-		switch (newstatus) {
-		case HERMES_LINKSTATUS_NOT_CONNECTED:
-			s = "Not Connected";
-                       break;
-               case HERMES_LINKSTATUS_CONNECTED:
-		       s = "Connected";
-                       break;
-               case HERMES_LINKSTATUS_DISCONNECTED:
-		       s = "Disconnected";
-                       break;
-               case HERMES_LINKSTATUS_AP_CHANGE:
-		       s = "AP Changed";
-                       break;
-               case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:
-		       s = "AP Out of Range";
-                       break;
-               case HERMES_LINKSTATUS_AP_IN_RANGE:
-		       s = "AP In Range";
-                       break;
-               case HERMES_LINKSTATUS_ASSOC_FAILED:
-		       s = "Association Failed";
-		       break;
-		default:
-			s = "UNKNOWN";
-		}
+		if ( (newstatus == HERMES_LINKSTATUS_CONNECTED)
+		     || (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
+		     || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE) )
+			priv->connected = 1;
+		else if ( (newstatus == HERMES_LINKSTATUS_NOT_CONNECTED)
+			  || (newstatus == HERMES_LINKSTATUS_DISCONNECTED)
+			  || (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE)
+			  || (newstatus == HERMES_LINKSTATUS_ASSOC_FAILED) )
+			priv->connected = 0;
+
+		if (newstatus != priv->last_linkstatus)
+			print_linkstatus(dev, newstatus);
 
-		printk(KERN_INFO "%s: New link status: %s (%04x)\n",
-		       dev->name, s, newstatus);
+		priv->last_linkstatus = newstatus;
 	}
 	break;
 	default:
@@ -1541,9 +1660,9 @@
 	}
 }
 
-static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw)
+static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 {
-	struct net_device *dev = priv->ndev;
+	struct orinoco_private *priv = dev->priv;
 	struct net_device_stats *stats = &priv->stats;
 	struct iw_statistics *wstats = &priv->wstats;
 	struct sk_buff *skb = NULL;
@@ -1632,14 +1751,13 @@
 	 * So, check ourselves */
 	if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
 	   ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
-	   is_snap(&hdr)) {
+	   is_ethersnap(&hdr)) {
 		/* These indicate a SNAP within 802.2 LLC within
 		   802.11 frame which we'll need to de-encapsulate to
 		   the original EthernetII frame. */
 
 		if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */
 			stats->rx_length_errors++;
-			stats->rx_dropped++;
 			goto drop;
 		}
 
@@ -1694,9 +1812,9 @@
 	return;
 }
 
-static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw)
+static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
 {
-	struct net_device *dev = priv->ndev;
+	struct orinoco_private *priv = dev->priv;
 	struct net_device_stats *stats = &priv->stats;
 	u16 fid = hermes_read_regn(hw, TXCOMPLFID);
 	struct hermes_tx_descriptor desc;
@@ -1720,8 +1838,9 @@
 	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
 }
 
-static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw)
+static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
 {
+	struct orinoco_private *priv = dev->priv;
 	struct net_device_stats *stats = &priv->stats;
 
 	stats->tx_packets++;
@@ -1729,9 +1848,10 @@
 	hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
 }
 
-static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw)
+static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
 {
-	struct net_device *dev = priv->ndev;
+	struct orinoco_private *priv = dev->priv;
+
 	u16 fid = hermes_read_regn(hw, ALLOCFID);
 
 	if (fid != priv->txfid) {
@@ -1913,7 +2033,7 @@
 
 	TRACE_ENTER(dev->name);
 
-	/* No need to lock, the resetting flag is already set in
+	/* No need to lock, the hw_unavailable flag is already set in
 	 * alloc_orinocodev() */
 	priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN;
 
@@ -2049,8 +2169,6 @@
 	priv->wep_on = 0;
 	priv->tx_key = 0;
 
-	priv->hw_unavailable = 0;
-
 	err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
 	if (err == -EIO) {
 		/* Try workaround for old Symbol firmware bug */
@@ -2070,6 +2188,12 @@
 		goto out;
 	}
 
+	/* Make the hardware available, as long as it hasn't been
+	 * removed elsewhere (e.g. by PCMCIA hot unplug) */
+	spin_lock_irq(&priv->lock);
+	priv->hw_unavailable--;
+	spin_unlock_irq(&priv->lock);
+
 	printk(KERN_DEBUG "%s: ready\n", dev->name);
 
  out:
@@ -2222,9 +2346,20 @@
 		return 1;
 	}
 
+	if (! priv->connected) {
+		/* Oops, the firmware hasn't established a connection,
+                   silently drop the packet (this seems to be the
+                   safest approach). */
+		stats->tx_errors++;
+		orinoco_unlock(priv, &flags);
+		dev_kfree_skb(skb);
+		TRACE_EXIT(dev->name);
+		return 0;
+	}
+
 	/* Length of the packet body */
 	/* FIXME: what if the skb is smaller than this? */
-	len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN);
+	len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN);
 
 	eh = (struct ethhdr *)skb->data;
 
@@ -2238,6 +2373,12 @@
 		goto fail;
 	}
 
+	/* Clear the 802.11 header and data length fields - some
+	 * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
+	 * if this isn't done. */
+	hermes_clear_words(hw, HERMES_DATA0,
+			   HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
+
 	/* Encapsulate Ethernet-II frames */
 	if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */
 		struct header_struct hdr;
@@ -2319,7 +2460,7 @@
 
 	stats->tx_errors++;
 
-	schedule_work(&priv->timeout_task);
+	schedule_work(&priv->reset_work);
 }
 
 static int
@@ -2489,7 +2630,7 @@
 	}
 
 	err = orinoco_hw_get_bitratelist(priv, &numrates,
-				       range.bitrate, IW_MAX_BITRATES);
+					 range.bitrate, IW_MAX_BITRATES);
 	if (err)
 		return err;
 	range.num_bitrates = numrates;
@@ -2756,7 +2897,7 @@
 	erq->flags = 1;
 	erq->length = strlen(essidbuf) + 1;
 	if (erq->pointer)
-		if ( copy_to_user(erq->pointer, essidbuf, erq->length) )
+		if (copy_to_user(erq->pointer, essidbuf, erq->length))
 			return -EFAULT;
 
 	TRACE_EXIT(dev->name);
@@ -3085,7 +3226,7 @@
 				rrq->value = 5500000;
 			else
 				rrq->value = val * 1000000;
-                        break;
+			break;
 		case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
 		case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
 			for (i = 0; i < BITRATE_TABLE_SIZE; i++)
@@ -3688,7 +3829,8 @@
 				  0, "set_ibssport" },
 				{ SIOCIWFIRSTPRIV + 0x7, 0,
 				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  "get_ibssport" }
+				  "get_ibssport" },
+				{ SIOCIWLASTPRIV, 0, 0, "dump_recs" },
 			};
 
 			err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab));
@@ -3710,7 +3852,7 @@
 		
 		printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
 
-		schedule_work(&priv->timeout_task);
+		schedule_work(&priv->reset_work);
 		break;
 
 	case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */
@@ -3782,13 +3924,20 @@
 		err = orinoco_ioctl_getibssport(dev, wrq);
 		break;
 
+	case SIOCIWLASTPRIV:
+		err = orinoco_debug_dump_recs(dev);
+		if (err)
+			printk(KERN_ERR "%s: Unable to dump records (%d)\n",
+			       dev->name, err);
+		break;
+
 
 	default:
 		err = -EOPNOTSUPP;
 	}
 	
 	if (! err && changed && netif_running(dev)) {
-		err = orinoco_reconfigure(priv);
+		err = orinoco_reconfigure(dev);
 	}		
 
 	TRACE_EXIT(dev->name);
@@ -3796,81 +3945,6 @@
 	return err;
 }
 
-/********************************************************************/
-/* procfs stuff                                                     */
-/********************************************************************/
-
-static struct proc_dir_entry *dir_base = NULL;
-
-#define PROC_LTV_SIZE		128
-
-/*
- * This function updates the total amount of data printed so far. It then
- * determines if the amount of data printed into a buffer  has reached the
- * offset requested. If it hasn't, then the buffer is shifted over so that
- * the next bit of data can be printed over the old bit. If the total
- * amount printed so far exceeds the total amount requested, then this
- * function returns 1, otherwise 0.
- */
-static int 
-shift_buffer(char *buffer, int requested_offset, int requested_len,
-	     int *total, int *slop, char **buf)
-{
-	int printed;
-	
-	printed = *buf - buffer;
-	if (*total + printed <= requested_offset) {
-		*total += printed;
-		*buf = buffer;
-	}
-	else {
-		if (*total < requested_offset) {
-			*slop = requested_offset - *total;
-		}
-		*total = requested_offset + printed - *slop;
-	}
-	if (*total > requested_offset + requested_len) {
-		return 1;
-	}
-	else {
-		return 0;
-	}
-}
-
-/*
- * This function calculates the actual start of the requested data
- * in the buffer. It also calculates actual length of data returned,
- * which could be less that the amount of data requested.
- */
-#define PROC_BUFFER_SIZE 4096
-#define PROC_SAFE_SIZE 3072
-
-static int
-calc_start_len(char *buffer, char **start, int requested_offset,
-	       int requested_len, int total, char *buf)
-{
-	int return_len, buffer_len;
-	
-	buffer_len = buf - buffer;
-	if (buffer_len >= PROC_BUFFER_SIZE - 1) {
-		printk(KERN_ERR "calc_start_len: exceeded /proc buffer size\n");
-	}
-	
-	/*
-	 * There may be bytes before and after the
-	 * chunk that was actually requested.
-	 */
-	return_len = total - requested_offset;
-	if (return_len < 0) {
-		return_len = 0;
-	}
-	*start = buf - return_len;
-	if (return_len > requested_len) {
-		return_len = requested_len;
-	}
-	return return_len;
-}
-
 struct {
 	u16 rid;
 	char *name;
@@ -3880,140 +3954,135 @@
 #define DISPLAY_STRING	2
 #define DISPLAY_XSTRING	3
 } record_table[] = {
-#define PROC_REC(name,type) { HERMES_RID_##name, #name, DISPLAY_##type }
-	PROC_REC(CNFPORTTYPE,WORDS),
-	PROC_REC(CNFOWNMACADDR,BYTES),
-	PROC_REC(CNFDESIREDSSID,STRING),
-	PROC_REC(CNFOWNCHANNEL,WORDS),
-	PROC_REC(CNFOWNSSID,STRING),
-	PROC_REC(CNFOWNATIMWINDOW,WORDS),
-	PROC_REC(CNFSYSTEMSCALE,WORDS),
-	PROC_REC(CNFMAXDATALEN,WORDS),
-	PROC_REC(CNFPMENABLED,WORDS),
-	PROC_REC(CNFPMEPS,WORDS),
-	PROC_REC(CNFMULTICASTRECEIVE,WORDS),
-	PROC_REC(CNFMAXSLEEPDURATION,WORDS),
-	PROC_REC(CNFPMHOLDOVERDURATION,WORDS),
-	PROC_REC(CNFOWNNAME,STRING),
-	PROC_REC(CNFOWNDTIMPERIOD,WORDS),
-	PROC_REC(CNFMULTICASTPMBUFFERING,WORDS),
-	PROC_REC(CNFWEPENABLED_AGERE,WORDS),
-	PROC_REC(CNFMANDATORYBSSID_SYMBOL,WORDS),
-	PROC_REC(CNFWEPDEFAULTKEYID,WORDS),
-	PROC_REC(CNFDEFAULTKEY0,BYTES),
-	PROC_REC(CNFDEFAULTKEY1,BYTES),
-	PROC_REC(CNFMWOROBUST_AGERE,WORDS),
-	PROC_REC(CNFDEFAULTKEY2,BYTES),
-	PROC_REC(CNFDEFAULTKEY3,BYTES),
-	PROC_REC(CNFWEPFLAGS_INTERSIL,WORDS),
-	PROC_REC(CNFWEPKEYMAPPINGTABLE,WORDS),
-	PROC_REC(CNFAUTHENTICATION,WORDS),
-	PROC_REC(CNFMAXASSOCSTA,WORDS),
-	PROC_REC(CNFKEYLENGTH_SYMBOL,WORDS),
-	PROC_REC(CNFTXCONTROL,WORDS),
-	PROC_REC(CNFROAMINGMODE,WORDS),
-	PROC_REC(CNFHOSTAUTHENTICATION,WORDS),
-	PROC_REC(CNFRCVCRCERROR,WORDS),
-	PROC_REC(CNFMMLIFE,WORDS),
-	PROC_REC(CNFALTRETRYCOUNT,WORDS),
-	PROC_REC(CNFBEACONINT,WORDS),
-	PROC_REC(CNFAPPCFINFO,WORDS),
-	PROC_REC(CNFSTAPCFINFO,WORDS),
-	PROC_REC(CNFPRIORITYQUSAGE,WORDS),
-	PROC_REC(CNFTIMCTRL,WORDS),
-	PROC_REC(CNFTHIRTY2TALLY,WORDS),
-	PROC_REC(CNFENHSECURITY,WORDS),
-	PROC_REC(CNFGROUPADDRESSES,BYTES),
-	PROC_REC(CNFCREATEIBSS,WORDS),
-	PROC_REC(CNFFRAGMENTATIONTHRESHOLD,WORDS),
-	PROC_REC(CNFRTSTHRESHOLD,WORDS),
-	PROC_REC(CNFTXRATECONTROL,WORDS),
-	PROC_REC(CNFPROMISCUOUSMODE,WORDS),
-	PROC_REC(CNFBASICRATES_SYMBOL,WORDS),
-	PROC_REC(CNFPREAMBLE_SYMBOL,WORDS),
-	PROC_REC(CNFSHORTPREAMBLE,WORDS),
-	PROC_REC(CNFWEPKEYS_AGERE,BYTES),
-	PROC_REC(CNFEXCLUDELONGPREAMBLE,WORDS),
-	PROC_REC(CNFTXKEY_AGERE,WORDS),
-	PROC_REC(CNFAUTHENTICATIONRSPTO,WORDS),
-	PROC_REC(CNFBASICRATES,WORDS),
-	PROC_REC(CNFSUPPORTEDRATES,WORDS),
-	PROC_REC(CNFTICKTIME,WORDS),
-	PROC_REC(CNFSCANREQUEST,WORDS),
-	PROC_REC(CNFJOINREQUEST,WORDS),
-	PROC_REC(CNFAUTHENTICATESTATION,WORDS),
-	PROC_REC(CNFCHANNELINFOREQUEST,WORDS),
-	PROC_REC(MAXLOADTIME,WORDS),
-	PROC_REC(DOWNLOADBUFFER,WORDS),
-	PROC_REC(PRIID,WORDS),
-	PROC_REC(PRISUPRANGE,WORDS),
-	PROC_REC(CFIACTRANGES,WORDS),
-	PROC_REC(NICSERNUM,WORDS),
-	PROC_REC(NICID,WORDS),
-	PROC_REC(MFISUPRANGE,WORDS),
-	PROC_REC(CFISUPRANGE,WORDS),
-	PROC_REC(CHANNELLIST,WORDS),
-	PROC_REC(REGULATORYDOMAINS,WORDS),
-	PROC_REC(TEMPTYPE,WORDS),
-/*  	PROC_REC(CIS,BYTES), */
-	PROC_REC(STAID,WORDS),
-	PROC_REC(CURRENTSSID,STRING),
-	PROC_REC(CURRENTBSSID,BYTES),
-	PROC_REC(COMMSQUALITY,WORDS),
-	PROC_REC(CURRENTTXRATE,WORDS),
-	PROC_REC(CURRENTBEACONINTERVAL,WORDS),
-	PROC_REC(CURRENTSCALETHRESHOLDS,WORDS),
-	PROC_REC(PROTOCOLRSPTIME,WORDS),
-	PROC_REC(SHORTRETRYLIMIT,WORDS),
-	PROC_REC(LONGRETRYLIMIT,WORDS),
-	PROC_REC(MAXTRANSMITLIFETIME,WORDS),
-	PROC_REC(MAXRECEIVELIFETIME,WORDS),
-	PROC_REC(CFPOLLABLE,WORDS),
-	PROC_REC(AUTHENTICATIONALGORITHMS,WORDS),
-	PROC_REC(PRIVACYOPTIONIMPLEMENTED,WORDS),
-	PROC_REC(OWNMACADDR,BYTES),
-	PROC_REC(SCANRESULTSTABLE,WORDS),
-	PROC_REC(PHYTYPE,WORDS),
-	PROC_REC(CURRENTCHANNEL,WORDS),
-	PROC_REC(CURRENTPOWERSTATE,WORDS),
-	PROC_REC(CCAMODE,WORDS),
-	PROC_REC(SUPPORTEDDATARATES,WORDS),
-	PROC_REC(BUILDSEQ,BYTES),
-	PROC_REC(FWID,XSTRING)
-#undef PROC_REC
+#define DEBUG_REC(name,type) { HERMES_RID_##name, #name, DISPLAY_##type }
+	DEBUG_REC(CNFPORTTYPE,WORDS),
+	DEBUG_REC(CNFOWNMACADDR,BYTES),
+	DEBUG_REC(CNFDESIREDSSID,STRING),
+	DEBUG_REC(CNFOWNCHANNEL,WORDS),
+	DEBUG_REC(CNFOWNSSID,STRING),
+	DEBUG_REC(CNFOWNATIMWINDOW,WORDS),
+	DEBUG_REC(CNFSYSTEMSCALE,WORDS),
+	DEBUG_REC(CNFMAXDATALEN,WORDS),
+	DEBUG_REC(CNFPMENABLED,WORDS),
+	DEBUG_REC(CNFPMEPS,WORDS),
+	DEBUG_REC(CNFMULTICASTRECEIVE,WORDS),
+	DEBUG_REC(CNFMAXSLEEPDURATION,WORDS),
+	DEBUG_REC(CNFPMHOLDOVERDURATION,WORDS),
+	DEBUG_REC(CNFOWNNAME,STRING),
+	DEBUG_REC(CNFOWNDTIMPERIOD,WORDS),
+	DEBUG_REC(CNFMULTICASTPMBUFFERING,WORDS),
+	DEBUG_REC(CNFWEPENABLED_AGERE,WORDS),
+	DEBUG_REC(CNFMANDATORYBSSID_SYMBOL,WORDS),
+	DEBUG_REC(CNFWEPDEFAULTKEYID,WORDS),
+	DEBUG_REC(CNFDEFAULTKEY0,BYTES),
+	DEBUG_REC(CNFDEFAULTKEY1,BYTES),
+	DEBUG_REC(CNFMWOROBUST_AGERE,WORDS),
+	DEBUG_REC(CNFDEFAULTKEY2,BYTES),
+	DEBUG_REC(CNFDEFAULTKEY3,BYTES),
+	DEBUG_REC(CNFWEPFLAGS_INTERSIL,WORDS),
+	DEBUG_REC(CNFWEPKEYMAPPINGTABLE,WORDS),
+	DEBUG_REC(CNFAUTHENTICATION,WORDS),
+	DEBUG_REC(CNFMAXASSOCSTA,WORDS),
+	DEBUG_REC(CNFKEYLENGTH_SYMBOL,WORDS),
+	DEBUG_REC(CNFTXCONTROL,WORDS),
+	DEBUG_REC(CNFROAMINGMODE,WORDS),
+	DEBUG_REC(CNFHOSTAUTHENTICATION,WORDS),
+	DEBUG_REC(CNFRCVCRCERROR,WORDS),
+	DEBUG_REC(CNFMMLIFE,WORDS),
+	DEBUG_REC(CNFALTRETRYCOUNT,WORDS),
+	DEBUG_REC(CNFBEACONINT,WORDS),
+	DEBUG_REC(CNFAPPCFINFO,WORDS),
+	DEBUG_REC(CNFSTAPCFINFO,WORDS),
+	DEBUG_REC(CNFPRIORITYQUSAGE,WORDS),
+	DEBUG_REC(CNFTIMCTRL,WORDS),
+	DEBUG_REC(CNFTHIRTY2TALLY,WORDS),
+	DEBUG_REC(CNFENHSECURITY,WORDS),
+	DEBUG_REC(CNFGROUPADDRESSES,BYTES),
+	DEBUG_REC(CNFCREATEIBSS,WORDS),
+	DEBUG_REC(CNFFRAGMENTATIONTHRESHOLD,WORDS),
+	DEBUG_REC(CNFRTSTHRESHOLD,WORDS),
+	DEBUG_REC(CNFTXRATECONTROL,WORDS),
+	DEBUG_REC(CNFPROMISCUOUSMODE,WORDS),
+	DEBUG_REC(CNFBASICRATES_SYMBOL,WORDS),
+	DEBUG_REC(CNFPREAMBLE_SYMBOL,WORDS),
+	DEBUG_REC(CNFSHORTPREAMBLE,WORDS),
+	DEBUG_REC(CNFWEPKEYS_AGERE,BYTES),
+	DEBUG_REC(CNFEXCLUDELONGPREAMBLE,WORDS),
+	DEBUG_REC(CNFTXKEY_AGERE,WORDS),
+	DEBUG_REC(CNFAUTHENTICATIONRSPTO,WORDS),
+	DEBUG_REC(CNFBASICRATES,WORDS),
+	DEBUG_REC(CNFSUPPORTEDRATES,WORDS),
+	DEBUG_REC(CNFTICKTIME,WORDS),
+	DEBUG_REC(CNFSCANREQUEST,WORDS),
+	DEBUG_REC(CNFJOINREQUEST,WORDS),
+	DEBUG_REC(CNFAUTHENTICATESTATION,WORDS),
+	DEBUG_REC(CNFCHANNELINFOREQUEST,WORDS),
+	DEBUG_REC(MAXLOADTIME,WORDS),
+	DEBUG_REC(DOWNLOADBUFFER,WORDS),
+	DEBUG_REC(PRIID,WORDS),
+	DEBUG_REC(PRISUPRANGE,WORDS),
+	DEBUG_REC(CFIACTRANGES,WORDS),
+	DEBUG_REC(NICSERNUM,XSTRING),
+	DEBUG_REC(NICID,WORDS),
+	DEBUG_REC(MFISUPRANGE,WORDS),
+	DEBUG_REC(CFISUPRANGE,WORDS),
+	DEBUG_REC(CHANNELLIST,WORDS),
+	DEBUG_REC(REGULATORYDOMAINS,WORDS),
+	DEBUG_REC(TEMPTYPE,WORDS),
+/*  	DEBUG_REC(CIS,BYTES), */
+	DEBUG_REC(STAID,WORDS),
+	DEBUG_REC(CURRENTSSID,STRING),
+	DEBUG_REC(CURRENTBSSID,BYTES),
+	DEBUG_REC(COMMSQUALITY,WORDS),
+	DEBUG_REC(CURRENTTXRATE,WORDS),
+	DEBUG_REC(CURRENTBEACONINTERVAL,WORDS),
+	DEBUG_REC(CURRENTSCALETHRESHOLDS,WORDS),
+	DEBUG_REC(PROTOCOLRSPTIME,WORDS),
+	DEBUG_REC(SHORTRETRYLIMIT,WORDS),
+	DEBUG_REC(LONGRETRYLIMIT,WORDS),
+	DEBUG_REC(MAXTRANSMITLIFETIME,WORDS),
+	DEBUG_REC(MAXRECEIVELIFETIME,WORDS),
+	DEBUG_REC(CFPOLLABLE,WORDS),
+	DEBUG_REC(AUTHENTICATIONALGORITHMS,WORDS),
+	DEBUG_REC(PRIVACYOPTIONIMPLEMENTED,WORDS),
+	DEBUG_REC(OWNMACADDR,BYTES),
+	DEBUG_REC(SCANRESULTSTABLE,WORDS),
+	DEBUG_REC(PHYTYPE,WORDS),
+	DEBUG_REC(CURRENTCHANNEL,WORDS),
+	DEBUG_REC(CURRENTPOWERSTATE,WORDS),
+	DEBUG_REC(CCAMODE,WORDS),
+	DEBUG_REC(SUPPORTEDDATARATES,WORDS),
+	DEBUG_REC(BUILDSEQ,BYTES),
+	DEBUG_REC(FWID,XSTRING)
+#undef DEBUG_REC
 };
-#define NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) )
 
-static int
-orinoco_proc_get_hermes_recs(char *page, char **start, off_t requested_offset,
-			   int requested_len, int *eof, void *data)
+#define DEBUG_LTV_SIZE		128
+
+static int orinoco_debug_dump_recs(struct net_device *dev)
 {
-	struct orinoco_private *priv = (struct orinoco_private *)data;
-	struct net_device *dev = priv->ndev;
+	struct orinoco_private *priv = dev->priv;
 	hermes_t *hw = &priv->hw;
-	char *buf = page;
-	int total = 0, slop = 0;
 	u8 *val8;
 	u16 *val16;
 	int i,j;
 	u16 length;
 	int err;
 
-	if (! netif_device_present(dev))
-		return -ENODEV;
-
-	val8 = kmalloc(PROC_LTV_SIZE + 2, GFP_KERNEL);
+	/* I'm not sure: we might have a lock here, so we'd better go
+           atomic, just in case. */
+	val8 = kmalloc(DEBUG_LTV_SIZE + 2, GFP_ATOMIC);
 	if (! val8)
 		return -ENOMEM;
 	val16 = (u16 *)val8;
 
-	for (i = 0; i < NUM_RIDS; i++) {
+	for (i = 0; i < ARRAY_SIZE(record_table); i++) {
 		u16 rid = record_table[i].rid;
 		int len;
 
-		memset(val8, 0, PROC_LTV_SIZE + 2);
+		memset(val8, 0, DEBUG_LTV_SIZE + 2);
 
-		err = hermes_read_ltv(hw, USER_BAP, rid, PROC_LTV_SIZE,
+		err = hermes_read_ltv(hw, USER_BAP, rid, DEBUG_LTV_SIZE,
 				      &length, val8);
 		if (err) {
 			DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid);
@@ -4023,190 +4092,39 @@
 		if (length == 0)
 			continue;
 
-		buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name,
-			       rid, length, (length-1)*2);
-		len = min(((int)length-1)*2, PROC_LTV_SIZE);
+		printk(KERN_DEBUG "%-15s (0x%04x): length=%d (%d bytes)\tvalue=",
+		       record_table[i].name,
+		       rid, length, (length-1)*2);
+		len = min(((int)length-1)*2, DEBUG_LTV_SIZE);
 
 		switch (record_table[i].displaytype) {
 		case DISPLAY_WORDS:
-			for (j = 0; j < len / 2; j++) {
-				buf += sprintf(buf, "%04X-", le16_to_cpu(val16[j]));
-			}
-			buf--;
+			for (j = 0; j < len / 2; j++)
+				printk("%04X-", le16_to_cpu(val16[j]));
 			break;
 
 		case DISPLAY_BYTES:
 		default:
-			for (j = 0; j < len; j++) {
-				buf += sprintf(buf, "%02X:", val8[j]);
-			}
-			buf--;
+			for (j = 0; j < len; j++)
+				printk("%02X:", val8[j]);
 			break;
 
 		case DISPLAY_STRING:
 			len = min(len, le16_to_cpu(val16[0])+2);
 			val8[len] = '\0';
-			buf += sprintf(buf, "\"%s\"", (char *)&val16[1]);
+			printk("\"%s\"", (char *)&val16[1]);
 			break;
 
 		case DISPLAY_XSTRING:
-			buf += sprintf(buf, "'%s'", (char *)val8);
+			printk("'%s'", (char *)val8);
 		}
 
-		buf += sprintf(buf, "\n");
-
-		if (shift_buffer(page, requested_offset, requested_len,
-				 &total, &slop, &buf))
-			break;
-
-		if ( (buf - page) > PROC_SAFE_SIZE )
-			break;
+		printk("\n");
 	}
 
 	kfree(val8);
 
-	return calc_start_len(page, start, requested_offset, requested_len,
-			      total, buf);
-}
-
-#ifdef HERMES_DEBUG_BUFFER
-static int
-orinoco_proc_get_hermes_buf(char *page, char **start, off_t requested_offset,
-			    int requested_len, int *eof, void *data)
-{
-	struct orinoco_private *priv = (struct orinoco_private *)data;
-	hermes_t *hw = &priv->hw;
-	char *buf = page;
-	int total = 0, slop = 0;
-	int i;
-
-	for (i = 0; i < min_t(int,hw->dbufp, HERMES_DEBUG_BUFSIZE); i++) {
-		memcpy(buf, &hw->dbuf[i], sizeof(hw->dbuf[i]));
-		buf += sizeof(hw->dbuf[i]);
-
-		if (shift_buffer(page, requested_offset, requested_len,
-				 &total, &slop, &buf))
-			break;
-
-		if ( (buf - page) > PROC_SAFE_SIZE )
-			break;
-	}
-
-	return calc_start_len(page, start, requested_offset, requested_len,
-			      total, buf);
-}
-
-static int
-orinoco_proc_get_hermes_prof(char *page, char **start, off_t requested_offset,
-			    int requested_len, int *eof, void *data)
-{
-	struct orinoco_private *priv = (struct orinoco_private *)data;
-	hermes_t *hw = &priv->hw;
-	char *buf = page;
-	int total = 0, slop = 0;
-	int i;
-
-	for (i = 0; i < (HERMES_BAP_BUSY_TIMEOUT+1); i++) {
-		memcpy(buf, &hw->profile[i], sizeof(hw->profile[i]));
-		buf += sizeof(hw->profile[i]);
-
-		if (shift_buffer(page, requested_offset, requested_len,
-				 &total, &slop, &buf))
-			break;
-
-		if ( (buf - page) > PROC_SAFE_SIZE )
-			break;
-	}
-
-	return calc_start_len(page, start, requested_offset, requested_len,
-			      total, buf);
-}
-#endif /* HERMES_DEBUG_BUFFER */
-
-/* initialise the /proc subsystem for the hermes driver, creating the
- * separate entries */
-static int
-orinoco_proc_init(void)
-{
-	int err = 0;
-
-	/* create the directory for it to sit in */
-	dir_base = create_proc_entry("hermes", S_IFDIR, &proc_root);
-	if (dir_base == NULL) {
-		printk(KERN_ERR "Unable to initialise /proc/hermes.\n");
-		orinoco_proc_cleanup();
-		err = -ENOMEM;
-	}
-
-	return err;
-}
-
-int
-orinoco_proc_dev_init(struct net_device *dev)
-{
-	struct orinoco_private *priv = dev->priv;
-	struct proc_dir_entry *e;
-
-	priv->dir_dev = NULL;
-
-	/* create the directory for it to sit in */
-	priv->dir_dev = create_proc_entry(dev->name, S_IFDIR | S_IRUGO | S_IXUGO,
-					  dir_base);
-	if (! priv->dir_dev) {
-		printk(KERN_ERR "Unable to initialize /proc/hermes/%s\n",  dev->name);
-		goto fail;
-	}
-
-	e = create_proc_read_entry("recs", S_IFREG | S_IRUGO,
-			       priv->dir_dev, orinoco_proc_get_hermes_recs, priv);
-	if (! e) {
-		printk(KERN_ERR "Unable to initialize /proc/hermes/%s/recs\n",  dev->name);
-		goto fail;
-	}
-
-#ifdef HERMES_DEBUG_BUFFER
-	e = create_proc_read_entry("buf", S_IFREG | S_IRUGO,
-					       priv->dir_dev, orinoco_proc_get_hermes_buf, priv);
-	if (! e) {
-		printk(KERN_ERR "Unable to initialize /proc/hermes/%s/buf\n", dev->name);
-		goto fail;
-	}
-
-	e = create_proc_read_entry("prof", S_IFREG | S_IRUGO,
-					       priv->dir_dev, orinoco_proc_get_hermes_prof, priv);
-	if (! e) {
-		printk(KERN_ERR "Unable to intialize /proc/hermes/%s/prof\n", dev->name);
-		goto fail;
-	}
-#endif /* HERMES_DEBUG_BUFFER */
-
 	return 0;
- fail:
-	orinoco_proc_dev_cleanup(dev);
-	return -ENOMEM;
-}
-
-void
-orinoco_proc_dev_cleanup(struct net_device *dev)
-{
-	struct orinoco_private *priv = dev->priv;
-
-	if (priv->dir_dev) {
-		remove_proc_entry("prof", priv->dir_dev);
-		remove_proc_entry("buf", priv->dir_dev);
-		remove_proc_entry("recs", priv->dir_dev);
-		remove_proc_entry(dev->name, dir_base);
-		priv->dir_dev = NULL;
-	}
-}
-
-static void
-orinoco_proc_cleanup(void)
-{
-	if (dir_base) {
-		remove_proc_entry("hermes", &proc_root);
-		dir_base = NULL;
-	}
 }
 
 struct net_device *alloc_orinocodev(int sizeof_card, int (*hard_reset)(struct orinoco_private *))
@@ -4232,6 +4150,7 @@
 	dev->do_ioctl = orinoco_ioctl;
 	dev->change_mtu = orinoco_change_mtu;
 	dev->set_multicast_list = orinoco_set_multicast_list;
+	/* we use the default eth_mac_addr for setting the MAC addr */
 
 	/* Set up default callbacks */
 	dev->open = orinoco_open;
@@ -4243,7 +4162,10 @@
 	priv->hw_unavailable = 1; /* orinoco_init() must clear this
 				   * before anything else touches the
 				   * hardware */
-	INIT_WORK(&priv->timeout_task, (void (*)(void *))orinoco_reset, dev);
+	INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev);
+
+	priv->last_linkstatus = 0xffff;
+	priv->connected = 0;
 
 	return dev;
 
@@ -4257,25 +4179,23 @@
 
 EXPORT_SYMBOL(__orinoco_up);
 EXPORT_SYMBOL(__orinoco_down);
+EXPORT_SYMBOL(orinoco_stop);
 EXPORT_SYMBOL(orinoco_reinit_firmware);
 
-EXPORT_SYMBOL(orinoco_proc_dev_init);
-EXPORT_SYMBOL(orinoco_proc_dev_cleanup);
 EXPORT_SYMBOL(orinoco_interrupt);
 
 /* Can't be declared "const" or the whole __initdata section will
  * become const */
-static char version[] __initdata = "orinoco.c 0.13a (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+static char version[] __initdata = "orinoco.c 0.13e (David Gibson <hermes@gibson.dropbear.id.au> and others)";
 
 static int __init init_orinoco(void)
 {
 	printk(KERN_DEBUG "%s\n", version);
-	return orinoco_proc_init();
+	return 0;
 }
 
 static void __exit exit_orinoco(void)
 {
-	orinoco_proc_cleanup();
 }
 
 module_init(init_orinoco);
diff -Nru a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
--- a/drivers/net/wireless/orinoco.h	Sun Apr 20 23:39:12 2003
+++ b/drivers/net/wireless/orinoco.h	Tue May 27 00:17:28 2003
@@ -11,9 +11,29 @@
 #include <linux/spinlock.h>
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
-#include <linux/workqueue.h>
+#include <linux/version.h>
 #include "hermes.h"
 
+/* Workqueue / task queue backwards compatibility stuff */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
+#include <linux/workqueue.h>
+#else
+#include <linux/tqueue.h>
+#define work_struct tq_struct
+#define INIT_WORK INIT_TQUEUE
+#define schedule_work schedule_task
+#endif
+
+/* Interrupt handler backwards compatibility stuff */
+#ifndef IRQ_NONE
+
+#define IRQ_NONE
+#define IRQ_HANDLED
+typedef void irqreturn_t;
+
+#endif
+
 /* To enable debug messages */
 //#define ORINOCO_DEBUG		3
 
@@ -42,9 +62,12 @@
 	/* Synchronisation stuff */
 	spinlock_t lock;
 	int hw_unavailable;
-	struct work_struct timeout_task;
+	struct work_struct reset_work;
 
+	/* driver state */
 	int open;
+	u16 last_linkstatus;
+	int connected;
 
 	/* Net device stuff */
 	struct net_device *ndev;
@@ -55,6 +78,7 @@
 	hermes_t hw;
 	u16 txfid;
 
+
 	/* Capabilities of the hardware/firmware */
 	int firmware_type;
 #define FIRMWARE_TYPE_AGERE 1
@@ -68,6 +92,7 @@
 	int has_sensitivity;
 	int nicbuf_size;
 	u16 channel_mask;
+	int broken_disableport;
 
 	/* Configuration paramaters */
 	u32 iw_mode;
@@ -91,9 +116,6 @@
 	/* Configuration dependent variables */
 	int port_type, createibss;
 	int promiscuous, mc_count;
-
-	/* /proc based debugging stuff */
-	struct proc_dir_entry *dir_dev;
 };
 
 #ifdef ORINOCO_DEBUG
@@ -110,10 +132,8 @@
 					   int (*hard_reset)(struct orinoco_private *));
 extern int __orinoco_up(struct net_device *dev);
 extern int __orinoco_down(struct net_device *dev);
-int orinoco_reinit_firmware(struct net_device *dev);
-
-extern int orinoco_proc_dev_init(struct net_device *dev);
-extern void orinoco_proc_dev_cleanup(struct net_device *dev);
+extern int orinoco_stop(struct net_device *dev);
+extern int orinoco_reinit_firmware(struct net_device *dev);
 extern irqreturn_t orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs);
 
 /********************************************************************/
diff -Nru a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
--- a/drivers/net/wireless/orinoco_cs.c	Sat Mar 29 06:00:21 2003
+++ b/drivers/net/wireless/orinoco_cs.c	Tue May 27 00:30:00 2003
@@ -1,4 +1,4 @@
-/* orinoco_cs.c 0.13a	- (formerly known as dldwd_cs.c)
+/* orinoco_cs.c 0.13e	- (formerly known as dldwd_cs.c)
  *
  * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
  * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
@@ -14,6 +14,7 @@
 #ifdef  __IN_PCMCIA_PACKAGE__
 #include <pcmcia/k_compat.h>
 #endif /* __IN_PCMCIA_PACKAGE__ */
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -21,9 +22,7 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/string.h>
-#include <linux/timer.h>
 #include <linux/ioport.h>
-#include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
@@ -90,8 +89,9 @@
 	dev_node_t node;
 
 	/* Used to handle hard reset */
-	wait_queue_head_t hard_reset_queue;
-	int hard_reset_flag;
+	/* yuck, we need this hack to work around the insanity of the
+         * PCMCIA layer */
+	unsigned long hard_reset_in_progress; 
 };
 
 /*
@@ -128,14 +128,14 @@
 	dev_link_t *link = &card->link;
 	int err;
 
-	card->hard_reset_flag = 0;
+	/* We need atomic ops here, because we're not holding the lock */
+	set_bit(0, &card->hard_reset_in_progress);
 
 	err = CardServices(ResetCard, link->handle, NULL);
 	if (err)
 		return err;
 
-	wait_event_interruptible(card->hard_reset_queue,
-				 card->hard_reset_flag);
+	clear_bit(0, &card->hard_reset_in_progress);
 
 	return 0;
 }
@@ -144,6 +144,16 @@
 /* PCMCIA stuff     						    */
 /********************************************************************/
 
+/* In 2.5 (as of 2.5.69 at least) there is a cs_error exported which
+ * does this, but it's not in 2.4 so we do our own for now. */
+static void
+orinoco_cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+	CardServices(ReportError, handle, &err);
+}
+
+
 /* Remove zombie instances (card removed, detach pending) */
 static void
 flush_stale_links(void)
@@ -187,7 +197,6 @@
 		return NULL;
 	priv = dev->priv;
 	card = priv->card;
-	init_waitqueue_head(&card->hard_reset_queue);
 
 	/* Link both structures together */
 	link = &card->link;
@@ -233,7 +242,7 @@
 
 	ret = CardServices(RegisterClient, &link->handle, &client_reg);
 	if (ret != CS_SUCCESS) {
-		cs_error(link->handle, RegisterClient, ret);
+		orinoco_cs_error(link->handle, RegisterClient, ret);
 		orinoco_cs_detach(link);
 		return NULL;
 	}
@@ -262,19 +271,12 @@
 		return;
 	}
 
-	/*
-	   If the device is currently configured and active, we won't
-	   actually delete it yet.  Instead, it is marked so that when
-	   the release() function is called, that will trigger a proper
-	   detach().
-	 */
 	if (link->state & DEV_CONFIG) {
-#ifdef PCMCIA_DEBUG
-		printk(KERN_DEBUG "orinoco_cs: detach postponed, '%s' "
-		       "still locked\n", link->dev->dev_name);
-#endif
-		link->state |= DEV_STALE_LINK;
-		return;
+		orinoco_cs_release((u_long)link);
+		if (link->state & DEV_CONFIG) {
+			link->state |= DEV_STALE_LINK;
+			return;
+		}
 	}
 
 	/* Break the link with Card Services */
@@ -465,7 +467,7 @@
 				link->irq.IRQInfo2 |= 1 << irq_list[i];
 		
   		link->irq.Handler = orinoco_interrupt; 
-  		link->irq.Instance = priv; 
+  		link->irq.Instance = dev; 
 		
 		CS_CHECK(RequestIRQ, link->handle, &link->irq);
 	}
@@ -522,18 +524,10 @@
 		       link->io.BasePort2 + link->io.NumPorts2 - 1);
 	printk("\n");
 
-	/* And give us the proc nodes for debugging */
-	if (orinoco_proc_dev_init(dev) != 0) {
-		printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n",
-		       dev->name);
-		goto failed;
-	}
-	
-
 	return;
 
  cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
+	orinoco_cs_error(link->handle, last_fn, last_ret);
 
  failed:
 	orinoco_cs_release((u_long) link);
@@ -550,21 +544,13 @@
 	dev_link_t *link = (dev_link_t *) arg;
 	struct net_device *dev = link->priv;
 	struct orinoco_private *priv = dev->priv;
+	unsigned long flags;
 
-	/*
-	   If the device is currently in use, we won't release until it
-	   is actually closed, because until then, we can't be sure that
-	   no one will try to access the device or its data structures.
-	 */
-	if (priv->open) {
-		DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n",
-		      link->dev->dev_name);
-		link->state |= DEV_STALE_CONFIG;
-		return;
-	}
-
-	/* Unregister proc entry */
-	orinoco_proc_dev_cleanup(dev);
+	/* We're committed to taking the device away now, so mark the
+	 * hardware as unavailable */
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->hw_unavailable++;
+	spin_unlock_irqrestore(&priv->lock, flags);
 
 	/* Don't bother checking to see if these succeed or not */
 	CardServices(ReleaseConfiguration, link->handle);
@@ -586,6 +572,7 @@
 	dev_link_t *link = args->client_data;
 	struct net_device *dev = link->priv;
 	struct orinoco_private *priv = dev->priv;
+	struct orinoco_pccard *card = priv->card;
 	int err = 0;
 	unsigned long flags;
 
@@ -596,14 +583,9 @@
 			orinoco_lock(priv, &flags);
 
 			netif_device_detach(dev);
-			priv->hw_unavailable = 1;
+			priv->hw_unavailable++;
 
 			orinoco_unlock(priv, &flags);
-
-/*  			if (link->open) */
-/*  				orinoco_cs_stop(dev); */
-
-			mod_timer(&link->release, jiffies + HZ / 20);
 		}
 		break;
 
@@ -618,24 +600,24 @@
 	case CS_EVENT_RESET_PHYSICAL:
 		/* Mark the device as stopped, to block IO until later */
 		if (link->state & DEV_CONFIG) {
-			err = orinoco_lock(priv, &flags);
-			if (err) {
-				printk(KERN_ERR "%s: hw_unavailable on SUSPEND/RESET_PHYSICAL\n",
-				       dev->name);
-				break;
-			}
-
-			err = __orinoco_down(dev);
-			if (err)
-				printk(KERN_WARNING "%s: %s: Error %d downing interface\n",
-				       dev->name,
-				       event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL",
-				       err);
+			/* This is probably racy, but I can't think of
+                           a better way, short of rewriting the PCMCIA
+                           layer to not suck :-( */
+			if (! test_bit(0, &card->hard_reset_in_progress)) {
+				spin_lock_irqsave(&priv->lock, flags);
 
-			netif_device_detach(dev);
-			priv->hw_unavailable = 1;
+				err = __orinoco_down(dev);
+				if (err)
+					printk(KERN_WARNING "%s: %s: Error %d downing interface\n",
+					       dev->name,
+					       event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL",
+					       err);
+				
+				netif_device_detach(dev);
+				priv->hw_unavailable++;
 
-			orinoco_unlock(priv, &flags);
+				spin_unlock_irqrestore(&priv->lock, flags);
+			}
 
 			CardServices(ReleaseConfiguration, link->handle);
 		}
@@ -646,32 +628,34 @@
 		/* Fall through... */
 	case CS_EVENT_CARD_RESET:
 		if (link->state & DEV_CONFIG) {
-			CardServices(RequestConfiguration, link->handle,
-				     &link->conf);
-
 			/* FIXME: should we double check that this is
 			 * the same card as we had before */
-			err = orinoco_reinit_firmware(dev);
-			if (err) {
-				printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
-				       dev->name, err);
-				break;
-			}
-
-			spin_lock_irqsave(&priv->lock, flags);
-
-			netif_device_attach(dev);
-			priv->hw_unavailable = 0;
+			CardServices(RequestConfiguration, link->handle,
+				     &link->conf);
 
-			if (priv->open) {
-				err = __orinoco_up(dev);
-				if (err)
-					printk(KERN_ERR "%s: Error %d restarting card\n",
+			if (! test_bit(0, &card->hard_reset_in_progress)) {
+				err = orinoco_reinit_firmware(dev);
+				if (err) {
+					printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
 					       dev->name, err);
+					break;
+				}
+				
+				spin_lock_irqsave(&priv->lock, flags);
+				
+				netif_device_attach(dev);
+				priv->hw_unavailable--;
+				
+				if (priv->open && ! priv->hw_unavailable) {
+					err = __orinoco_up(dev);
+					if (err)
+						printk(KERN_ERR "%s: Error %d restarting card\n",
+						       dev->name, err);
+					
+				}
 
+				spin_unlock_irqrestore(&priv->lock, flags);
 			}
-
-			orinoco_unlock(priv, &flags);
 		}
 		break;
 	}
@@ -685,7 +669,7 @@
 
 /* Can't be declared "const" or the whole __initdata section will
  * become const */
-static char version[] __initdata = "orinoco_cs.c 0.13a (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+static char version[] __initdata = "orinoco_cs.c 0.13e (David Gibson <hermes@gibson.dropbear.id.au> and others)";
 
 static struct pcmcia_driver orinoco_driver = {
 	.owner		= THIS_MODULE,
@@ -712,7 +696,6 @@
 	if (dev_list)
 		DEBUG(0, "orinoco_cs: Removing leftover devices.\n");
 	while (dev_list != NULL) {
-		del_timer(&dev_list->release);
 		if (dev_list->state & DEV_CONFIG)
 			orinoco_cs_release((u_long) dev_list);
 		orinoco_cs_detach(dev_list);
diff -Nru a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
--- a/drivers/net/wireless/orinoco_pci.c	Thu Nov 21 14:06:13 2002
+++ b/drivers/net/wireless/orinoco_pci.c	Tue May 27 00:17:28 2003
@@ -1,4 +1,4 @@
-/* orinoco_pci.c 0.13a
+/* orinoco_pci.c 0.13e
  * 
  * Driver for Prism II devices that have a direct PCI interface
  * (i.e., not in a Pcmcia or PLX bridge)
@@ -10,8 +10,10 @@
  * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
  * has been copied from it. linux-wlan-ng-0.1.10 is originally :
  *	Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
- * The rest is :
+ * This file originally written by:
  *	Copyright (C) 2001 Jean Tourrilhes <jt@hpl.hp.com>
+ * And is now maintained by:
+ *	Copyright (C) 2002 David Gibson, IBM Corporation <herme@gibson.dropbear.id.au>
  *
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License"); you may not use this file except in
@@ -84,6 +86,7 @@
  */
 
 #include <linux/config.h>
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -93,7 +96,6 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/ioport.h>
-#include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
@@ -142,8 +144,6 @@
 	unsigned long	timeout;
 	u16	reg;
 
-	TRACE_ENTER(priv->ndev->name);
-
 	/* Assert the reset until the card notice */
 	hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
 	printk(KERN_NOTICE "Reset done");
@@ -180,8 +180,6 @@
 	}
 	printk(KERN_NOTICE "pci_cor : reg = 0x%X - %lX - %lX\n", reg, timeout, jiffies);
 
-	TRACE_EXIT(priv->ndev->name);
-
 	return 0;
 }
 
@@ -197,7 +195,6 @@
 	unsigned long pci_iolen;
 	struct orinoco_private *priv = NULL;
 	struct net_device *dev = NULL;
-	int netdev_registered = 0;
 
 	err = pci_enable_device(pdev);
 	if (err)
@@ -218,9 +215,9 @@
 	}
 	priv = dev->priv;
 
-	dev->base_addr = (int) pci_ioaddr;
-        dev->mem_start = (unsigned long) pci_iorange;
-        dev->mem_end = ((unsigned long) pci_iorange) + pci_iolen - 1;
+	dev->base_addr = (unsigned long) pci_ioaddr;
+	dev->mem_start = pci_iorange;
+	dev->mem_end = pci_iorange + pci_iolen - 1;
 
 	SET_MODULE_OWNER(dev);
 
@@ -228,12 +225,15 @@
 	       "Detected Orinoco/Prism2 PCI device at %s, mem:0x%lX to 0x%lX -> 0x%p, irq:%d\n",
 	       pdev->slot_name, dev->mem_start, dev->mem_end, pci_ioaddr, pdev->irq);
 
-	hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_MEM, HERMES_32BIT_REGSPACING);
+	hermes_struct_init(&priv->hw, dev->base_addr,
+			   HERMES_MEM, HERMES_32BIT_REGSPACING);
 	pci_set_drvdata(pdev, dev);
 
-	err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, priv);
+	err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
+			  dev->name, dev);
 	if (err) {
-		printk(KERN_ERR "orinoco_pci: Error allocating IRQ %d.\n", pdev->irq);
+		printk(KERN_ERR "orinoco_pci: Error allocating IRQ %d.\n",
+		       pdev->irq);
 		err = -EBUSY;
 		goto fail;
 	}
@@ -254,24 +254,12 @@
 		printk(KERN_ERR "%s: Failed to register net device\n", dev->name);
 		goto fail;
 	}
-	netdev_registered = 1;
-
-	err = orinoco_proc_dev_init(dev);
-	if (err) {
-		printk(KERN_ERR "%s: Failed to create /proc node\n", dev->name);
-		err = -EIO;
-		goto fail;
-	}
 
         return 0;               /* succeeded */
  fail:
 	if (dev) {
-		orinoco_proc_dev_cleanup(dev);
-		if (netdev_registered)
-			unregister_netdev(dev);
-
 		if (dev->irq)
-			free_irq(dev->irq, priv);
+			free_irq(dev->irq, dev);
 
 		kfree(dev);
 	}
@@ -279,6 +267,8 @@
 	if (pci_ioaddr)
 		iounmap(pci_ioaddr);
 
+	pci_disable_device(pdev);
+
 	return err;
 }
 
@@ -290,21 +280,85 @@
 	if (! dev)
 		BUG();
 
-	orinoco_proc_dev_cleanup(dev);
-
 	unregister_netdev(dev);
 
         if (dev->irq)
-		free_irq(dev->irq, priv);
+		free_irq(dev->irq, dev);
 
 	if (priv->hw.iobase)
 		iounmap((unsigned char *) priv->hw.iobase);
 
+	pci_set_drvdata(pdev, NULL);
 	kfree(dev);
 
 	pci_disable_device(pdev);
 }
 
+static int orinoco_pci_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct orinoco_private *priv = dev->priv;
+	unsigned long flags;
+	int err;
+	
+	printk(KERN_DEBUG "%s: Orinoco-PCI entering sleep mode (state=%d)\n",
+	       dev->name, state);
+
+	err = orinoco_lock(priv, &flags);
+	if (err) {
+		printk(KERN_ERR "%s: hw_unavailable on orinoco_pci_suspend\n",
+		       dev->name);
+		return err;
+	}
+
+	err = __orinoco_down(dev);
+	if (err)
+		printk(KERN_WARNING "%s: orinoco_pci_suspend(): Error %d downing interface\n",
+		       dev->name, err);
+	
+	netif_device_detach(dev);
+
+	priv->hw_unavailable++;
+	
+	orinoco_unlock(priv, &flags);
+
+	return 0;
+}
+
+static int orinoco_pci_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct orinoco_private *priv = dev->priv;
+	unsigned long flags;
+	int err;
+
+	printk(KERN_DEBUG "%s: Orinoco-PCI waking up\n", dev->name);
+
+	err = orinoco_reinit_firmware(dev);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d re-initializing firmware on orinoco_pci_resume()\n",
+		       dev->name, err);
+		return err;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	netif_device_attach(dev);
+
+	priv->hw_unavailable--;
+
+	if (priv->open && (! priv->hw_unavailable)) {
+		err = __orinoco_up(dev);
+		if (err)
+			printk(KERN_ERR "%s: Error %d restarting card on orinoco_pci_resume()\n",
+			       dev->name, err);
+	}
+	
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
 static struct pci_device_id orinoco_pci_pci_id_table[] __devinitdata = {
 	{0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
 	{0,},
@@ -317,12 +371,12 @@
 	.id_table	= orinoco_pci_pci_id_table,
 	.probe		= orinoco_pci_init_one,
 	.remove		= __devexit_p(orinoco_pci_remove_one),
-	.suspend	= 0,
-	.resume		= 0
+	.suspend	= orinoco_pci_suspend,
+	.resume		= orinoco_pci_resume,
 };
 
-static char version[] __initdata = "orinoco_pci.c 0.13a (Jean Tourrilhes <jt@hpl.hp.com>)";
-MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>");
+static char version[] __initdata = "orinoco_pci.c 0.13e (David Gibson <hermes@gibson.dropbear.id.au> & Jean Tourrilhes <jt@hpl.hp.com>)";
+MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
 MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface");
 MODULE_LICENSE("Dual MPL/GPL");
 
diff -Nru a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
--- a/drivers/net/wireless/orinoco_plx.c	Sun Sep 29 21:46:30 2002
+++ b/drivers/net/wireless/orinoco_plx.c	Tue May 27 00:17:28 2003
@@ -1,4 +1,4 @@
-/* orinoco_plx.c 0.13a
+/* orinoco_plx.c 0.13e
  * 
  * Driver for Prism II devices which would usually be driven by orinoco_cs,
  * but are connected to the PCI bus by a PLX9052. 
@@ -119,7 +119,6 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#include <linux/proc_fs.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
@@ -156,7 +155,6 @@
 	unsigned long pccard_ioaddr = 0;
 	unsigned long pccard_iolen = 0;
 	struct net_device *dev = NULL;
-	int netdev_registered = 0;
 	int i;
 
 	err = pci_enable_device(pdev);
@@ -201,7 +199,7 @@
 	addr = pci_resource_start(pdev, 1);
 	reg = 0;
 	reg = inl(addr+PLX_INTCSR);
-	if(reg & PLX_INTCSR_INTEN)
+	if (reg & PLX_INTCSR_INTEN)
 		printk(KERN_DEBUG "orinoco_plx: "
 		       "Local Interrupt already enabled\n");
 	else {
@@ -244,7 +242,7 @@
 			HERMES_IO, HERMES_16BIT_REGSPACING);
 	pci_set_drvdata(pdev, dev);
 
-	err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, priv);
+	err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, dev);
 	if (err) {
 		printk(KERN_ERR "orinoco_plx: Error allocating IRQ %d.\n", pdev->irq);
 		err = -EBUSY;
@@ -255,27 +253,17 @@
 	err = register_netdev(dev);
 	if (err)
 		goto fail;
-	netdev_registered = 1;
-
-	err = orinoco_proc_dev_init(dev);
-	if (err)
-		goto fail;
 
 	return 0;		/* succeeded */
 
  fail:	
 	printk(KERN_DEBUG "orinoco_plx: init_one(), FAIL!\n");
 
-	if (priv) {
-		orinoco_proc_dev_cleanup(dev);
-
-		if (netdev_registered)
-			unregister_netdev(dev);
-		
+	if (dev) {
 		if (dev->irq)
-			free_irq(dev->irq, priv);
+			free_irq(dev->irq, dev);
 		
-		kfree(priv);
+		kfree(dev);
 	}
 
 	if (pccard_ioaddr)
@@ -292,18 +280,17 @@
 static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct orinoco_private *priv = dev->priv;
 
 	if (! dev)
 		BUG();
 
-	orinoco_proc_dev_cleanup(dev);
-
 	unregister_netdev(dev);
 		
 	if (dev->irq)
-		free_irq(dev->irq, priv);
+		free_irq(dev->irq, dev);
 		
+	pci_set_drvdata(pdev, NULL);
+
 	kfree(dev);
 
 	release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
@@ -341,7 +328,7 @@
 	.resume		= 0,
 };
 
-static char version[] __initdata = "orinoco_plx.c 0.13a (Daniel Barlow <dan@telent.net>, David Gibson <hermes@gibson.dropbear.id.au>)";
+static char version[] __initdata = "orinoco_plx.c 0.13e (Daniel Barlow <dan@telent.net>, David Gibson <hermes@gibson.dropbear.id.au>)";
 MODULE_AUTHOR("Daniel Barlow <dan@telent.net>");
 MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge");
 #ifdef MODULE_LICENSE
diff -Nru a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/orinoco_tmd.c	Tue May 27 10:17:28 2003
@@ -0,0 +1,238 @@
+/* orinoco_tmd.c 0.01
+ * 
+ * Driver for Prism II devices which would usually be driven by orinoco_cs,
+ * but are connected to the PCI bus by a TMD7160. 
+ *
+ * Copyright (C) 2003 Joerg Dorchain <joerg@dorchain.net>
+ * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow <dan@telent.net>
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+
+ * Caution: this is experimental and probably buggy.  For success and
+ * failure reports for different cards and adaptors, see
+ * orinoco_tmd_pci_id_table near the end of the file.  If you have a
+ * card we don't have the PCI id for, and looks like it should work,
+ * drop me mail with the id and "it works"/"it doesn't work".
+ *
+ * Note: if everything gets detected fine but it doesn't actually send
+ * or receive packets, your first port of call should probably be to   
+ * try newer firmware in the card.  Especially if you're doing Ad-Hoc
+ * modes
+ *
+ * The actual driving is done by orinoco.c, this is just resource
+ * allocation stuff.
+ *
+ * This driver is modeled after the orinoco_plx driver. The main
+ * difference is that the TMD chip has only IO port ranges and no
+ * memory space, i.e.  no access to the CIS. Compared to the PLX chip,
+ * the io range functionalities are exchanged.
+ *
+ * Pheecom sells cards with the TMD chip as "ASIC version"
+ */
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/wireless.h>
+#include <linux/fcntl.h>
+
+#include <pcmcia/cisreg.h>
+
+#include "hermes.h"
+#include "orinoco.h"
+
+static char dev_info[] = "orinoco_tmd";
+
+#define COR_VALUE     (COR_LEVEL_REQ | COR_FUNC_ENA | COR_FUNC_ENA) /* Enable PC card with level triggered irqs and irq requests */
+
+
+static int orinoco_tmd_init_one(struct pci_dev *pdev,
+				const struct pci_device_id *ent)
+{
+	int err = 0;
+	u32 reg, addr;
+	struct orinoco_private *priv = NULL;
+	unsigned long pccard_ioaddr = 0;
+	unsigned long pccard_iolen = 0;
+	struct net_device *dev = NULL;
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return -EIO;
+
+	printk(KERN_DEBUG "TMD setup\n");
+	pccard_ioaddr = pci_resource_start(pdev, 2);
+	pccard_iolen = pci_resource_len(pdev, 2);
+	if (! request_region(pccard_ioaddr, pccard_iolen, dev_info)) {
+		printk(KERN_ERR "orinoco_tmd: I/O resource at 0x%lx len 0x%lx busy\n",
+			pccard_ioaddr, pccard_iolen);
+		pccard_ioaddr = 0;
+		err = -EBUSY;
+		goto fail;
+	}
+	addr = pci_resource_start(pdev, 1);
+	outb(COR_VALUE, addr);
+	mdelay(1);
+	reg = inb(addr);
+	if (reg != COR_VALUE) {
+		printk(KERN_ERR "orinoco_tmd: Error setting TMD COR values %x should be %x\n", reg, COR_VALUE);
+		err = -EIO;
+		goto fail;
+	}
+
+	dev = alloc_orinocodev(0, NULL);
+	if (! dev) {
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	priv = dev->priv;
+	dev->base_addr = pccard_ioaddr;
+	SET_MODULE_OWNER(dev);
+
+	printk(KERN_DEBUG
+	       "Detected Orinoco/Prism2 TMD device at %s irq:%d, io addr:0x%lx\n",
+	       pdev->slot_name, pdev->irq, pccard_ioaddr);
+
+	hermes_struct_init(&(priv->hw), dev->base_addr,
+			HERMES_IO, HERMES_16BIT_REGSPACING);
+	pci_set_drvdata(pdev, dev);
+
+	err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name,
+			  dev);
+	if (err) {
+		printk(KERN_ERR "orinoco_tmd: Error allocating IRQ %d.\n",
+		       pdev->irq);
+		err = -EBUSY;
+		goto fail;
+	}
+	dev->irq = pdev->irq;
+
+	err = register_netdev(dev);
+	if (err)
+		goto fail;
+
+	return 0;		/* succeeded */
+
+ fail:	
+	printk(KERN_DEBUG "orinoco_tmd: init_one(), FAIL!\n");
+
+	if (dev) {
+		if (dev->irq)
+			free_irq(dev->irq, dev);
+		
+		kfree(dev);
+	}
+
+	if (pccard_ioaddr)
+		release_region(pccard_ioaddr, pccard_iolen);
+
+	pci_disable_device(pdev);
+
+	return err;
+}
+
+static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	if (! dev)
+		BUG();
+
+	unregister_netdev(dev);
+		
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+		
+	pci_set_drvdata(pdev, NULL);
+
+	kfree(dev);
+
+	release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
+
+	pci_disable_device(pdev);
+}
+
+
+static struct pci_device_id orinoco_tmd_pci_id_table[] __devinitdata = {
+	{0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,},      /* NDC and OEMs, e.g. pheecom */
+	{0,},
+};
+
+MODULE_DEVICE_TABLE(pci, orinoco_tmd_pci_id_table);
+
+static struct pci_driver orinoco_tmd_driver = {
+	.name		= "orinoco_tmd",
+	.id_table	= orinoco_tmd_pci_id_table,
+	.probe		= orinoco_tmd_init_one,
+	.remove		= __devexit_p(orinoco_tmd_remove_one),
+	.suspend	= 0,
+	.resume		= 0,
+};
+
+static char version[] __initdata = "orinoco_tmd.c 0.01 (Joerg Dorchain <joerg@dorchain.net>)";
+MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
+MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("Dual MPL/GPL");
+#endif
+
+static int __init orinoco_tmd_init(void)
+{
+	printk(KERN_DEBUG "%s\n", version);
+	return pci_module_init(&orinoco_tmd_driver);
+}
+
+extern void __exit orinoco_tmd_exit(void)
+{
+	pci_unregister_driver(&orinoco_tmd_driver);
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout(HZ);
+}
+
+module_init(orinoco_tmd_init);
+module_exit(orinoco_tmd_exit);
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff -Nru a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
--- a/drivers/parport/parport_cs.c	Sat Apr 26 09:16:25 2003
+++ b/drivers/parport/parport_cs.c	Sun May 18 13:57:40 2003
@@ -390,28 +390,27 @@
     return 0;
 } /* parport_event */
 
-/*====================================================================*/
+static struct pcmcia_driver parport_cs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "parport_cs",
+	},
+	.attach		= parport_attach,
+	.detach		= parport_detach,
+};
 
 static int __init init_parport_cs(void)
 {
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "parport_cs: Card Services release "
-	       "does not match!\n");
-	return -EINVAL;
-    }
-    register_pccard_driver(&dev_info, &parport_attach, &parport_detach);
-    return 0;
+	return pcmcia_register_driver(&parport_cs_driver);
 }
 
 static void __exit exit_parport_cs(void)
 {
-    DEBUG(0, "parport_cs: unloading\n");
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL)
-	parport_detach(dev_list);
+	pcmcia_unregister_driver(&parport_cs_driver);
+
+	/* XXX: this really needs to move into generic code.. */
+	while (dev_list != NULL)
+		parport_detach(dev_list);
 }
 
 module_init(init_parport_cs);
diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c
--- a/drivers/pci/pci.c	Sat Mar 22 07:22:30 2003
+++ b/drivers/pci/pci.c	Thu May 29 22:42:44 2003
@@ -701,6 +701,17 @@
 	return 0;
 }
 
+int
+pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
+{
+	if (!pci_dma_supported(dev, mask))
+		return -EIO;
+
+	dev->consistent_dma_mask = mask;
+
+	return 0;
+}
+     
 static int __devinit pci_init(void)
 {
 	struct pci_dev *dev;
@@ -751,6 +762,7 @@
 EXPORT_SYMBOL(pci_clear_mwi);
 EXPORT_SYMBOL(pci_set_dma_mask);
 EXPORT_SYMBOL(pci_dac_set_dma_mask);
+EXPORT_SYMBOL(pci_set_consistent_dma_mask);
 EXPORT_SYMBOL(pci_assign_resource);
 EXPORT_SYMBOL(pci_find_parent_resource);
 
diff -Nru a/drivers/pci/probe.c b/drivers/pci/probe.c
--- a/drivers/pci/probe.c	Thu May 22 10:29:05 2003
+++ b/drivers/pci/probe.c	Thu May 29 22:42:44 2003
@@ -517,6 +517,7 @@
 	/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
 	   set this higher, assuming the system even supports it.  */
 	dev->dma_mask = 0xffffffff;
+	dev->consistent_dma_mask = 0xffffffff;
 	if (pci_setup_device(dev) < 0) {
 		kfree(dev);
 		return NULL;
diff -Nru a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
--- a/drivers/pcmcia/cs.c	Sun May 25 17:00:00 2003
+++ b/drivers/pcmcia/cs.c	Thu May 29 22:42:33 2003
@@ -48,6 +48,7 @@
 #include <linux/pm.h>
 #include <linux/pci.h>
 #include <linux/device.h>
+#include <linux/suspend.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 
@@ -783,6 +784,9 @@
 		}
 
 		schedule();
+		if (current->flags & PF_FREEZE)
+			refrigerator(PF_IOTHREAD);
+
 		if (!skt->thread)
 			break;
 	}
diff -Nru a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
--- a/drivers/pcmcia/ds.c	Sun May 25 17:00:00 2003
+++ b/drivers/pcmcia/ds.c	Wed May 28 08:01:10 2003
@@ -182,50 +182,6 @@
 }
 EXPORT_SYMBOL(pcmcia_unregister_driver);
 
-
-int register_pccard_driver(dev_info_t *dev_info,
-			   dev_link_t *(*attach)(void),
-			   void (*detach)(dev_link_t *))
-{
-    struct pcmcia_driver *driver;
-
-    DEBUG(0, "ds: register_pccard_driver('%s')\n", (char *)dev_info);
-    driver = get_pcmcia_driver(dev_info);
-    if (driver)
-	    return -EBUSY;
-
-    driver = kmalloc(sizeof(struct pcmcia_driver), GFP_KERNEL);
-    if (!driver) return -ENOMEM;
-    memset(driver, 0, sizeof(struct pcmcia_driver));
-    driver->drv.name = (char *)dev_info;
-    pcmcia_register_driver(driver);
-
-    driver->attach = attach;
-    driver->detach = detach;
-
-    return 0;
-} /* register_pccard_driver */
-
-/*====================================================================*/
-
-int unregister_pccard_driver(dev_info_t *dev_info)
-{
-    struct pcmcia_driver *driver;
-
-    DEBUG(0, "ds: unregister_pccard_driver('%s')\n",
-	  (char *)dev_info);
-
-    driver = get_pcmcia_driver(dev_info);
-    if (!driver)
-	return -ENODEV;
-    
-    pcmcia_unregister_driver(driver);
-    kfree(driver);
-    return 0;
-} /* unregister_pccard_driver */
-
-/*====================================================================*/
-
 #ifdef CONFIG_PROC_FS
 static int proc_read_drivers_callback(struct device_driver *driver, void *d)
 {
@@ -875,11 +831,6 @@
 	.write		= ds_write,
 	.poll		= ds_poll,
 };
-
-EXPORT_SYMBOL(register_pccard_driver);
-EXPORT_SYMBOL(unregister_pccard_driver);
-
-/*====================================================================*/
 
 static int __devinit pcmcia_bus_add_socket(struct device *dev, unsigned int socket_nr)
 {
diff -Nru a/drivers/pcmcia/pci_socket.c b/drivers/pcmcia/pci_socket.c
--- a/drivers/pcmcia/pci_socket.c	Sun May 25 17:00:00 2003
+++ b/drivers/pcmcia/pci_socket.c	Wed May 28 08:01:10 2003
@@ -196,9 +196,9 @@
 	pci_socket_t *socket = pci_get_drvdata(dev);
 
 	/* note: we are already unregistered from the cs core */
+	class_device_unregister(&socket->cls_d.class_dev);
 	if (socket->op && socket->op->close)
 		socket->op->close(socket);
-	class_device_unregister(&socket->cls_d.class_dev);
 	pci_set_drvdata(dev, NULL);
 }
 
diff -Nru a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c
--- a/drivers/s390/net/ctctty.c	Mon May 26 12:20:48 2003
+++ b/drivers/s390/net/ctctty.c	Mon May 26 15:29:27 2003
@@ -48,7 +48,6 @@
 #define CTC_ASYNC_SPLIT_TERMIOS      0x0008 /* Sep. termios for dialin/out  */
 #define CTC_TTY_XMIT_SIZE              1024 /* Default bufsize for write    */
 #define CTC_SERIAL_XMIT_MAX            4000 /* Maximum bufsize for write    */
-#define CTC_SERIAL_TYPE_NORMAL            1
 
 /* Private data (similar to async_struct in <linux/serial.h>) */
 typedef struct {
@@ -1176,7 +1175,7 @@
 	device->minor_start = 0;
 	device->num = CTC_TTY_MAX_DEVICES;
 	device->type = TTY_DRIVER_TYPE_SERIAL;
-	device->subtype = CTC_SERIAL_TYPE_NORMAL;
+	device->subtype = SERIAL_TYPE_NORMAL;
 	device->init_termios = tty_std_termios;
 	device->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 	device->flags = TTY_DRIVER_REAL_RAW;
diff -Nru a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
--- a/drivers/sbus/char/aurora.c	Mon Apr 21 20:58:42 2003
+++ b/drivers/sbus/char/aurora.c	Mon May 26 15:29:27 2003
@@ -85,8 +85,6 @@
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 #endif
 
-#define AURORA_TYPE_NORMAL	1
-
 static struct tty_driver aurora_driver;
 static struct Aurora_board aurora_board[AURORA_NBOARD] = {
 	{0,},
@@ -661,8 +659,7 @@
 	if (mcr & MCR_CDCHG)  {
 		if (sbus_readb(&bp->r[chip]->r[CD180_MSVR]) & MSVR_CD) 
 			wake_up_interruptible(&port->open_wait);
-		else if (!((port->flags & ASYNC_CALLOUT_ACTIVE) &&
-			   (port->flags & ASYNC_CALLOUT_NOHUP))) 
+		else
 			schedule_task(&port->tqueue_hangup);
 	}
 	
@@ -1334,19 +1331,12 @@
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (port->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		port->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (port->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (port->normal_termios.c_cflag & CLOCAL) 
-			do_clocal = 1;
-	} else {
-		if (C_CLOCAL(tty))  
-			do_clocal = 1;
-	}
+	if (C_CLOCAL(tty))  
+		do_clocal = 1;
 
 	/* Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -1367,13 +1357,10 @@
 			    &bp->r[chip]->r[CD180_CAR]);
 		udelay(1);
 		CD = sbus_readb(&bp->r[chip]->r[CD180_MSVR]) & MSVR_CD;
-		if (!(port->flags & ASYNC_CALLOUT_ACTIVE))  {
-			port->MSVR=bp->RTS;
+		port->MSVR=bp->RTS;
 
-			/* auto drops DTR */
-			sbus_writeb(port->MSVR,
-				    &bp->r[chip]->r[CD180_MSVR]);
-		}
+		/* auto drops DTR */
+		sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]);
 		sti();
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) ||
@@ -1384,8 +1371,7 @@
 				retval = -ERESTARTSYS;	
 			break;
 		}
-		if (/*!(port->flags & ASYNC_CALLOUT_ACTIVE) &&*/
-		    !(port->flags & ASYNC_CLOSING) &&
+		if (!(port->flags & ASYNC_CLOSING) &&
 		    (do_clocal || CD))
 			break;
 		if (signal_pending(current)) {
@@ -1465,8 +1451,6 @@
 		restore_flags(flags);
 	}
 
-	port->session = current->session;
-	port->pgrp = current->pgrp;
 #ifdef AURORA_DEBUG
 	printk("aurora_open: end\n");
 #endif
@@ -1520,8 +1504,6 @@
 	 */
 	if (port->flags & ASYNC_NORMAL_ACTIVE)
 		port->normal_termios = *tty->termios;
-/*	if (port->flags & ASYNC_CALLOUT_ACTIVE)
-		port->callout_termios = *tty->termios;*/
 
 	/* Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -1578,8 +1560,7 @@
 		}
 		wake_up_interruptible(&port->open_wait);
 	}
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&port->close_wait);
 	restore_flags(flags);
 #ifdef AURORA_DEBUG
@@ -2223,7 +2204,7 @@
 	aurora_shutdown_port(bp, port);
 	port->event = 0;
 	port->count = 0;
-	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	port->flags &= ~ASYNC_NORMAL_ACTIVE;
 	port->tty = 0;
 	wake_up_interruptible(&port->open_wait);
 #ifdef AURORA_DEBUG
@@ -2310,7 +2291,7 @@
 	aurora_driver.major = AURORA_MAJOR;
 	aurora_driver.num = AURORA_TNPORTS;
 	aurora_driver.type = TTY_DRIVER_TYPE_SERIAL;
-	aurora_driver.subtype = AURORA_TYPE_NORMAL;
+	aurora_driver.subtype = SERIAL_TYPE_NORMAL;
 	aurora_driver.init_termios = tty_std_termios;
 	aurora_driver.init_termios.c_cflag =
 		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
diff -Nru a/drivers/sbus/char/aurora.h b/drivers/sbus/char/aurora.h
--- a/drivers/sbus/char/aurora.h	Mon Feb  4 23:41:06 2002
+++ b/drivers/sbus/char/aurora.h	Mon May 26 15:29:09 2003
@@ -247,8 +247,6 @@
 	long			event;
 	int			timeout;
 	int			close_delay;
-	long			session;
-	long			pgrp;
 	unsigned char 		* xmit_buf;
 	int			custom_divisor;
 	int			xmit_head;
diff -Nru a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c
--- a/drivers/sbus/char/bbc_envctrl.c	Tue Feb 11 14:57:52 2003
+++ b/drivers/sbus/char/bbc_envctrl.c	Wed May 28 23:01:24 2003
@@ -571,12 +571,13 @@
 	set_fan_speeds(fp);
 }
 
-void bbc_envctrl_init(void)
+int bbc_envctrl_init(void)
 {
 	struct linux_ebus_child *echild;
 	int temp_index = 0;
 	int fan_index = 0;
 	int devidx = 0;
+	int err = 0;
 
 	while ((echild = bbc_i2c_getdev(devidx++)) != NULL) {
 		if (!strcmp(echild->prom_name, "temperature"))
@@ -585,7 +586,8 @@
 			attach_one_fan(echild, fan_index++);
 	}
 	if (temp_index != 0 && fan_index != 0)
-		kernel_thread(kenvctrld, NULL, CLONE_FS | CLONE_FILES);
+		err = kernel_thread(kenvctrld, NULL, CLONE_FS | CLONE_FILES);
+	return err;
 }
 
 static void destroy_one_temp(struct bbc_cpu_temperature *tp)
diff -Nru a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
--- a/drivers/sbus/char/bbc_i2c.c	Sun Apr 20 23:48:19 2003
+++ b/drivers/sbus/char/bbc_i2c.c	Wed May 28 23:01:24 2003
@@ -430,14 +430,15 @@
 	return 0;
 }
 
-extern void bbc_envctrl_init(void);
+extern int bbc_envctrl_init(void);
 extern void bbc_envctrl_cleanup(void);
+static void bbc_i2c_cleanup(void);
 
 static int __init bbc_i2c_init(void)
 {
 	struct linux_ebus *ebus = NULL;
 	struct linux_ebus_device *edev = NULL;
-	int index = 0;
+	int err, index = 0;
 
 	if (tlb_type != cheetah || !bbc_present())
 		return -ENODEV;
@@ -454,11 +455,13 @@
 	if (!index)
 		return -ENODEV;
 
-	bbc_envctrl_init();
-	return 0;
+	err = bbc_envctrl_init();
+	if (err)
+		bbc_i2c_cleanup();
+	return err;
 }
 
-static void __exit bbc_i2c_cleanup(void)
+static void bbc_i2c_cleanup(void)
 {
 	struct bbc_i2c_bus *bp = all_bbc_i2c;
 
diff -Nru a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
--- a/drivers/sbus/char/envctrl.c	Tue Apr 22 23:40:00 2003
+++ b/drivers/sbus/char/envctrl.c	Wed May 28 22:52:16 2003
@@ -1053,7 +1053,7 @@
 	struct linux_ebus *ebus = NULL;
 	struct linux_ebus_device *edev = NULL;
 	struct linux_ebus_child *edev_child = NULL;
-	int i = 0;
+	int err, i = 0;
 
 	for_each_ebus(ebus) {
 		for_each_ebusdev(edev, ebus) {
@@ -1108,9 +1108,11 @@
 	udelay(200);
 
 	/* Register the device as a minor miscellaneous device. */
-	if (misc_register(&envctrl_dev)) {
+	err = misc_register(&envctrl_dev);
+	if (err) {
 		printk("envctrl: Unable to get misc minor %d\n",
 		       envctrl_dev.minor);
+		goto out_iounmap;
 	}
 
 	/* Note above traversal routine post-incremented 'i' to accommodate 
@@ -1125,9 +1127,21 @@
 			i2c_childlist[i].addr, (0 == i) ? ("\n") : (" "));
 	}
 
-	kernel_thread(kenvctrld, NULL, CLONE_FS | CLONE_FILES);
+	err = kernel_thread(kenvctrld, NULL, CLONE_FS | CLONE_FILES);
+	if (err)
+		goto out_deregister;
 
 	return 0;
+
+out_deregister:
+	misc_deregister(&envctrl_dev);
+out_iounmap:
+	iounmap(i2c);
+	for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++) {
+		if (i2c_childlist[i].tables)
+			kfree(i2c_childlist[i].tables);
+	}
+	return err;
 #else
 	return -ENODEV;
 #endif
diff -Nru a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
--- a/drivers/scsi/3w-xxxx.c	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/3w-xxxx.c	Mon May 12 08:14:01 2003
@@ -2497,7 +2497,8 @@
 } /* End tw_scsi_eh_reset() */
 
 /* This function handles input and output from /proc/scsi/3w-xxxx/x */
-int tw_scsi_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) 
+int tw_scsi_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
+		      off_t offset, int length, int inout) 
 {
 	TW_Device_Extension *tw_dev = NULL;
 	TW_Info info;
@@ -2508,7 +2509,7 @@
 
 	/* Find the correct device extension */
 	for (i=0;i<tw_device_extension_count;i++) 
-		if (tw_device_extension_list[i]->host->host_no == hostno) 
+		if (tw_device_extension_list[i]->host->host_no == shost->host_no) 
 			tw_dev = tw_device_extension_list[i];
 	if (tw_dev == NULL) {
 		printk(KERN_WARNING "3w-xxxx: tw_scsi_proc_info(): Couldn't locate device extension.\n");
@@ -2544,7 +2545,7 @@
 		if (start) {
 			*start = buffer;
 		}
-		tw_copy_info(&info, "scsi%d: 3ware Storage Controller\n", hostno);
+		tw_copy_info(&info, "scsi%d: 3ware Storage Controller\n", shost->host_no);
 		tw_copy_info(&info, "Driver version: %s\n", tw_driver_version);
 		tw_copy_info(&info, "Current commands posted:       %3d\n", tw_dev->posted_request_count);
 		tw_copy_info(&info, "Max commands posted:           %3d\n", tw_dev->max_posted_request_count);
diff -Nru a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
--- a/drivers/scsi/3w-xxxx.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/3w-xxxx.h	Mon May 12 07:26:10 2003
@@ -474,7 +474,6 @@
 int tw_scsi_detect(Scsi_Host_Template *tw_host);
 int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt);
 int tw_scsi_eh_reset(Scsi_Cmnd *SCpnt);
-int tw_scsi_proc_info(char *buffer, char **start, off_t offset, int length, int inode, int inout);
 int tw_scsi_queue(Scsi_Cmnd *cmd, void (*done) (Scsi_Cmnd *));
 int tw_scsi_release(struct Scsi_Host *tw_host);
 int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id);
diff -Nru a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
--- a/drivers/scsi/53c700.c	Sat Apr 26 07:41:50 2003
+++ b/drivers/scsi/53c700.c	Mon May 26 14:44:44 2003
@@ -124,6 +124,7 @@
 #include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/sched.h>
+#include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <asm/dma.h>
 #include <asm/system.h>
@@ -167,12 +168,14 @@
 STATIC int NCR_700_bus_reset(Scsi_Cmnd * SCpnt);
 STATIC int NCR_700_dev_reset(Scsi_Cmnd * SCpnt);
 STATIC int NCR_700_host_reset(Scsi_Cmnd * SCpnt);
-STATIC int NCR_700_proc_directory_info(char *, char **, off_t, int, int, int);
+STATIC int NCR_700_proc_directory_info(struct Scsi_Host *, char *, char **, off_t, int, int);
 STATIC void NCR_700_chip_setup(struct Scsi_Host *host);
 STATIC void NCR_700_chip_reset(struct Scsi_Host *host);
 STATIC int NCR_700_slave_configure(Scsi_Device *SDpnt);
 STATIC void NCR_700_slave_destroy(Scsi_Device *SDpnt);
 
+static struct device_attribute **NCR_700_dev_attrs = NULL;
+
 static char *NCR_700_phase[] = {
 	"",
 	"after selection",
@@ -247,6 +250,9 @@
 	static int banner = 0;
 	int j;
 
+	if(tpnt->sdev_attrs == NULL)
+		tpnt->sdev_attrs = NCR_700_dev_attrs;
+
 	memory = dma_alloc_noncoherent(hostdata->dev, TOTAL_MEM_SIZE,
 				       &pScript, GFP_KERNEL);
 	if(memory == NULL) {
@@ -1703,23 +1709,15 @@
 	return IRQ_RETVAL(handled);
 }
 
-/* FIXME: Need to put some proc information in and plumb it
- * into the scsi proc system */
 STATIC int
-NCR_700_proc_directory_info(char *proc_buf, char **startp,
-			 off_t offset, int bytes_available,
-			 int host_no, int write)
+NCR_700_proc_directory_info(struct Scsi_Host *host, char *proc_buf, char **startp,
+			 off_t offset, int bytes_available, int write)
 {
 	static char buf[4096];	/* 1 page should be sufficient */
 	int len = 0;
-	struct Scsi_Host *host;
 	struct NCR_700_Host_Parameters *hostdata;
 	Scsi_Device *SDp;
 
-	host = scsi_host_hn_get(host_no);
-	if(host == NULL)
-		return 0;
-
 	if(write) {
 		/* FIXME: Clear internal statistics here */
 		return 0;
@@ -2023,6 +2021,56 @@
 	/* to do here: deallocate memory */
 }
 
+static ssize_t
+NCR_700_store_queue_depth(struct device *dev, const char *buf, size_t count)
+{
+	int depth;
+
+	struct scsi_device *SDp = to_scsi_device(dev);
+	depth = simple_strtoul(buf, NULL, 0);
+	if(depth > NCR_700_MAX_TAGS)
+		return -EINVAL;
+	scsi_adjust_queue_depth(SDp, MSG_ORDERED_TAG, depth);
+
+	return count;
+}
+
+static ssize_t
+NCR_700_show_active_tags(struct device *dev, char *buf)
+{
+	struct scsi_device *SDp = to_scsi_device(dev);
+
+	return snprintf(buf, 20, "%d\n", NCR_700_get_depth(SDp));
+}
+
+static struct device_attribute NCR_700_queue_depth_attr = {
+	.attr = {
+		.name = 	"queue_depth",
+		.mode =		S_IWUSR,
+	},
+	.store = NCR_700_store_queue_depth,
+};
+
+static struct device_attribute NCR_700_active_tags_attr = {
+	.attr = {
+		.name =		"active_tags",
+		.mode =		S_IRUGO,
+	},
+	.show = NCR_700_show_active_tags,
+};
+
+STATIC int __init
+NCR_700_init(void)
+{
+	scsi_sysfs_modify_sdev_attribute(&NCR_700_dev_attrs,
+					 &NCR_700_queue_depth_attr);
+	scsi_sysfs_modify_sdev_attribute(&NCR_700_dev_attrs,
+					 &NCR_700_active_tags_attr);
+	return 0;
+}
+
 EXPORT_SYMBOL(NCR_700_detect);
 EXPORT_SYMBOL(NCR_700_release);
 EXPORT_SYMBOL(NCR_700_intr);
+
+module_init(NCR_700_init);
diff -Nru a/drivers/scsi/AM53C974.c b/drivers/scsi/AM53C974.c
--- a/drivers/scsi/AM53C974.c	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/AM53C974.c	Tue May 13 03:59:32 2003
@@ -732,6 +732,12 @@
 	hostdata->disconnecting = 0;
 	hostdata->dma_busy = 0;
 
+	if (!request_region (instance->io_port, 128, "AM53C974")) {
+		printk ("AM53C974 (scsi%d): Could not get IO region %04lx.\n",
+			instance->host_no, instance->io_port);
+		scsi_unregister(instance);
+		return 0;
+	}
 /* Set up an interrupt handler if we aren't already sharing an IRQ with another board */
 	for (search = first_host;
 	     search && (((the_template != NULL) && (search->hostt != the_template)) ||
@@ -2442,6 +2448,7 @@
 static int AM53C974_release(struct Scsi_Host *shp)
 {
 	free_irq(shp->irq, shp);
+	release_region(shp->io_port, 128);
 	scsi_unregister(shp);
 	return 0;
 }
diff -Nru a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
--- a/drivers/scsi/BusLogic.c	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/BusLogic.c	Mon May 12 07:26:10 2003
@@ -4327,9 +4327,9 @@
   BugLogic_ProcDirectoryInfo implements /proc/scsi/BusLogic/<N>.
 */
 
-int BusLogic_ProcDirectoryInfo(char *ProcBuffer, char **StartPointer,
+int BusLogic_ProcDirectoryInfo(struct Scsi_Host *shost, char *ProcBuffer, char **StartPointer,
 			       off_t Offset, int BytesAvailable,
-			       int HostNumber, int WriteFlag)
+			       int WriteFlag)
 {
   BusLogic_HostAdapter_T *HostAdapter;
   BusLogic_TargetStatistics_T *TargetStatistics;
@@ -4338,11 +4338,11 @@
   for (HostAdapter = BusLogic_FirstRegisteredHostAdapter;
        HostAdapter != NULL;
        HostAdapter = HostAdapter->Next)
-    if (HostAdapter->HostNumber == HostNumber) break;
+    if (HostAdapter->HostNumber == shost->host_no) break;
   if (HostAdapter == NULL)
     {
       BusLogic_Error("Cannot find Host Adapter for SCSI Host %d\n",
-		     NULL, HostNumber);
+		     NULL, shost->host_no);
       return 0;
     }
   TargetStatistics = HostAdapter->TargetStatistics;
diff -Nru a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
--- a/drivers/scsi/BusLogic.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/BusLogic.h	Mon May 12 07:45:05 2003
@@ -56,7 +56,7 @@
 				 void (*CompletionRoutine)(SCSI_Command_T *));
 extern int BusLogic_BIOSDiskParameters(struct scsi_device *,
 		struct block_device *, sector_t, int *);
-extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int);
+extern int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, char **, off_t, int, int);
 extern int BusLogic_SlaveConfigure(SCSI_Device_T *);
 
 #ifdef BusLogic_DriverVersion
diff -Nru a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
--- a/drivers/scsi/NCR5380.c	Thu May 15 18:42:51 2003
+++ b/drivers/scsi/NCR5380.c	Mon May 19 19:40:41 2003
@@ -824,7 +824,7 @@
 	NCR5380_dprint(NDEBUG_ANY, instance);
 	NCR5380_dprint_phase(NDEBUG_ANY, instance);
 
-	len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), instance->host_no, 0);
+	len = NCR5380_proc_info(instance, pr_bfr, &start, 0, sizeof(pr_bfr), 0);
 	pr_bfr[len] = 0;
 	printk("\n%s\n", pr_bfr);
 }
@@ -855,16 +855,12 @@
 #ifndef NCR5380_proc_info
 static
 #endif
-int NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, char **start, off_t offset, int length, int inout)
 {
 	char *pos = buffer;
-	struct Scsi_Host *instance;
 	struct NCR5380_hostdata *hostdata;
 	Scsi_Cmnd *ptr;
 
-	instance = scsi_host_hn_get(hostno);
-	if (!instance)
-		return (-ESRCH);
 	hostdata = (struct NCR5380_hostdata *) instance->hostdata;
 
 	if (inout) {		/* Has data been written to the file ? */
diff -Nru a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
--- a/drivers/scsi/NCR5380.h	Sat Apr 26 07:28:14 2003
+++ b/drivers/scsi/NCR5380.h	Mon May 12 07:58:21 2003
@@ -310,7 +310,10 @@
 static int NCR5380_host_reset(Scsi_Cmnd * cmd);
 static int NCR5380_device_reset(Scsi_Cmnd * cmd);
 static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
-
+#ifdef NCR5380_proc_info
+int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, char **start,
+off_t offset, int length, int inout);
+#endif
 
 static void NCR5380_reselect(struct Scsi_Host *instance);
 static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag);
diff -Nru a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
--- a/drivers/scsi/NCR53C9x.c	Sat Apr 26 07:28:14 2003
+++ b/drivers/scsi/NCR53C9x.c	Mon May 12 07:26:10 2003
@@ -890,24 +890,15 @@
 }
 
 /* ESP proc filesystem code. */
-int esp_proc_info(char *buffer, char **start, off_t offset, int length,
-		  int hostno, int inout)
+int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length,
+		  int inout)
 {
-	struct NCR_ESP *esp;
+	struct NCR_ESP *esp = (struct NCR_ESP *) SCpnt->device->host->hostdata;
 
 	if(inout)
 		return -EINVAL; /* not yet */
-
-	for_each_esp(esp) {
-		if(esp->ehost->host_no == hostno)
-			break;
-	}
-	if(!esp)
-		return -EINVAL;
-
 	if(start)
 		*start = buffer;
-
 	return esp_host_info(esp, buffer, offset, length);
 }
 
diff -Nru a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
--- a/drivers/scsi/NCR53C9x.h	Sat Apr 26 07:28:14 2003
+++ b/drivers/scsi/NCR53C9x.h	Mon May 12 07:26:10 2003
@@ -664,6 +664,6 @@
 extern int esp_command(Scsi_Cmnd *);
 extern int esp_abort(Scsi_Cmnd *);
 extern int esp_reset(Scsi_Cmnd *);
-extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
-			 int hostno, int inout);
+extern int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length,
+			 int inout);
 #endif /* !(NCR53C9X_H) */
diff -Nru a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
--- a/drivers/scsi/NCR_D700.c	Sun May 25 17:00:00 2003
+++ b/drivers/scsi/NCR_D700.c	Mon May 26 18:54:33 2003
@@ -385,6 +385,7 @@
 static void __exit NCR_D700_exit(void)
 {
 	mca_unregister_driver(&NCR_D700_driver);
+	scsi_sysfs_release_attributes();
 }
 
 module_init(NCR_D700_init);
diff -Nru a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
--- a/drivers/scsi/aacraid/linit.c	Thu May  8 11:24:16 2003
+++ b/drivers/scsi/aacraid/linit.c	Mon May 12 08:14:20 2003
@@ -137,7 +137,6 @@
 static int aac_queuecommand(Scsi_Cmnd *, void (*CompletionRoutine)(Scsi_Cmnd *));
 static int aac_biosparm(struct scsi_device *, struct block_device *,
 			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);
 static int aac_eh_device_reset(Scsi_Cmnd* cmd);
@@ -616,7 +615,6 @@
 static Scsi_Host_Template driver_template = {
 	.module				= THIS_MODULE,
 	.name           		= "AAC",
-	.proc_info      		= aac_procinfo,
 	.detect         		= aac_detect,
 	.release        		= aac_release,
 	.info           		= aac_driverinfo,
@@ -682,35 +680,3 @@
 
 
 #include "scsi_module.c"
-
-/**
- *	aac_procinfo	-	Implement /proc/scsi/<drivername>/<n>
- *	@proc_buffer: memory buffer for I/O
- *	@start_ptr: pointer to first valid data
- *	@offset: offset into file
- *	@bytes_available: space left
- *	@host_no: scsi host ident
- *	@write: direction of I/O
- *
- *	Used to export driver statistics and other infos to the world outside 
- *	the kernel using the proc file system. Also provides an interface to
- *	feed the driver with information.
- *
- *		For reads
- *			- if offset > 0 return 0
- *			- if offset == 0 write data to proc_buffer and set the start_ptr to
- *			beginning of proc_buffer, return the number of characters written.
- *		For writes
- *			- writes currently not supported, return 0
- *
- *	Bugs:	Only offset zero is handled
- */
-
-static int aac_procinfo(char *proc_buffer, char **start_ptr,off_t offset,
-			int bytes_available, int host_no, int write)
-{
-	if(write || offset > 0)
-		return 0;
-	*start_ptr = proc_buffer;
-	return sprintf(proc_buffer, "%s  %d\n", "Raid Controller, scsi hba number", host_no);
-}
diff -Nru a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
--- a/drivers/scsi/advansys.c	Thu May  8 11:31:08 2003
+++ b/drivers/scsi/advansys.c	Mon May 12 07:41:38 2003
@@ -4290,14 +4290,14 @@
  * user just won't get all the available statistics.
  */
 int
-advansys_proc_info(char *buffer, char **start, off_t offset, int length,
-                   int hostno, int inout)
+advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
+		off_t offset, int length, int inout)
 {
     struct Scsi_Host    *shp;
     asc_board_t         *boardp;
     int                 i;
     char                *cp;
-    int                 cplen;
+    int			cplen;
     int                 cnt;
     int                 totcnt;
     int                 leftlen;
@@ -4322,7 +4322,7 @@
 
     /* Find the specified board. */
     for (i = 0; i < asc_board_count; i++) {
-        if (asc_host[i]->host_no == hostno) {
+        if (asc_host[i]->host_no == shost->host_no) {
             break;
         }
     }
@@ -4767,7 +4767,7 @@
 
 	    scsi_set_device(shp, &pci_devp->dev);
 
-            /* Save a pointer to the Scsi_host of each board found. */
+            /* Save a pointer to the Scsi_Host of each board found. */
             asc_host[asc_board_count++] = shp;
 
             /* Initialize private per board data */
diff -Nru a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h
--- a/drivers/scsi/advansys.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/advansys.h	Mon May 12 07:26:10 2003
@@ -55,14 +55,6 @@
 int advansys_biosparam(struct scsi_device *, struct block_device *,
 		sector_t, int[]);
 static int advansys_slave_configure(Scsi_Device *);
-#ifdef CONFIG_PROC_FS
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28)
-extern struct proc_dir_entry proc_scsi_advansys;
-#endif /* version < v2.3.28 */
-int advansys_proc_info(char *, char **, off_t, int, int, int);
-#else /* !defined(CONFIG_PROC_FS) */
-#define advansys_proc_info      NULL
-#endif /* !defined(CONFIG_PROC_FS) */
 
 /* init/main.c setup function */
 void advansys_setup(char *, int *);
diff -Nru a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
--- a/drivers/scsi/aha152x.c	Sat Apr 26 07:28:18 2003
+++ b/drivers/scsi/aha152x.c	Mon May 12 07:26:11 2003
@@ -3734,26 +3734,18 @@
 #define SPRINTF(args...) \
 	do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
 
-static int aha152x_proc_info(char *buffer, char **start,
-		      off_t offset, int length, int hostno, int inout)
+static int aha152x_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start,
+		      off_t offset, int length, int inout)
 {
 	int i;
 	char *pos = buffer;
-	struct Scsi_Host *shpnt;
 	Scsi_Cmnd *ptr;
 	unsigned long flags;
 	int thislength;
 
-	for (i = 0, shpnt = (struct Scsi_Host *) NULL; i<ARRAY_SIZE(aha152x_host); i++)
-		if (aha152x_host[i] && aha152x_host[i]->host_no == hostno)
-			shpnt = aha152x_host[i];
-
-	if (!shpnt)
-		return -ESRCH;
-
 	DPRINTK(debug_procinfo, 
 	       KERN_DEBUG "aha152x_proc_info: buffer=%p offset=%ld length=%d hostno=%d inout=%d\n",
-	       buffer, offset, length, hostno, inout);
+	       buffer, offset, length, shpnt->host_no, inout);
 
 
 	if (inout)
diff -Nru a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
--- a/drivers/scsi/aha1740.c	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/aha1740.c	Mon May 12 07:26:11 2003
@@ -76,21 +76,15 @@
 /* One for each IRQ level (9-15) */
 static struct Scsi_Host * aha_host[8] = {NULL, };
 
-static int aha1740_proc_info(char *buffer, char **start, off_t offset,
-		      int length, int hostno, int inout)
+static int aha1740_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset,
+		      int length, int inout)
 {
     int len;
-    struct Scsi_Host * shpnt;
     struct aha1740_hostdata *host;
 
     if (inout)
 	return-ENOSYS;
 
-    for (len = 0; len < 8; len++) {
-	shpnt = aha_host[len];
-	if (shpnt && shpnt->host_no == hostno)
-	    break;
-    }
     host = HOSTDATA(shpnt);
 
     len = sprintf(buffer, "aha174x at IO:%lx, IRQ %d, SLOT %d.\n"
@@ -108,7 +102,6 @@
     if (len > length)
 	len = length;
     return len;
-}
 
 
 static int aha1740_makecode(unchar *sense, unchar *status)
diff -Nru a/drivers/scsi/aha1740.h b/drivers/scsi/aha1740.h
--- a/drivers/scsi/aha1740.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/aha1740.h	Mon May 12 07:26:11 2003
@@ -156,7 +156,6 @@
 static int aha1740_command(Scsi_Cmnd *);
 static int aha1740_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 static int aha1740_biosparam(struct scsi_device *, struct block_device *, sector_t, int *);
-static int aha1740_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
 
 #define AHA1740_ECBS 32
 #define AHA1740_SCATTER 16
diff -Nru a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
--- a/drivers/scsi/aic7xxx/aic79xx.h	Thu Apr 24 11:15:39 2003
+++ b/drivers/scsi/aic7xxx/aic79xx.h	Wed May 14 15:03:47 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#89 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#90 $
  *
  * $FreeBSD$
  */
@@ -1225,20 +1225,20 @@
 	int			  seltime;
 
 	/*
-	 * Interrupt coalessing settings.
+	 * Interrupt coalescing settings.
 	 */
-#define	AHD_INT_COALESSING_TIMER_DEFAULT		250 /*us*/
-#define	AHD_INT_COALESSING_MAXCMDS_DEFAULT		10
-#define	AHD_INT_COALESSING_MAXCMDS_MAX			127
-#define	AHD_INT_COALESSING_MINCMDS_DEFAULT		5
-#define	AHD_INT_COALESSING_MINCMDS_MAX			127
-#define	AHD_INT_COALESSING_THRESHOLD_DEFAULT		2000
-#define	AHD_INT_COALESSING_STOP_THRESHOLD_DEFAULT	1000
-	u_int			  int_coalessing_timer;
-	u_int			  int_coalessing_maxcmds;
-	u_int			  int_coalessing_mincmds;
-	u_int			  int_coalessing_threshold;
-	u_int			  int_coalessing_stop_threshold;
+#define	AHD_INT_COALESCING_TIMER_DEFAULT		250 /*us*/
+#define	AHD_INT_COALESCING_MAXCMDS_DEFAULT		10
+#define	AHD_INT_COALESCING_MAXCMDS_MAX			127
+#define	AHD_INT_COALESCING_MINCMDS_DEFAULT		5
+#define	AHD_INT_COALESCING_MINCMDS_MAX			127
+#define	AHD_INT_COALESCING_THRESHOLD_DEFAULT		2000
+#define	AHD_INT_COALESCING_STOP_THRESHOLD_DEFAULT	1000
+	u_int			  int_coalescing_timer;
+	u_int			  int_coalescing_maxcmds;
+	u_int			  int_coalescing_mincmds;
+	u_int			  int_coalescing_threshold;
+	u_int			  int_coalescing_stop_threshold;
 
 	uint16_t	 	  user_discenable;/* Disconnection allowed  */
 	uint16_t		  user_tagenable;/* Tagged Queuing allowed */
@@ -1362,11 +1362,11 @@
 int			 ahd_parse_cfgdata(struct ahd_softc *ahd,
 					   struct seeprom_config *sc);
 void			 ahd_intr_enable(struct ahd_softc *ahd, int enable);
-void			 ahd_update_coalessing_values(struct ahd_softc *ahd,
+void			 ahd_update_coalescing_values(struct ahd_softc *ahd,
 						      u_int timer,
 						      u_int maxcmds,
 						      u_int mincmds);
-void			 ahd_enable_coalessing(struct ahd_softc *ahd,
+void			 ahd_enable_coalescing(struct ahd_softc *ahd,
 					       int enable);
 void			 ahd_pause_and_flushwork(struct ahd_softc *ahd);
 int			 ahd_suspend(struct ahd_softc *ahd); 
@@ -1514,7 +1514,7 @@
 #define AHD_SHOW_QUEUE		0x02000
 #define AHD_SHOW_TQIN		0x04000
 #define AHD_SHOW_SG		0x08000
-#define AHD_SHOW_INT_COALESSING	0x10000
+#define AHD_SHOW_INT_COALESCING	0x10000
 #define AHD_DEBUG_SEQUENCER	0x20000
 #endif
 void			ahd_print_scb(struct scb *scb);
diff -Nru a/drivers/scsi/aic7xxx/aic79xx.reg b/drivers/scsi/aic7xxx/aic79xx.reg
--- a/drivers/scsi/aic7xxx/aic79xx.reg	Thu Apr 24 11:46:35 2003
+++ b/drivers/scsi/aic7xxx/aic79xx.reg	Fri May 23 10:55:33 2003
@@ -39,7 +39,7 @@
  *
  * $FreeBSD$
  */
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#69 $"
 
 /*
  * This file is processed by the aic7xxx_asm utility for use in assembling
@@ -286,7 +286,7 @@
 	address			0x00B
 	access_mode	RW
 	mask	HOST_TQINPOS	0x80	/* Boundary at either 0 or 128 */
-	mask	ENINT_COALESS	0x40	/* Perform interrupt coalessing */
+	mask	ENINT_COALESCE	0x40	/* Perform interrupt coalescing */
 }
 
 /*
@@ -3704,28 +3704,28 @@
 	}
 
 	/*
-	 * The maximum amount of time to wait, when interrupt coalessing
+	 * The maximum amount of time to wait, when interrupt coalescing
 	 * is enabled, before issueing a CMDCMPLT interrupt for a completed
 	 * command.
 	 */
-	INT_COALESSING_TIMER {
+	INT_COALESCING_TIMER {
 		size		2
 	}
 
 	/*
-	 * The maximum number of commands to coaless into a single interrupt.
+	 * The maximum number of commands to coalesce into a single interrupt.
 	 * Actually the 2's complement of that value to simplify sequencer
 	 * code.
 	 */
-	INT_COALESSING_MAXCMDS {
+	INT_COALESCING_MAXCMDS {
 		size		1
 	}
 
 	/*
 	 * The minimum number of commands still outstanding required
-	 * to continue coalessing (2's complement of value).
+	 * to continue coalescing (2's complement of value).
 	 */
-	INT_COALESSING_MINCMDS {
+	INT_COALESCING_MINCMDS {
 		size		1
 	}
 
@@ -3737,9 +3737,9 @@
 	}
 
 	/*
-	 * The count of commands that have been coalessed.
+	 * The count of commands that have been coalesced.
 	 */
-	INT_COALESSING_CMDCOUNT {
+	INT_COALESCING_CMDCOUNT {
 		size		1
 	}
 
@@ -3842,10 +3842,15 @@
 	}
 	SCB_LUN {
 		size	1
-		field	LID				0xff
+		field	LID	0xff
 	}
 	SCB_TASK_ATTRIBUTE {
 		size	1
+		/*
+		 * Overloaded field for non-packetized 
+		 * ignore wide residue message handling.
+		 */
+		field	SCB_XFERLEN_ODD	0x01
 	}
 	SCB_CDB_LEN {
 		size	1
diff -Nru a/drivers/scsi/aic7xxx/aic79xx.seq b/drivers/scsi/aic7xxx/aic79xx.seq
--- a/drivers/scsi/aic7xxx/aic79xx.seq	Thu Apr 24 11:46:35 2003
+++ b/drivers/scsi/aic7xxx/aic79xx.seq	Fri May 23 10:55:34 2003
@@ -40,7 +40,7 @@
  * $FreeBSD$
  */
 
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $"
 PATCH_ARG_LIST = "struct ahd_softc *ahd"
 PREFIX = "ahd_"
 
@@ -212,44 +212,44 @@
 qoutfifo_updated:
 	/*
 	 * If there are more commands waiting to be dma'ed
-	 * to the host, always coaless.  Otherwise honor the
+	 * to the host, always coalesce.  Otherwise honor the
 	 * host's wishes.
 	 */
-	cmp	COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne coaless_by_count;
-	cmp	COMPLETE_SCB_HEAD[1], SCB_LIST_NULL jne coaless_by_count;
-	test	LOCAL_HS_MAILBOX, ENINT_COALESS jz issue_cmdcmplt;
+	cmp	COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne coalesce_by_count;
+	cmp	COMPLETE_SCB_HEAD[1], SCB_LIST_NULL jne coalesce_by_count;
+	test	LOCAL_HS_MAILBOX, ENINT_COALESCE jz issue_cmdcmplt;
 
 	/*
 	 * If we have relatively few commands outstanding, don't
 	 * bother waiting for another command to complete.
 	 */
-	test	CMDS_PENDING[1], 0xFF jnz coaless_by_count;
+	test	CMDS_PENDING[1], 0xFF jnz coalesce_by_count;
 	/* Add -1 so that jnc means <= not just < */
-	add	A, -1, INT_COALESSING_MINCMDS;
+	add	A, -1, INT_COALESCING_MINCMDS;
 	add	NONE, A, CMDS_PENDING;
 	jnc	issue_cmdcmplt;
 	
 	/*
-	 * If coalessing, only coaless up to the limit
+	 * If coalescing, only coalesce up to the limit
 	 * provided by the host driver.
 	 */
-coaless_by_count:
-	mov	A, INT_COALESSING_MAXCMDS;
-	add	NONE, A, INT_COALESSING_CMDCOUNT;
+coalesce_by_count:
+	mov	A, INT_COALESCING_MAXCMDS;
+	add	NONE, A, INT_COALESCING_CMDCOUNT;
 	jc	issue_cmdcmplt;
 	/*
 	 * If the timer is not currently active,
 	 * fire it up.
 	 */
 	test	INTCTL, SWTMINTMASK jz return;
-	bmov	SWTIMER, INT_COALESSING_TIMER, 2;
+	bmov	SWTIMER, INT_COALESCING_TIMER, 2;
 	mvi	CLRSEQINTSTAT, CLRSEQ_SWTMRTO;
 	or	INTCTL, SWTMINTEN|SWTIMER_START;
 	and	INTCTL, ~SWTMINTMASK ret;
 
 issue_cmdcmplt:
 	mvi	INTSTAT, CMDCMPLT;
-	clr	INT_COALESSING_CMDCOUNT;
+	clr	INT_COALESCING_CMDCOUNT;
 	or	INTCTL, SWTMINTMASK ret;
 
 BEGIN_CRITICAL;
@@ -261,6 +261,15 @@
 	clr	A;
 	add	CMDS_PENDING, 1;
 	adc	CMDS_PENDING[1], A;
+	if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) {
+		/*
+		 * "Short Luns" are not placed into outgoing LQ
+		 * packets in the correct byte order.  Use a full
+		 * sized lun field instead and fill it with the
+		 * one byte of lun information we support.
+		 */
+		mov	SCB_PKT_LUN[6], SCB_LUN;
+	}
 	/*
 	 * The FIFO use count field is shared with the
 	 * tag set by the host so that our SCB dma engine
@@ -324,7 +333,7 @@
 	mov	CCSCBRAM, SCBPTR;
 	or	CCSCBRAM, A, SCBPTR[1];
 	mov	NONE, SDSCB_QOFF;
-	inc	INT_COALESSING_CMDCOUNT;
+	inc	INT_COALESCING_CMDCOUNT;
 	add	CMDS_PENDING, -1;
 	adc	CMDS_PENDING[1], -1;
 	cmp	SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je fill_qoutfifo_done;
@@ -863,7 +872,8 @@
 	mvi	REG0	call inb_next;
 	cmp	REG0, 0x01 jne mesgin_reject;
 	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2;
-	test	DATA_COUNT_ODD, 0x1	jz mesgin_done;
+	test	SCB_TASK_ATTRIBUTE, SCB_XFERLEN_ODD jnz mesgin_done;
+	SET_SEQINTCODE(IGN_WIDE_RES)
 	jmp	mesgin_done;
 
 mesgin_proto_violation:
@@ -1308,8 +1318,6 @@
 		bmov 	HADDR, CCSGRAM, 4;
 	}
 	bmov	HCNT, CCSGRAM, 3;
-	test	HCNT[0], 0x1 jz . + 2;
-	xor	DATA_COUNT_ODD, 0x1;
 	bmov	SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;
 	if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) {
 		and	HADDR[4], SG_HIGH_ADDR_BITS, SCB_RESIDUAL_DATACNT[3];
@@ -1325,8 +1333,6 @@
 	adc	SCB_RESIDUAL_SGPTR[2],A;
 	adc	SCB_RESIDUAL_SGPTR[3],A;
 	mov	SINDEX, SCB_RESIDUAL_SGPTR[0];
-	test	DATA_COUNT_ODD, 0x1 jz . + 2;
-	or	SINDEX, ODD_SEG;
 	test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 3;
 	or	SINDEX, LAST_SEG;
 	clr	SG_STATE;
@@ -1352,12 +1358,9 @@
  */
 load_first_seg:
 	bmov	HADDR, SCB_DATAPTR, 11;
-	and	DATA_COUNT_ODD, 0x1, SCB_DATACNT[0];
 	and	REG_ISR, ~SG_FULL_RESID, SCB_SGPTR[0];
 	test	SCB_DATACNT[3], SG_LAST_SEG jz . + 2;
 	or	REG_ISR, LAST_SEG;
-	test	DATA_COUNT_ODD, 0x1 jz . + 2;
-	or	REG_ISR, ODD_SEG;
 	mov	SG_CACHE_PRE, REG_ISR;
 	mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN);
 	/*
@@ -1507,7 +1510,7 @@
 		 * send Ignore Wide Residue messages for data-in phases.
 		test	DFCNTRL, DIRECTION jz target_ITloop;
 		test	SSTAT1, REQINIT	jnz .;
-		test	DATA_COUNT_ODD, 0x1 jz target_ITloop;
+		test	SCB_TASK_ATTRIBUTE, SCB_XFERLEN_ODD jz target_ITloop;
 		SET_MODE(M_SCSI, M_SCSI)
 		test	NEGCONOPTS, WIDEXFER jz target_ITloop;
 		 */
@@ -1577,9 +1580,6 @@
 	adc	SCB_RESIDUAL_SGPTR[3], -1;
 sgptr_fixup_done:
 	and	SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW;
-	clr	DATA_COUNT_ODD;
-	test	SG_CACHE_SHADOW, ODD_SEG jz . + 2;
-	or	DATA_COUNT_ODD, 0x1;
 	clr	SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */
 	bmov	SCB_RESIDUAL_DATACNT, SHCNT, 3 ret;
 
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
--- a/drivers/scsi/aic7xxx/aic79xx_core.c	Thu May  1 10:00:20 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c	Fri May 23 10:58:23 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#190 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#194 $
  *
  * $FreeBSD$
  */
@@ -4401,7 +4401,7 @@
 
 		sgptr = ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR);
 		if ((sgptr & SG_LIST_NULL) != 0
-		 && ahd_inb(ahd, DATA_COUNT_ODD) == 1) {
+		 && (ahd_inb(ahd, SCB_TASK_ATTRIBUTE) & SCB_XFERLEN_ODD) != 0) {
 			/*
 			 * If the residual occurred on the last
 			 * transfer and the transfer request was
@@ -4414,29 +4414,20 @@
 			uint32_t sglen;
 
 			/* Pull in the rest of the sgptr */
-			sgptr |=
-			    (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 3) << 24)
-			  | (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 2) << 16)
-			  | (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 1) << 8);
-			sgptr &= SG_PTR_MASK;
-			data_cnt =
-			    (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+3) << 24)
-			  | (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+2) << 16)
-			  | (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+1) << 8)
-			  | (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT));
-
-			data_addr = (((uint64_t)ahd_inb(ahd, SHADDR + 7)) << 56)
-				  | (((uint64_t)ahd_inb(ahd, SHADDR + 6)) << 48)
-				  | (((uint64_t)ahd_inb(ahd, SHADDR + 5)) << 40)
-				  | (((uint64_t)ahd_inb(ahd, SHADDR + 4)) << 32)
-				  | (ahd_inb(ahd, SHADDR + 3) << 24)
-				  | (ahd_inb(ahd, SHADDR + 2) << 16)
-				  | (ahd_inb(ahd, SHADDR + 1) << 8)
-				  | (ahd_inb(ahd, SHADDR));
-
+			sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR);
+			data_cnt = ahd_inl_scbram(ahd, SCB_RESIDUAL_DATACNT);
+			if ((sgptr & SG_LIST_NULL) != 0) {
+				/*
+				 * The residual data count is not updated
+				 * for the command run to completion case.
+				 * Explicitly zero the count.
+				 */
+				data_cnt &= ~AHD_SG_LEN_MASK;
+			}
+			data_addr = ahd_inq(ahd, SHADDR);
 			data_cnt += 1;
 			data_addr -= 1;
-
+			sgptr &= SG_PTR_MASK;
 			if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
 				struct ahd_dma64_seg *sg;
 
@@ -4504,16 +4495,17 @@
 								  sg);
 				}
 			}
-			ahd_outb(ahd, SCB_RESIDUAL_SGPTR + 3, sgptr >> 24);
-			ahd_outb(ahd, SCB_RESIDUAL_SGPTR + 2, sgptr >> 16);
-			ahd_outb(ahd, SCB_RESIDUAL_SGPTR + 1, sgptr >> 8);
-			ahd_outb(ahd, SCB_RESIDUAL_SGPTR, sgptr);
-
-			ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 3, data_cnt >> 24);
-			ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 2, data_cnt >> 16);
-			ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 1, data_cnt >> 8);
-			ahd_outb(ahd, SCB_RESIDUAL_DATACNT, data_cnt);
+			/*
+			 * Toggle the "oddness" of the transfer length
+			 * to handle this mid-transfer ignore wide
+			 * residue.  This ensures that the oddness is
+			 * correct for subsequent data transfers.
+			 */
+			ahd_outb(ahd, SCB_TASK_ATTRIBUTE,
+			    ahd_inb(ahd, SCB_TASK_ATTRIBUTE) ^ SCB_XFERLEN_ODD);
 
+			ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr);
+			ahd_outl(ahd, SCB_RESIDUAL_DATACNT, data_cnt);
 			/*
 			 * The FIFO's pointers will be updated if/when the
 			 * sequencer re-enters a data phase.
@@ -4806,12 +4798,12 @@
 		   | AHD_EXTENDED_TRANS_A|AHD_STPWLEVEL_A;
 	ahd_timer_init(&ahd->reset_timer);
 	ahd_timer_init(&ahd->stat_timer);
-	ahd->int_coalessing_timer = AHD_INT_COALESSING_TIMER_DEFAULT;
-	ahd->int_coalessing_maxcmds = AHD_INT_COALESSING_MAXCMDS_DEFAULT;
-	ahd->int_coalessing_mincmds = AHD_INT_COALESSING_MINCMDS_DEFAULT;
-	ahd->int_coalessing_threshold = AHD_INT_COALESSING_THRESHOLD_DEFAULT;
-	ahd->int_coalessing_stop_threshold =
-	    AHD_INT_COALESSING_STOP_THRESHOLD_DEFAULT;
+	ahd->int_coalescing_timer = AHD_INT_COALESCING_TIMER_DEFAULT;
+	ahd->int_coalescing_maxcmds = AHD_INT_COALESCING_MAXCMDS_DEFAULT;
+	ahd->int_coalescing_mincmds = AHD_INT_COALESCING_MINCMDS_DEFAULT;
+	ahd->int_coalescing_threshold = AHD_INT_COALESCING_THRESHOLD_DEFAULT;
+	ahd->int_coalescing_stop_threshold =
+	    AHD_INT_COALESCING_STOP_THRESHOLD_DEFAULT;
 
 	if (ahd_platform_alloc(ahd, platform_arg) != 0) {
 		ahd_free(ahd);
@@ -5722,6 +5714,7 @@
 		next_scb->sg_list = segs;
 		next_scb->sense_data = sense_data;
 		next_scb->sense_busaddr = sense_busaddr;
+		memset(hscb, 0, sizeof(*hscb));
 		next_scb->hscb = hscb;
 		hscb->hscb_busaddr = ahd_htole32(hscb_busaddr);
 
@@ -6341,14 +6334,14 @@
 	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 3, (busaddr >> 24) & 0xFF);
 
 	/*
-	 * Default to coalessing disabled.
+	 * Default to coalescing disabled.
 	 */
-	ahd_outw(ahd, INT_COALESSING_CMDCOUNT, 0);
+	ahd_outw(ahd, INT_COALESCING_CMDCOUNT, 0);
 	ahd_outw(ahd, CMDS_PENDING, 0);
-	ahd_update_coalessing_values(ahd, ahd->int_coalessing_timer,
-				     ahd->int_coalessing_maxcmds,
-				     ahd->int_coalessing_mincmds);
-	ahd_enable_coalessing(ahd, FALSE);
+	ahd_update_coalescing_values(ahd, ahd->int_coalescing_timer,
+				     ahd->int_coalescing_maxcmds,
+				     ahd->int_coalescing_mincmds);
+	ahd_enable_coalescing(ahd, FALSE);
 
 	ahd_loadseq(ahd);
 	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
@@ -6601,30 +6594,30 @@
 }
 
 void
-ahd_update_coalessing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds,
+ahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds,
 			     u_int mincmds)
 {
 	if (timer > AHD_TIMER_MAX_US)
 		timer = AHD_TIMER_MAX_US;
-	ahd->int_coalessing_timer = timer;
+	ahd->int_coalescing_timer = timer;
 
-	if (maxcmds > AHD_INT_COALESSING_MAXCMDS_MAX)
-		maxcmds = AHD_INT_COALESSING_MAXCMDS_MAX;
-	if (mincmds > AHD_INT_COALESSING_MINCMDS_MAX)
-		mincmds = AHD_INT_COALESSING_MINCMDS_MAX;
-	ahd->int_coalessing_maxcmds = maxcmds;
-	ahd_outw(ahd, INT_COALESSING_TIMER, timer / AHD_TIMER_US_PER_TICK);
-	ahd_outb(ahd, INT_COALESSING_MAXCMDS, -maxcmds);
-	ahd_outb(ahd, INT_COALESSING_MINCMDS, -mincmds);
+	if (maxcmds > AHD_INT_COALESCING_MAXCMDS_MAX)
+		maxcmds = AHD_INT_COALESCING_MAXCMDS_MAX;
+	if (mincmds > AHD_INT_COALESCING_MINCMDS_MAX)
+		mincmds = AHD_INT_COALESCING_MINCMDS_MAX;
+	ahd->int_coalescing_maxcmds = maxcmds;
+	ahd_outw(ahd, INT_COALESCING_TIMER, timer / AHD_TIMER_US_PER_TICK);
+	ahd_outb(ahd, INT_COALESCING_MAXCMDS, -maxcmds);
+	ahd_outb(ahd, INT_COALESCING_MINCMDS, -mincmds);
 }
 
 void
-ahd_enable_coalessing(struct ahd_softc *ahd, int enable)
+ahd_enable_coalescing(struct ahd_softc *ahd, int enable)
 {
 
-	ahd->hs_mailbox &= ~ENINT_COALESS;
+	ahd->hs_mailbox &= ~ENINT_COALESCE;
 	if (enable)
-		ahd->hs_mailbox |= ENINT_COALESS;
+		ahd->hs_mailbox |= ENINT_COALESCE;
 	ahd_outb(ahd, HS_MAILBOX, ahd->hs_mailbox);
 	ahd_flush_device_writes(ahd);
 	ahd_run_qoutfifo(ahd);
@@ -7718,20 +7711,20 @@
 	}
 	ahd_lock(ahd, &s);
 
-	enint_coal = ahd->hs_mailbox & ENINT_COALESS;
-	if (ahd->cmdcmplt_total > ahd->int_coalessing_threshold)
-		enint_coal |= ENINT_COALESS;
-	else if (ahd->cmdcmplt_total < ahd->int_coalessing_stop_threshold)
-		enint_coal &= ~ENINT_COALESS;
+	enint_coal = ahd->hs_mailbox & ENINT_COALESCE;
+	if (ahd->cmdcmplt_total > ahd->int_coalescing_threshold)
+		enint_coal |= ENINT_COALESCE;
+	else if (ahd->cmdcmplt_total < ahd->int_coalescing_stop_threshold)
+		enint_coal &= ~ENINT_COALESCE;
 
-	if (enint_coal != (ahd->hs_mailbox & ENINT_COALESS)) {
-		ahd_enable_coalessing(ahd, enint_coal);
+	if (enint_coal != (ahd->hs_mailbox & ENINT_COALESCE)) {
+		ahd_enable_coalescing(ahd, enint_coal);
 #ifdef AHD_DEBUG
-		if ((ahd_debug & AHD_SHOW_INT_COALESSING) != 0)
-			printf("%s: Interrupt coalessing "
+		if ((ahd_debug & AHD_SHOW_INT_COALESCING) != 0)
+			printf("%s: Interrupt coalescing "
 			       "now %sabled. Cmds %d\n",
 			       ahd_name(ahd),
-			       (enint_coal & ENINT_COALESS) ? "en" : "dis",
+			       (enint_coal & ENINT_COALESCE) ? "en" : "dis",
 			       ahd->cmdcmplt_total);
 #endif
 	}
@@ -8279,8 +8272,6 @@
 	download_consts[PKT_OVERRUN_BUFOFFSET] =
 		(ahd->overrun_buf - (uint8_t *)ahd->qoutfifo) / 256;
 	download_consts[SCB_TRANSFER_SIZE] = SCB_TRANSFER_SIZE_1BYTE_LUN;
-	if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0)
-		download_consts[SCB_TRANSFER_SIZE] = SCB_TRANSFER_SIZE_FULL_LUN;
 	cur_patch = patches;
 	downloaded = 0;
 	skip_addr = 0;
@@ -8509,7 +8500,7 @@
 }
 
 void
-ahd_dump_all_cards_state()
+ahd_dump_all_cards_state(void)
 {
 	struct ahd_softc *list_ahd;
 
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_inline.h b/drivers/scsi/aic7xxx/aic79xx_inline.h
--- a/drivers/scsi/aic7xxx/aic79xx_inline.h	Thu May  1 10:00:20 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_inline.h	Fri May 23 10:55:34 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#48 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#50 $
  *
  * $FreeBSD$
  */
@@ -271,11 +271,12 @@
 	scb->crc_retry_count = 0;
 	if ((scb->flags & SCB_PACKETIZED) != 0) {
 		/* XXX what about ACA??  It is type 4, but TAG_TYPE == 0x3. */
-		scb->hscb->task_attribute= scb->hscb->control & SCB_TAG_TYPE;
-		/*
-		 * For Rev A short lun workaround.
-		 */
-		scb->hscb->pkt_long_lun[6] = scb->hscb->lun;
+		scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE;
+	} else {
+		if (ahd_get_transfer_length(scb) & 0x01)
+			scb->hscb->task_attribute = SCB_XFERLEN_ODD;
+		else
+			scb->hscb->task_attribute = 0;
 	}
 
 	if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c	Thu May  8 11:24:16 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c	Fri May 23 10:58:23 2003
@@ -1,7 +1,7 @@
 /*
  * Adaptec AIC79xx device driver for Linux.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#160 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#169 $
  *
  * --------------------------------------------------------------------------
  * Copyright (c) 1994-2000 Justin T. Gibbs.
@@ -62,11 +62,6 @@
 
 #include <linux/mm.h>		/* For fetching system memory size */
 
-#define __KERNEL_SYSCALLS__
-
-#include <linux/unistd.h>
-static int errno;
-
 /*
  * Lock protecting manipulation of the ahd softc list.
  */
@@ -755,31 +750,11 @@
 	consumed = 1;
 	sg->addr = ahd_htole32(addr & 0xFFFFFFFF);
 	scb->platform_data->xfer_len += len;
+
 	if (sizeof(bus_addr_t) > 4
-	 && (ahd->flags & AHD_39BIT_ADDRESSING) != 0) {
-		/*
-		 * Due to DAC restrictions, we can't
-		 * cross a 4GB boundary.
-		 */
-		if ((addr ^ (addr + len - 1)) & ~0xFFFFFFFF) {
-			struct	 ahd_dma_seg *next_sg;
-			uint32_t next_len;
-
-			printf("Crossed Seg\n");
-			if ((scb->sg_count + 2) > AHD_NSEG)
-				panic("Too few segs for dma mapping.  "
-				      "Increase AHD_NSEG\n");
-
-			consumed++;
-			next_sg = sg + 1;
-			next_sg->addr = 0;
-			next_len = 0x100000000 - (addr & 0xFFFFFFFF);
-			len -= next_len;
-			next_len |= ((addr >> 8) + 0x1000000) & 0x7F000000;
-			next_sg->len = ahd_htole32(next_len);
-		}
-		len |= (addr >> 8) & 0x7F000000;
-	}
+	 && (ahd->flags & AHD_39BIT_ADDRESSING) != 0)
+		len |= (addr >> 8) & AHD_SG_HIGH_ADDR_MASK;
+
 	sg->len = ahd_htole32(len);
 	return (consumed);
 }
@@ -796,14 +771,18 @@
 static int	   ahd_linux_slave_alloc(Scsi_Device *);
 static int	   ahd_linux_slave_configure(Scsi_Device *);
 static void	   ahd_linux_slave_destroy(Scsi_Device *);
+#if defined(__i386__)
 static int	   ahd_linux_biosparam(struct scsi_device*,
 				       struct block_device*, sector_t, int[]);
+#endif
 #else
 static int	   ahd_linux_release(struct Scsi_Host *);
 static void	   ahd_linux_select_queue_depth(struct Scsi_Host *host,
 						Scsi_Device *scsi_devs);
+#if defined(__i386__)
 static int	   ahd_linux_biosparam(Disk *, kdev_t, int[]);
 #endif
+#endif
 static int	   ahd_linux_bus_reset(Scsi_Cmnd *);
 static int	   ahd_linux_dev_reset(Scsi_Cmnd *);
 static int	   ahd_linux_abort(Scsi_Cmnd *);
@@ -1211,6 +1190,7 @@
 }
 #endif
 
+#if defined(__i386__)
 /*
  * Return the disk geometry for the given SCSI device.
  */
@@ -1273,6 +1253,7 @@
 	geom[2] = cylinders;
 	return (0);
 }
+#endif
 
 /*
  * Abort the current SCSI command(s).
@@ -2198,7 +2179,7 @@
 }
 
 uint64_t
-ahd_linux_get_memsize()
+ahd_linux_get_memsize(void)
 {
 	struct sysinfo si;
 
@@ -2213,7 +2194,7 @@
  * scenario.
  */
 static int
-ahd_linux_next_unit()
+ahd_linux_next_unit(void)
 {
 	struct ahd_softc *ahd;
 	int unit;
@@ -2955,13 +2936,11 @@
 			struct ahd_devinfo *devinfo,
 			struct ahd_linux_target *targ)
 {
-	cam_status cam_status;
 	u_int32_t status;
-	u_int scsi_status;
 
-	scsi_status = ahd_cmd_get_scsi_status(cmd);
-	cam_status = ahd_cmd_get_transaction_status(cmd);
-	status = aic_error_action(cmd, targ->inq_data, cam_status, scsi_status);
+	status = aic_error_action(cmd, targ->inq_data,
+				  ahd_cmd_get_transaction_status(cmd),
+				  ahd_cmd_get_scsi_status(cmd));
 
 	
 #ifdef AHD_DEBUG
@@ -4211,7 +4190,7 @@
 /*
  * SCSI controller interrupt handler.
  */
-AIC_LINUX_IRQRETURN_T
+irqreturn_t
 ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct	ahd_softc *ahd;
@@ -4225,7 +4204,7 @@
 		ahd_schedule_runq(ahd);
 	ahd_linux_run_complete_queue(ahd);
 	ahd_unlock(ahd, &flags);
-	AIC_LINUX_IRQRETURN(ours);
+	return IRQ_RETVAL(ours);
 }
 
 void
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h	Mon May 12 20:52:59 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h	Mon May 26 19:01:56 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#130 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#133 $
  *
  */
 #ifndef _AIC79XX_LINUX_H_
@@ -293,7 +293,7 @@
 #define AHD_SCSI_HAS_HOST_LOCK 0
 #endif
 
-#define AIC79XX_DRIVER_VERSION "1.3.8"
+#define AIC79XX_DRIVER_VERSION "1.3.9"
 
 /**************************** Front End Queues ********************************/
 /*
@@ -1006,7 +1006,7 @@
 	(((dev_softc)->dma_mask = mask) && 0)
 #endif
 /**************************** Proc FS Support *********************************/
-int	ahd_linux_proc_info(char *, char **, off_t, int, int, int);
+int	ahd_linux_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
 
 /*************************** Domain Validation ********************************/
 #define AHD_DV_CMD(cmd) ((cmd)->scsi_done == ahd_linux_dv_complete)
@@ -1211,7 +1211,7 @@
 int	ahd_platform_abort_scbs(struct ahd_softc *ahd, int target,
 				char channel, int lun, u_int tag,
 				role_t role, uint32_t status);
-AIC_LINUX_IRQRETURN_T
+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 *);
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c	Mon Mar 10 16:57:17 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c	Wed May 14 15:00:40 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_pci.c#21 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#23 $
  */
 
 #include "aic79xx_osm.h"
@@ -156,19 +156,21 @@
 	pci_set_master(pdev);
 
 	if (sizeof(bus_addr_t) > 4) {
-		uint64_t memsize;
+		uint64_t   memsize;
+		bus_addr_t mask_64bit;
+		bus_addr_t mask_39bit;
 
 		memsize = ahd_linux_get_memsize();
-		if (memsize >= 0x8000000000
-	 	 && ahd_pci_set_dma_mask(pdev, 0xFFFFFFFFFFFFFFFFULL) == 0) {
+		mask_64bit = (bus_addr_t)(0xFFFFFFFFFFFFFFFFULL&(bus_addr_t)~0);
+		mask_39bit = (bus_addr_t)(0x7FFFFFFFFFULL&(bus_addr_t)~0);
+		if (memsize >= 0x8000000000ULL
+	 	 && ahd_pci_set_dma_mask(pdev, mask_64bit) == 0) {
 			ahd->flags |= AHD_64BIT_ADDRESSING;
-			ahd->platform_data->hw_dma_mask =
-			    (bus_addr_t)(0xFFFFFFFFFFFFFFFFULL&(bus_addr_t)~0);
+			ahd->platform_data->hw_dma_mask = mask_64bit;
 		} else if (memsize > 0x80000000
-			&& ahd_pci_set_dma_mask(pdev, 0x7FFFFFFFFFULL) == 0) {
+			&& ahd_pci_set_dma_mask(pdev, mask_39bit) == 0) {
 			ahd->flags |= AHD_39BIT_ADDRESSING;
-			ahd->platform_data->hw_dma_mask =
-			    (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0);
+			ahd->platform_data->hw_dma_mask = mask_39bit;
 		}
 	} else {
 		ahd_pci_set_dma_mask(pdev, 0xFFFFFFFF);
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c	Thu May  1 10:00:20 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c	Tue May 20 14:03:03 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#71 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#73 $
  *
  * $FreeBSD$
  */
@@ -65,28 +65,29 @@
 }
 
 #define ID_ALL_MASK			0xFFFFFFFFFFFFFFFFull
+#define ID_ALL_IROC_MASK		0xFFFFFF7FFFFFFFFFull
 #define ID_DEV_VENDOR_MASK		0xFFFFFFFF00000000ull
 #define ID_9005_GENERIC_MASK		0xFFF0FFFF00000000ull
+#define ID_9005_GENERIC_IROC_MASK	0xFFF0FF7F00000000ull
 
 #define ID_AIC7901			0x800F9005FFFF9005ull
-#define ID_AIC7901A			0x801E9005FFFF9005ull
-#define ID_AIC7901A_IROC		0x809E9005FFFF9005ull
 #define ID_AHA_29320A			0x8000900500609005ull
+#define ID_AHA_29320ALP			0x8017900500449005ull
+
+#define ID_AIC7901A			0x801E9005FFFF9005ull
+#define ID_AHA_29320			0x8012900500429005ull
+#define ID_AHA_29320B			0x8013900500439005ull
 #define ID_AHA_29320LP			0x8014900500449005ull
-#define ID_AHA_29320LP_IROC		0x8094900500449005ull
 
 #define ID_AIC7902			0x801F9005FFFF9005ull
-#define ID_AIC7902_IROC			0x809F9005FFFF9005ull
 #define ID_AIC7902_B			0x801D9005FFFF9005ull
-#define ID_AIC7902_B_IROC		0x809D9005FFFF9005ull
 #define ID_AHA_39320			0x8010900500409005ull
+#define ID_AHA_39320_B			0x8015900500409005ull
 #define ID_AHA_39320A			0x8016900500409005ull
 #define ID_AHA_39320D			0x8011900500419005ull
 #define ID_AHA_39320D_B			0x801C900500419005ull
 #define ID_AHA_39320D_HP		0x8011900500AC0E11ull
 #define ID_AHA_39320D_B_HP		0x801C900500AC0E11ull
-#define ID_AHA_29320			0x8012900500429005ull
-#define ID_AHA_29320B			0x8013900500439005ull
 #define ID_AIC7902_PCI_REV_A4		0x3
 #define ID_AIC7902_PCI_REV_B0		0x10
 #define SUBID_HP			0x0E11
@@ -113,22 +114,42 @@
 #define		SUBID_9005_SEEPTYPE_NONE	0x0
 #define		SUBID_9005_SEEPTYPE_4K		0x1
 
+static ahd_device_setup_t ahd_aic7901_setup;
 static ahd_device_setup_t ahd_aic7901A_setup;
 static ahd_device_setup_t ahd_aic7902_setup;
 
 struct ahd_pci_identity ahd_pci_ident_table [] =
 {
+	/* aic7901 based controllers */
+	{
+		ID_AHA_29320A,
+		ID_ALL_MASK,
+		"Adaptec 29320A Ultra320 SCSI adapter",
+		ahd_aic7901_setup
+	},
+	{
+		ID_AHA_29320ALP,
+		ID_ALL_MASK,
+		"Adaptec 29320ALP Ultra320 SCSI adapter",
+		ahd_aic7901_setup
+	},
 	/* aic7901A based controllers */
 	{
-		ID_AHA_29320LP,
+		ID_AHA_29320,
 		ID_ALL_MASK,
-		"Adaptec 29320LP Ultra320 SCSI adapter",
+		"Adaptec 29320 Ultra320 SCSI adapter",
 		ahd_aic7901A_setup
 	},
 	{
-		ID_AHA_29320A,
+		ID_AHA_29320B,
 		ID_ALL_MASK,
-		"Adaptec 29320A Ultra320 SCSI adapter",
+		"Adaptec 29320B Ultra320 SCSI adapter",
+		ahd_aic7901A_setup
+	},
+	{
+		ID_AHA_29320LP,
+		ID_ALL_MASK,
+		"Adaptec 29320LP Ultra320 SCSI adapter",
 		ahd_aic7901A_setup
 	},
 	/* aic7902 based controllers */	
@@ -139,6 +160,12 @@
 		ahd_aic7902_setup
 	},
 	{
+		ID_AHA_39320_B,
+		ID_ALL_MASK,
+		"Adaptec 39320 Ultra320 SCSI adapter",
+		ahd_aic7902_setup
+	},
+	{
 		ID_AHA_39320A,
 		ID_ALL_MASK,
 		"Adaptec 39320A Ultra320 SCSI adapter",
@@ -182,6 +209,12 @@
 	},
 	/* Generic chip probes for devices we don't know 'exactly' */
 	{
+		ID_AIC7901 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec AIC7901 Ultra320 SCSI adapter",
+		ahd_aic7901_setup
+	},
+	{
 		ID_AIC7901A & ID_DEV_VENDOR_MASK,
 		ID_DEV_VENDOR_MASK,
 		"Adaptec AIC7901A Ultra320 SCSI adapter",
@@ -332,9 +365,9 @@
 	}
 	
 	/* Ensure busmastering is enabled */
-	command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/1);
+	command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2);
 	command |= PCIM_CMD_BUSMASTEREN;
-	ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/1);
+	ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/2);
 
 	error = ahd_softc_init(ahd);
 	if (error != 0)
@@ -868,6 +901,18 @@
 }
 
 static int
+ahd_aic7901_setup(struct ahd_softc *ahd)
+{
+	int error;
+
+	error = ahd_aic7902_setup(ahd);
+	if (error != 0)
+		return (error);
+	ahd->chip = AHD_AIC7901;
+	return (0);
+}
+
+static int
 ahd_aic7901A_setup(struct ahd_softc *ahd)
 {
 	int error;
@@ -890,7 +935,7 @@
 	if (rev < ID_AIC7902_PCI_REV_A4) {
 		printf("%s: Unable to attach to unsupported chip revision %d\n",
 		       ahd_name(ahd), rev);
-		ahd_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/1);
+		ahd_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/2);
 		return (ENXIO);
 	}
 	ahd->channel = ahd_get_pci_function(pci) + 'A';
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c
--- a/drivers/scsi/aic7xxx/aic79xx_proc.c	Thu Apr 24 14:10:07 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_proc.c	Mon May 12 08:30:19 2003
@@ -278,8 +278,8 @@
  * Return information to handle /proc support for the driver.
  */
 int
-ahd_linux_proc_info(char *buffer, char **start, off_t offset,
-		  int length, int hostno, int inout)
+ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset,
+		  int length, int inout)
 {
 	struct	ahd_softc *ahd;
 	struct	info_str info;
@@ -292,7 +292,7 @@
 	retval = -EINVAL;
 	ahd_list_lock(&l);
 	TAILQ_FOREACH(ahd, &ahd_tailq, links) {
-		if (ahd->platform_data->host->host_no == hostno)
+		if (ahd->platform_data->host == shost)
 			break;
 	}
 
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	Thu Apr 24 11:46:35 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped	Fri May 23 10:55:34 2003
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#69 $
  */
 typedef int (ahd_reg_print_t)(u_int, u_int *, u_int);
 typedef struct ahd_reg_parse_entry {
@@ -2134,24 +2134,24 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_int_coalessing_timer_print;
+ahd_reg_print_t ahd_int_coalescing_timer_print;
 #else
-#define ahd_int_coalessing_timer_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INT_COALESSING_TIMER", 0x14a, regvalue, cur_col, wrap)
+#define ahd_int_coalescing_timer_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "INT_COALESCING_TIMER", 0x14a, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_int_coalessing_maxcmds_print;
+ahd_reg_print_t ahd_int_coalescing_maxcmds_print;
 #else
-#define ahd_int_coalessing_maxcmds_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INT_COALESSING_MAXCMDS", 0x14c, regvalue, cur_col, wrap)
+#define ahd_int_coalescing_maxcmds_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "INT_COALESCING_MAXCMDS", 0x14c, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_int_coalessing_mincmds_print;
+ahd_reg_print_t ahd_int_coalescing_mincmds_print;
 #else
-#define ahd_int_coalessing_mincmds_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INT_COALESSING_MINCMDS", 0x14d, regvalue, cur_col, wrap)
+#define ahd_int_coalescing_mincmds_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "INT_COALESCING_MINCMDS", 0x14d, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -2162,10 +2162,10 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_int_coalessing_cmdcount_print;
+ahd_reg_print_t ahd_int_coalescing_cmdcount_print;
 #else
-#define ahd_int_coalessing_cmdcount_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INT_COALESSING_CMDCOUNT", 0x150, regvalue, cur_col, wrap)
+#define ahd_int_coalescing_cmdcount_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "INT_COALESCING_CMDCOUNT", 0x150, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -2432,7 +2432,7 @@
 
 #define	HS_MAILBOX      		0x0b
 #define		HOST_TQINPOS    	0x80
-#define		ENINT_COALESS   	0x40
+#define		ENINT_COALESCE  	0x40
 
 #define	CLRSEQINTSTAT   		0x0c
 #define		CLRSEQ_SWTMRTO  	0x10
@@ -3612,15 +3612,15 @@
 
 #define	ALLOCFIFO_SCBPTR		0x148
 
-#define	INT_COALESSING_TIMER		0x14a
+#define	INT_COALESCING_TIMER		0x14a
 
-#define	INT_COALESSING_MAXCMDS		0x14c
+#define	INT_COALESCING_MAXCMDS		0x14c
 
-#define	INT_COALESSING_MINCMDS		0x14d
+#define	INT_COALESCING_MINCMDS		0x14d
 
 #define	CMDS_PENDING    		0x14e
 
-#define	INT_COALESSING_CMDCOUNT		0x150
+#define	INT_COALESCING_CMDCOUNT		0x150
 
 #define	LOCAL_HS_MAILBOX		0x151
 
@@ -3683,6 +3683,7 @@
 #define		LID             	0xff
 
 #define	SCB_TASK_ATTRIBUTE		0x1ab
+#define		SCB_XFERLEN_ODD 	0x01
 
 #define	SCB_CDB_LEN     		0x1ac
 #define		SCB_CDB_LEN_PTR 	0x80
@@ -3768,5 +3769,5 @@
 
 
 /* Exported Labels */
-#define	LABEL_seq_isr 	0x270
-#define	LABEL_timer_isr	0x26c
+#define	LABEL_seq_isr 	0x269
+#define	LABEL_timer_isr	0x265
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	Thu Apr 24 11:46:35 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped	Tue May 20 14:05:24 2003
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#93 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#68 $
  */
 
 #include "aic79xx_osm.h"
@@ -161,7 +161,7 @@
 }
 
 static ahd_reg_parse_entry_t HS_MAILBOX_parse_table[] = {
-	{ "ENINT_COALESS",	0x40, 0x40 },
+	{ "ENINT_COALESCE",	0x40, 0x40 },
 	{ "HOST_TQINPOS",	0x80, 0x80 }
 };
 
@@ -3375,23 +3375,23 @@
 }
 
 int
-ahd_int_coalessing_timer_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_int_coalescing_timer_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "INT_COALESSING_TIMER",
+	return (ahd_print_register(NULL, 0, "INT_COALESCING_TIMER",
 	    0x14a, regvalue, cur_col, wrap));
 }
 
 int
-ahd_int_coalessing_maxcmds_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_int_coalescing_maxcmds_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "INT_COALESSING_MAXCMDS",
+	return (ahd_print_register(NULL, 0, "INT_COALESCING_MAXCMDS",
 	    0x14c, regvalue, cur_col, wrap));
 }
 
 int
-ahd_int_coalessing_mincmds_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_int_coalescing_mincmds_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "INT_COALESSING_MINCMDS",
+	return (ahd_print_register(NULL, 0, "INT_COALESCING_MINCMDS",
 	    0x14d, regvalue, cur_col, wrap));
 }
 
@@ -3403,9 +3403,9 @@
 }
 
 int
-ahd_int_coalessing_cmdcount_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_int_coalescing_cmdcount_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "INT_COALESSING_CMDCOUNT",
+	return (ahd_print_register(NULL, 0, "INT_COALESCING_CMDCOUNT",
 	    0x150, regvalue, cur_col, wrap));
 }
 
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	Thu Apr 24 11:46:35 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped	Fri May 23 10:55:34 2003
@@ -2,30 +2,30 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#69 $
  */
 static uint8_t seqprog[] = {
 	0xff, 0x02, 0x06, 0x78,
-	0x00, 0xea, 0x4e, 0x59,
+	0x00, 0xea, 0x50, 0x59,
 	0x01, 0xea, 0x04, 0x30,
 	0xff, 0x04, 0x0c, 0x78,
-	0x19, 0xea, 0x4e, 0x59,
+	0x19, 0xea, 0x50, 0x59,
 	0x19, 0xea, 0x04, 0x00,
-	0x33, 0xea, 0x42, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x60, 0x3a, 0x1a, 0x68,
 	0x04, 0x47, 0x1b, 0x68,
 	0xff, 0x21, 0x1b, 0x70,
-	0x40, 0x4b, 0x90, 0x69,
-	0x00, 0xe2, 0x52, 0x59,
-	0x40, 0x4b, 0x90, 0x69,
-	0x20, 0x4b, 0x80, 0x69,
+	0x40, 0x4b, 0x92, 0x69,
+	0x00, 0xe2, 0x54, 0x59,
+	0x40, 0x4b, 0x92, 0x69,
+	0x20, 0x4b, 0x82, 0x69,
 	0xfc, 0x42, 0x24, 0x78,
 	0x10, 0x40, 0x24, 0x78,
-	0x00, 0xe2, 0xd2, 0x5d,
+	0x00, 0xe2, 0xc4, 0x5d,
 	0x20, 0x4d, 0x28, 0x78,
-	0x00, 0xe2, 0xd2, 0x5d,
+	0x00, 0xe2, 0xc4, 0x5d,
 	0x30, 0x3f, 0xc0, 0x09,
 	0x30, 0xe0, 0x30, 0x60,
 	0x7f, 0x4a, 0x94, 0x08,
@@ -35,7 +35,7 @@
 	0x00, 0xe2, 0x56, 0x58,
 	0x00, 0xe2, 0x66, 0x58,
 	0x00, 0xe2, 0x06, 0x40,
-	0x33, 0xea, 0x42, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x01, 0x52, 0x64, 0x78,
 	0x02, 0x58, 0x50, 0x31,
@@ -43,26 +43,26 @@
 	0xff, 0xad, 0x4f, 0x78,
 	0x50, 0x4b, 0x4a, 0x68,
 	0xbf, 0x3a, 0x74, 0x08,
-	0x14, 0xea, 0x4e, 0x59,
+	0x14, 0xea, 0x50, 0x59,
 	0x14, 0xea, 0x04, 0x00,
 	0x08, 0xa8, 0x51, 0x03,
 	0xff, 0xae, 0x3f, 0x68,
-	0x00, 0xe2, 0x50, 0x5b,
+	0x00, 0xe2, 0x56, 0x5b,
 	0x00, 0xe2, 0x3e, 0x40,
-	0x00, 0xea, 0x42, 0x59,
+	0x00, 0xea, 0x44, 0x59,
 	0x01, 0xea, 0x00, 0x30,
 	0x80, 0xf9, 0x5e, 0x68,
-	0x00, 0xe2, 0x40, 0x59,
-	0x11, 0xea, 0x42, 0x59,
+	0x00, 0xe2, 0x42, 0x59,
+	0x11, 0xea, 0x44, 0x59,
 	0x11, 0xea, 0x00, 0x00,
-	0x80, 0xf9, 0x40, 0x79,
+	0x80, 0xf9, 0x42, 0x79,
 	0xff, 0xea, 0xd4, 0x0d,
-	0x22, 0xea, 0x42, 0x59,
+	0x22, 0xea, 0x44, 0x59,
 	0x22, 0xea, 0x00, 0x00,
 	0x10, 0x16, 0x70, 0x78,
 	0x01, 0x0b, 0xa2, 0x32,
 	0x10, 0x16, 0x2c, 0x00,
-	0x18, 0xad, 0xfe, 0x78,
+	0x18, 0xad, 0x00, 0x79,
 	0x04, 0xad, 0xca, 0x68,
 	0x80, 0xad, 0x64, 0x78,
 	0x10, 0xad, 0x98, 0x78,
@@ -71,15 +71,15 @@
 	0x02, 0x8c, 0x59, 0x32,
 	0x02, 0x28, 0x19, 0x33,
 	0x02, 0xa8, 0x50, 0x36,
-	0x33, 0xea, 0x42, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x40, 0x3a, 0x64, 0x68,
 	0x50, 0x4b, 0x64, 0x68,
-	0x22, 0xea, 0x42, 0x59,
+	0x22, 0xea, 0x44, 0x59,
 	0x22, 0xea, 0x00, 0x00,
 	0xe7, 0xad, 0x5a, 0x09,
 	0x02, 0x8c, 0x59, 0x32,
-	0x1a, 0xea, 0x4e, 0x59,
+	0x1a, 0xea, 0x50, 0x59,
 	0x1a, 0xea, 0x04, 0x00,
 	0xff, 0xea, 0xd4, 0x0d,
 	0xe7, 0xad, 0x5a, 0x09,
@@ -113,29 +113,30 @@
 	0xff, 0xea, 0xc0, 0x09,
 	0x01, 0x4e, 0x9d, 0x1a,
 	0x00, 0x4f, 0x9f, 0x22,
+	0x01, 0xaa, 0x6d, 0x33,
 	0x01, 0xea, 0x5c, 0x33,
 	0x04, 0xa4, 0x49, 0x32,
 	0xff, 0xea, 0x4a, 0x03,
 	0xff, 0xea, 0x4e, 0x03,
 	0x01, 0x10, 0xd4, 0x31,
-	0x10, 0xa8, 0xf3, 0x68,
+	0x10, 0xa8, 0xf5, 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, 0xf2, 0x70,
+	0xff, 0xa9, 0xf4, 0x70,
 	0x02, 0xa0, 0x48, 0x37,
-	0xff, 0x21, 0xfb, 0x70,
+	0xff, 0x21, 0xfd, 0x70,
 	0x02, 0x22, 0x51, 0x31,
 	0x02, 0xa0, 0x4c, 0x33,
 	0x02, 0xa0, 0x44, 0x36,
 	0x02, 0xa0, 0x40, 0x32,
 	0x02, 0xa0, 0x44, 0x36,
-	0x04, 0x47, 0x03, 0x69,
-	0x40, 0x16, 0x2e, 0x69,
-	0xff, 0x2d, 0x33, 0x61,
+	0x04, 0x47, 0x05, 0x69,
+	0x40, 0x16, 0x30, 0x69,
+	0xff, 0x2d, 0x35, 0x61,
 	0xff, 0x29, 0x65, 0x70,
 	0x01, 0x37, 0xc1, 0x31,
 	0x02, 0x28, 0x55, 0x32,
@@ -148,20 +149,20 @@
 	0x01, 0x50, 0xa1, 0x1a,
 	0xff, 0x4e, 0x9d, 0x1a,
 	0xff, 0x4f, 0x9f, 0x22,
-	0xff, 0x8d, 0x27, 0x71,
-	0x80, 0xac, 0x26, 0x71,
-	0x20, 0x16, 0x26, 0x69,
+	0xff, 0x8d, 0x29, 0x71,
+	0x80, 0xac, 0x28, 0x71,
+	0x20, 0x16, 0x28, 0x69,
 	0x02, 0x8c, 0x51, 0x31,
-	0x00, 0xe2, 0x10, 0x41,
+	0x00, 0xe2, 0x12, 0x41,
 	0x01, 0xac, 0x08, 0x31,
 	0x09, 0xea, 0x5a, 0x01,
 	0x02, 0x8c, 0x51, 0x32,
 	0xff, 0xea, 0x1a, 0x07,
 	0x04, 0x24, 0xf9, 0x30,
-	0x1d, 0xea, 0x38, 0x41,
+	0x1d, 0xea, 0x3a, 0x41,
 	0x02, 0x2c, 0x51, 0x31,
 	0x04, 0xa0, 0xf9, 0x30,
-	0x19, 0xea, 0x38, 0x41,
+	0x19, 0xea, 0x3a, 0x41,
 	0x06, 0xea, 0x08, 0x81,
 	0x01, 0xe2, 0x5a, 0x35,
 	0x02, 0xf2, 0xf0, 0x35,
@@ -179,23 +180,23 @@
 	0x02, 0x20, 0xb9, 0x30,
 	0x02, 0x20, 0x51, 0x31,
 	0x4c, 0xa9, 0xd7, 0x28,
-	0x10, 0xa8, 0x61, 0x79,
+	0x10, 0xa8, 0x63, 0x79,
 	0x01, 0x6b, 0xc0, 0x30,
 	0x02, 0x64, 0xc8, 0x00,
 	0x40, 0x3a, 0x74, 0x04,
 	0x00, 0xe2, 0x56, 0x58,
-	0x33, 0xea, 0x42, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x30, 0x3f, 0xc0, 0x09,
-	0x30, 0xe0, 0x62, 0x61,
-	0x20, 0x3f, 0x78, 0x69,
-	0x10, 0x3f, 0x62, 0x79,
+	0x30, 0xe0, 0x64, 0x61,
+	0x20, 0x3f, 0x7a, 0x69,
+	0x10, 0x3f, 0x64, 0x79,
 	0x02, 0xea, 0x7e, 0x00,
-	0x00, 0xea, 0x42, 0x59,
+	0x00, 0xea, 0x44, 0x59,
 	0x01, 0xea, 0x00, 0x30,
 	0x02, 0x48, 0x51, 0x35,
 	0x01, 0xea, 0x7e, 0x00,
-	0x11, 0xea, 0x42, 0x59,
+	0x11, 0xea, 0x44, 0x59,
 	0x11, 0xea, 0x00, 0x00,
 	0x02, 0x48, 0x51, 0x35,
 	0x08, 0xea, 0x98, 0x00,
@@ -205,11 +206,11 @@
 	0x0f, 0x67, 0xc0, 0x09,
 	0x00, 0x34, 0x69, 0x02,
 	0x20, 0xea, 0x96, 0x00,
-	0x00, 0xe2, 0xf6, 0x41,
-	0x40, 0x3a, 0xac, 0x69,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x40, 0x3a, 0xae, 0x69,
 	0x02, 0x55, 0x06, 0x68,
-	0x02, 0x56, 0xac, 0x69,
-	0xff, 0x5b, 0xac, 0x61,
+	0x02, 0x56, 0xae, 0x69,
+	0xff, 0x5b, 0xae, 0x61,
 	0x02, 0x20, 0x51, 0x31,
 	0x80, 0xea, 0xb2, 0x01,
 	0x44, 0xea, 0x00, 0x00,
@@ -217,36 +218,36 @@
 	0x33, 0xea, 0x00, 0x00,
 	0xff, 0xea, 0xb2, 0x09,
 	0xff, 0xe0, 0xc0, 0x19,
-	0xff, 0xe0, 0xae, 0x79,
+	0xff, 0xe0, 0xb0, 0x79,
 	0x02, 0xa4, 0x51, 0x31,
-	0x00, 0xe2, 0xa4, 0x41,
+	0x00, 0xe2, 0xa6, 0x41,
 	0x02, 0x5e, 0x50, 0x31,
 	0x02, 0xa8, 0xb8, 0x30,
 	0x02, 0x5c, 0x50, 0x31,
-	0xff, 0xa5, 0xbf, 0x71,
+	0xff, 0xa5, 0xc1, 0x71,
 	0x02, 0xa4, 0x41, 0x31,
 	0x02, 0x22, 0x51, 0x31,
 	0x02, 0xa0, 0x4c, 0x33,
 	0x02, 0xa0, 0x44, 0x32,
-	0x00, 0xe2, 0xc8, 0x41,
-	0x10, 0xa8, 0xc9, 0x69,
+	0x00, 0xe2, 0xca, 0x41,
+	0x10, 0xa8, 0xcb, 0x69,
 	0x3d, 0xa9, 0xc9, 0x29,
 	0x01, 0xe4, 0xc8, 0x01,
 	0x01, 0xea, 0xca, 0x01,
 	0xff, 0xea, 0xda, 0x01,
 	0x02, 0x20, 0x51, 0x31,
 	0x02, 0xa6, 0x41, 0x32,
-	0xff, 0x21, 0xd1, 0x61,
+	0xff, 0x21, 0xd3, 0x61,
 	0xff, 0xea, 0x46, 0x02,
 	0x02, 0x5c, 0x50, 0x31,
 	0x40, 0xea, 0x96, 0x00,
-	0x02, 0x56, 0xda, 0x6d,
-	0x01, 0x55, 0xda, 0x6d,
-	0x10, 0xa8, 0xdd, 0x79,
-	0x10, 0x40, 0xe6, 0x69,
-	0x01, 0x56, 0xe6, 0x79,
+	0x02, 0x56, 0xcc, 0x6d,
+	0x01, 0x55, 0xcc, 0x6d,
+	0x10, 0xa8, 0xdf, 0x79,
+	0x10, 0x40, 0xe8, 0x69,
+	0x01, 0x56, 0xe8, 0x79,
 	0xff, 0xad, 0x07, 0x78,
-	0x13, 0xea, 0x4e, 0x59,
+	0x13, 0xea, 0x50, 0x59,
 	0x13, 0xea, 0x04, 0x00,
 	0x00, 0xe2, 0x06, 0x40,
 	0xbf, 0x3a, 0x74, 0x08,
@@ -257,104 +258,106 @@
 	0x40, 0xea, 0x66, 0x02,
 	0x08, 0x3c, 0x78, 0x00,
 	0x80, 0xea, 0x62, 0x02,
-	0x00, 0xe2, 0xb2, 0x5b,
+	0x00, 0xe2, 0xb8, 0x5b,
 	0x01, 0x36, 0xc1, 0x31,
-	0x9f, 0xe0, 0x54, 0x7c,
-	0x80, 0xe0, 0x0a, 0x72,
-	0xa0, 0xe0, 0x42, 0x72,
-	0xc0, 0xe0, 0x38, 0x72,
-	0xe0, 0xe0, 0x72, 0x72,
-	0x01, 0xea, 0x4e, 0x59,
+	0x9f, 0xe0, 0x4c, 0x7c,
+	0x80, 0xe0, 0x0c, 0x72,
+	0xa0, 0xe0, 0x44, 0x72,
+	0xc0, 0xe0, 0x3a, 0x72,
+	0xe0, 0xe0, 0x74, 0x72,
+	0x01, 0xea, 0x50, 0x59,
 	0x01, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xf6, 0x41,
-	0x80, 0x33, 0x11, 0x7a,
-	0x03, 0xea, 0x4e, 0x59,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x80, 0x33, 0x13, 0x7a,
+	0x03, 0xea, 0x50, 0x59,
 	0x03, 0xea, 0x04, 0x00,
-	0xee, 0x00, 0x18, 0x6a,
+	0xee, 0x00, 0x1a, 0x6a,
 	0x05, 0xea, 0xb4, 0x00,
-	0x33, 0xea, 0x42, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x02, 0xa8, 0x90, 0x32,
-	0x00, 0xe2, 0x68, 0x59,
+	0x00, 0xe2, 0x6a, 0x59,
 	0xef, 0xac, 0xd5, 0x19,
-	0x00, 0xe2, 0x28, 0x52,
+	0x00, 0xe2, 0x2a, 0x52,
 	0x09, 0x80, 0xe1, 0x30,
 	0x02, 0xea, 0x36, 0x00,
 	0xa8, 0xea, 0x32, 0x00,
-	0x00, 0xe2, 0x2e, 0x42,
+	0x00, 0xe2, 0x30, 0x42,
 	0x01, 0xac, 0xd1, 0x30,
 	0x10, 0x80, 0x89, 0x31,
 	0x20, 0xea, 0x32, 0x00,
 	0xbf, 0x33, 0x67, 0x0a,
-	0x20, 0x19, 0x30, 0x6a,
-	0x02, 0x4d, 0xf6, 0x69,
+	0x20, 0x19, 0x32, 0x6a,
+	0x02, 0x4d, 0xf8, 0x69,
 	0x40, 0x33, 0x67, 0x02,
-	0x00, 0xe2, 0xf6, 0x41,
-	0x80, 0x33, 0xaf, 0x6a,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x80, 0x33, 0xb5, 0x6a,
 	0x01, 0x44, 0x10, 0x33,
 	0x08, 0xa8, 0x51, 0x03,
-	0x00, 0xe2, 0xf6, 0x41,
+	0x00, 0xe2, 0xf8, 0x41,
 	0x10, 0xea, 0x80, 0x00,
 	0x01, 0x31, 0xc5, 0x31,
-	0x80, 0xe2, 0x5e, 0x62,
-	0x10, 0xa8, 0x83, 0x6a,
+	0x80, 0xe2, 0x60, 0x62,
+	0x10, 0xa8, 0x85, 0x6a,
 	0xc0, 0xaa, 0xc5, 0x01,
-	0x40, 0xa8, 0x4f, 0x6a,
+	0x40, 0xa8, 0x51, 0x6a,
 	0xbf, 0xe2, 0xc4, 0x09,
-	0x20, 0xa8, 0x63, 0x7a,
+	0x20, 0xa8, 0x65, 0x7a,
 	0x01, 0xe2, 0x88, 0x30,
-	0x00, 0xe2, 0xb2, 0x5b,
-	0xa0, 0x36, 0x6b, 0x62,
+	0x00, 0xe2, 0xb8, 0x5b,
+	0xa0, 0x36, 0x6d, 0x62,
 	0x23, 0xa8, 0x89, 0x08,
-	0x00, 0xe2, 0xb2, 0x5b,
-	0xa0, 0x36, 0x6b, 0x62,
-	0x00, 0xa8, 0x62, 0x42,
-	0xff, 0xe2, 0x62, 0x62,
-	0x00, 0xe2, 0x82, 0x42,
+	0x00, 0xe2, 0xb8, 0x5b,
+	0xa0, 0x36, 0x6d, 0x62,
+	0x00, 0xa8, 0x64, 0x42,
+	0xff, 0xe2, 0x64, 0x62,
+	0x00, 0xe2, 0x84, 0x42,
 	0x40, 0xea, 0x98, 0x00,
 	0x01, 0xe2, 0x88, 0x30,
-	0x00, 0xe2, 0xb2, 0x5b,
-	0xa0, 0x36, 0x41, 0x72,
+	0x00, 0xe2, 0xb8, 0x5b,
+	0xa0, 0x36, 0x43, 0x72,
 	0x40, 0xea, 0x98, 0x00,
 	0x01, 0x31, 0x89, 0x32,
 	0x08, 0xea, 0x62, 0x02,
-	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,
+	0x00, 0xe2, 0xf8, 0x41,
+	0xe0, 0xea, 0xd4, 0x5b,
+	0x80, 0xe0, 0xc0, 0x6a,
+	0x04, 0xe0, 0x66, 0x73,
+	0x02, 0xe0, 0x96, 0x73,
+	0x00, 0xea, 0x1e, 0x73,
+	0x03, 0xe0, 0xa6, 0x73,
+	0x23, 0xe0, 0x96, 0x72,
+	0x08, 0xe0, 0xbc, 0x72,
+	0x00, 0xe2, 0xb8, 0x5b,
+	0x07, 0xea, 0x50, 0x59,
 	0x07, 0xea, 0x04, 0x00,
-	0x08, 0x42, 0xf7, 0x71,
-	0x04, 0x42, 0x91, 0x62,
+	0x08, 0x42, 0xf9, 0x71,
+	0x04, 0x42, 0x93, 0x62,
 	0x01, 0x43, 0x89, 0x30,
-	0x00, 0xe2, 0x82, 0x42,
+	0x00, 0xe2, 0x84, 0x42,
 	0x01, 0x44, 0xd4, 0x31,
-	0x00, 0xe2, 0x82, 0x42,
+	0x00, 0xe2, 0x84, 0x42,
 	0x01, 0x00, 0x60, 0x32,
-	0x33, 0xea, 0x42, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x4c, 0x34, 0xc1, 0x28,
 	0x01, 0x64, 0xc0, 0x31,
-	0x00, 0x30, 0x43, 0x59,
+	0x00, 0x30, 0x45, 0x59,
 	0x01, 0x30, 0x01, 0x30,
-	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,
+	0x01, 0xe0, 0xba, 0x7a,
+	0xa0, 0xea, 0xca, 0x5b,
+	0x01, 0xa0, 0xba, 0x62,
+	0x01, 0x84, 0xaf, 0x7a,
+	0x01, 0xab, 0xbd, 0x6a,
+	0x05, 0xea, 0x50, 0x59,
+	0x05, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0xbc, 0x42,
+	0x03, 0xea, 0x50, 0x59,
 	0x03, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xb6, 0x42,
-	0x07, 0xea, 0xd6, 0x5b,
+	0x00, 0xe2, 0xbc, 0x42,
+	0x07, 0xea, 0xdc, 0x5b,
 	0x01, 0x44, 0xd4, 0x31,
-	0x00, 0xe2, 0xf6, 0x41,
+	0x00, 0xe2, 0xf8, 0x41,
 	0x3f, 0xe0, 0x6a, 0x0a,
 	0xc0, 0x34, 0xc1, 0x09,
 	0x00, 0x35, 0x51, 0x01,
@@ -365,54 +368,54 @@
 	0x01, 0xea, 0xc6, 0x01,
 	0x02, 0xe2, 0xc8, 0x31,
 	0x02, 0xec, 0x40, 0x31,
-	0xff, 0xa1, 0xd6, 0x72,
+	0xff, 0xa1, 0xdc, 0x72,
 	0x02, 0xe8, 0xda, 0x31,
 	0x02, 0xa0, 0x50, 0x31,
-	0x00, 0xe2, 0xf8, 0x42,
+	0x00, 0xe2, 0xfe, 0x42,
 	0x80, 0x33, 0x67, 0x02,
 	0x01, 0x44, 0xd4, 0x31,
-	0x00, 0xe2, 0xb2, 0x5b,
+	0x00, 0xe2, 0xb8, 0x5b,
 	0x01, 0x33, 0x67, 0x02,
-	0xe0, 0x36, 0x13, 0x63,
+	0xe0, 0x36, 0x19, 0x63,
 	0x02, 0x33, 0x67, 0x02,
-	0x20, 0x46, 0x0c, 0x63,
+	0x20, 0x46, 0x12, 0x63,
 	0xff, 0xea, 0x52, 0x09,
-	0xa8, 0xea, 0xc4, 0x5b,
-	0x04, 0xa8, 0xf3, 0x7a,
+	0xa8, 0xea, 0xca, 0x5b,
+	0x04, 0xa8, 0xf9, 0x7a,
 	0x01, 0x34, 0xc1, 0x31,
-	0x00, 0xa9, 0xf3, 0x62,
+	0x00, 0xa9, 0xf9, 0x62,
 	0x01, 0x35, 0xc1, 0x31,
-	0x00, 0xaa, 0xfd, 0x72,
+	0x00, 0xaa, 0x03, 0x73,
 	0x01, 0xa9, 0x52, 0x11,
-	0xff, 0xa9, 0xe8, 0x6a,
-	0x00, 0xe2, 0x0c, 0x43,
+	0xff, 0xa9, 0xee, 0x6a,
+	0x00, 0xe2, 0x12, 0x43,
 	0x10, 0x33, 0x67, 0x02,
-	0x04, 0xa8, 0x0d, 0x7b,
+	0x04, 0xa8, 0x13, 0x7b,
 	0xfb, 0xa8, 0x51, 0x0b,
 	0xff, 0xea, 0x66, 0x0a,
-	0x01, 0x9c, 0x07, 0x6b,
+	0x01, 0x9c, 0x0d, 0x6b,
 	0x02, 0xa8, 0x90, 0x32,
-	0x00, 0xe2, 0x68, 0x59,
-	0x10, 0xa8, 0xb7, 0x7a,
-	0xff, 0xea, 0xd6, 0x5b,
-	0x00, 0xe2, 0xb6, 0x42,
-	0x04, 0xea, 0x4e, 0x59,
+	0x00, 0xe2, 0x6a, 0x59,
+	0x10, 0xa8, 0xbd, 0x7a,
+	0xff, 0xea, 0xdc, 0x5b,
+	0x00, 0xe2, 0xbc, 0x42,
+	0x04, 0xea, 0x50, 0x59,
 	0x04, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xb6, 0x42,
-	0x04, 0xea, 0x4e, 0x59,
+	0x00, 0xe2, 0xbc, 0x42,
+	0x04, 0xea, 0x50, 0x59,
 	0x04, 0xea, 0x04, 0x00,
-	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,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x08, 0xa8, 0xb5, 0x7a,
+	0xc0, 0x33, 0x29, 0x7b,
+	0x80, 0x33, 0xb5, 0x6a,
+	0xff, 0x88, 0x29, 0x6b,
+	0x40, 0x33, 0xb5, 0x6a,
+	0x10, 0xa8, 0x2f, 0x7b,
+	0x0a, 0xea, 0x50, 0x59,
 	0x0a, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x48, 0x5b,
-	0x00, 0xe2, 0x7c, 0x43,
-	0x50, 0x4b, 0x30, 0x6b,
+	0x00, 0xe2, 0x4e, 0x5b,
+	0x00, 0xe2, 0x82, 0x43,
+	0x50, 0x4b, 0x36, 0x6b,
 	0xbf, 0x3a, 0x74, 0x08,
 	0x01, 0xe0, 0xf4, 0x31,
 	0xff, 0xea, 0xc0, 0x09,
@@ -422,25 +425,25 @@
 	0x01, 0xfa, 0xc0, 0x35,
 	0x02, 0xa8, 0x84, 0x32,
 	0x02, 0xea, 0xb4, 0x00,
-	0x33, 0xea, 0x42, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x02, 0x42, 0x51, 0x31,
 	0xff, 0xae, 0x65, 0x68,
-	0xff, 0x88, 0x55, 0x6b,
-	0x01, 0x9c, 0x51, 0x6b,
-	0x02, 0x9c, 0x59, 0x6b,
-	0x01, 0x84, 0x59, 0x7b,
+	0xff, 0x88, 0x5b, 0x6b,
+	0x01, 0x9c, 0x57, 0x6b,
+	0x02, 0x9c, 0x5f, 0x6b,
+	0x01, 0x84, 0x5f, 0x7b,
 	0x02, 0x28, 0x19, 0x33,
 	0x02, 0xa8, 0x50, 0x36,
-	0xff, 0x88, 0x59, 0x73,
-	0x00, 0xe2, 0x2c, 0x5b,
+	0xff, 0x88, 0x5f, 0x73,
+	0x00, 0xe2, 0x32, 0x5b,
 	0x02, 0xa8, 0x5c, 0x33,
 	0x02, 0x2c, 0x19, 0x33,
 	0x02, 0xa8, 0x58, 0x32,
 	0x04, 0x9c, 0x39, 0x07,
-	0xc0, 0x33, 0xaf, 0x6a,
+	0xc0, 0x33, 0xb5, 0x6a,
 	0x04, 0xa8, 0x51, 0x03,
-	0x20, 0xa8, 0x7d, 0x6b,
+	0x20, 0xa8, 0x83, 0x6b,
 	0x02, 0xa8, 0x40, 0x31,
 	0xc0, 0x34, 0xc1, 0x09,
 	0x00, 0x35, 0x51, 0x01,
@@ -455,56 +458,56 @@
 	0xf7, 0x57, 0xae, 0x08,
 	0x08, 0xea, 0x98, 0x00,
 	0x01, 0x44, 0xd4, 0x31,
-	0xee, 0x00, 0x86, 0x6b,
+	0xee, 0x00, 0x8c, 0x6b,
 	0x02, 0xea, 0xb4, 0x00,
-	0x00, 0xe2, 0xae, 0x5b,
-	0x09, 0x4c, 0x88, 0x7b,
+	0x00, 0xe2, 0xb4, 0x5b,
+	0x09, 0x4c, 0x8e, 0x7b,
 	0x08, 0x4c, 0x06, 0x68,
-	0x0b, 0xea, 0x4e, 0x59,
+	0x0b, 0xea, 0x50, 0x59,
 	0x0b, 0xea, 0x04, 0x00,
 	0x01, 0x44, 0xd4, 0x31,
-	0x20, 0x33, 0xf7, 0x79,
-	0x00, 0xe2, 0x98, 0x5b,
-	0x00, 0xe2, 0xf6, 0x41,
-	0x01, 0x84, 0x9d, 0x7b,
+	0x20, 0x33, 0xf9, 0x79,
+	0x00, 0xe2, 0x9e, 0x5b,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x01, 0x84, 0xa3, 0x7b,
 	0x01, 0x9c, 0x39, 0x07,
 	0x08, 0x60, 0x20, 0x33,
 	0x08, 0x80, 0x31, 0x37,
 	0xdf, 0x33, 0x67, 0x0a,
-	0xee, 0x00, 0xaa, 0x6b,
+	0xee, 0x00, 0xb0, 0x6b,
 	0x05, 0xea, 0xb4, 0x00,
-	0x33, 0xea, 0x42, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
-	0x00, 0xe2, 0x68, 0x59,
-	0x00, 0xe2, 0xb6, 0x42,
+	0x00, 0xe2, 0x6a, 0x59,
+	0x00, 0xe2, 0xbc, 0x42,
 	0x01, 0xea, 0x6c, 0x02,
 	0xc0, 0xea, 0x66, 0x06,
-	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,
+	0xff, 0x42, 0xc4, 0x6b,
+	0x01, 0x41, 0xb8, 0x6b,
+	0x02, 0x41, 0xb8, 0x7b,
+	0xff, 0x42, 0xc4, 0x6b,
+	0x01, 0x41, 0xb8, 0x6b,
+	0x02, 0x41, 0xb8, 0x7b,
+	0xff, 0x42, 0xc4, 0x7b,
+	0x04, 0x4c, 0xb8, 0x6b,
 	0xe0, 0x41, 0x6c, 0x0e,
 	0x01, 0x44, 0xd4, 0x31,
-	0xff, 0x42, 0xc6, 0x7b,
-	0x04, 0x4c, 0xc6, 0x6b,
+	0xff, 0x42, 0xcc, 0x7b,
+	0x04, 0x4c, 0xcc, 0x6b,
 	0xe0, 0x41, 0x6c, 0x0a,
-	0xe0, 0x36, 0xf7, 0x61,
+	0xe0, 0x36, 0xf9, 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, 0xde, 0x7b,
+	0x04, 0xa6, 0xe4, 0x7b,
 	0xff, 0xea, 0x5a, 0x09,
 	0xff, 0xea, 0x4c, 0x0d,
-	0x01, 0xa6, 0xfc, 0x6b,
+	0x01, 0xa6, 0x02, 0x6c,
 	0x10, 0xad, 0x64, 0x78,
-	0x80, 0xad, 0xf4, 0x6b,
+	0x80, 0xad, 0xfa, 0x6b,
 	0x08, 0xad, 0x64, 0x68,
 	0x04, 0x84, 0xf9, 0x30,
 	0x00, 0xea, 0x08, 0x81,
@@ -521,8 +524,6 @@
 	0x08, 0xb0, 0xe0, 0x30,
 	0x04, 0xb0, 0xe0, 0x30,
 	0x03, 0xb0, 0xf0, 0x30,
-	0x01, 0x78, 0x0a, 0x7c,
-	0x01, 0xa7, 0x4e, 0x11,
 	0x01, 0xb0, 0x06, 0x33,
 	0x7f, 0x83, 0xe9, 0x08,
 	0x04, 0xac, 0x58, 0x19,
@@ -532,9 +533,7 @@
 	0x00, 0x86, 0x0d, 0x23,
 	0x00, 0x87, 0x0f, 0x23,
 	0x01, 0x84, 0xc5, 0x31,
-	0x01, 0xa7, 0x20, 0x7c,
-	0x04, 0xe2, 0xc4, 0x01,
-	0x80, 0x83, 0x27, 0x7c,
+	0x80, 0x83, 0x25, 0x7c,
 	0x02, 0xe2, 0xc4, 0x01,
 	0xff, 0xea, 0x4c, 0x09,
 	0x01, 0xe2, 0x36, 0x30,
@@ -544,86 +543,80 @@
 	0x00, 0xe2, 0x64, 0x50,
 	0xfe, 0xa6, 0x4c, 0x0d,
 	0x0b, 0x90, 0xe1, 0x30,
-	0x01, 0x98, 0x4f, 0x09,
 	0xfd, 0x9c, 0x49, 0x09,
-	0x80, 0x9b, 0x3d, 0x7c,
+	0x80, 0x9b, 0x39, 0x7c,
 	0x02, 0xa4, 0x48, 0x01,
-	0x01, 0xa7, 0x40, 0x7c,
-	0x04, 0xa4, 0x48, 0x01,
 	0x01, 0xa4, 0x36, 0x30,
 	0xa8, 0xea, 0x32, 0x00,
 	0xfd, 0x9c, 0x39, 0x0b,
 	0x05, 0x9b, 0x07, 0x33,
-	0x80, 0x83, 0x4d, 0x6c,
+	0x80, 0x83, 0x45, 0x6c,
 	0x02, 0xea, 0x4c, 0x05,
 	0xff, 0xea, 0x4c, 0x0d,
-	0x00, 0xe2, 0x3c, 0x59,
-	0x02, 0xa6, 0xe0, 0x6b,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x02, 0xa6, 0xe6, 0x6b,
 	0x80, 0xf9, 0xf2, 0x05,
-	0xc0, 0x33, 0x5b, 0x7c,
-	0x03, 0xea, 0x4e, 0x59,
+	0xc0, 0x33, 0x53, 0x7c,
+	0x03, 0xea, 0x50, 0x59,
 	0x03, 0xea, 0x04, 0x00,
-	0x20, 0x33, 0x7f, 0x7c,
-	0x01, 0x84, 0x65, 0x6c,
-	0x06, 0xea, 0x4e, 0x59,
+	0x20, 0x33, 0x77, 0x7c,
+	0x01, 0x84, 0x5d, 0x6c,
+	0x06, 0xea, 0x50, 0x59,
 	0x06, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x82, 0x44,
+	0x00, 0xe2, 0x7a, 0x44,
 	0x01, 0x00, 0x60, 0x32,
-	0xee, 0x00, 0x6e, 0x6c,
+	0xee, 0x00, 0x66, 0x6c,
 	0x05, 0xea, 0xb4, 0x00,
-	0x33, 0xea, 0x42, 0x59,
+	0x33, 0xea, 0x44, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x80, 0x3d, 0x7a, 0x00,
-	0xfc, 0x42, 0x70, 0x7c,
+	0xfc, 0x42, 0x68, 0x7c,
 	0x7f, 0x3d, 0x7a, 0x08,
-	0x00, 0x30, 0x43, 0x59,
+	0x00, 0x30, 0x45, 0x59,
 	0x01, 0x30, 0x01, 0x30,
-	0x09, 0xea, 0x4e, 0x59,
+	0x09, 0xea, 0x50, 0x59,
 	0x09, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xf6, 0x41,
-	0x01, 0x9c, 0x65, 0x6c,
-	0x00, 0xe2, 0x32, 0x5c,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x01, 0x9c, 0x5d, 0x6c,
+	0x00, 0xe2, 0x30, 0x5c,
 	0x20, 0x33, 0x67, 0x02,
 	0x01, 0x00, 0x60, 0x32,
-	0x02, 0xa6, 0x8a, 0x7c,
-	0x00, 0xe2, 0x4e, 0x5c,
+	0x02, 0xa6, 0x82, 0x7c,
+	0x00, 0xe2, 0x46, 0x5c,
 	0x00, 0xe2, 0x56, 0x58,
 	0x00, 0xe2, 0x66, 0x58,
 	0x00, 0xe2, 0x3a, 0x58,
-	0x00, 0x30, 0x43, 0x59,
+	0x00, 0x30, 0x45, 0x59,
 	0x01, 0x30, 0x01, 0x30,
-	0x20, 0x19, 0x8a, 0x6c,
-	0x00, 0xe2, 0xba, 0x5c,
-	0x04, 0x19, 0xa4, 0x6c,
+	0x20, 0x19, 0x82, 0x6c,
+	0x00, 0xe2, 0xb2, 0x5c,
+	0x04, 0x19, 0x9c, 0x6c,
 	0x02, 0x19, 0x32, 0x00,
-	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,
+	0x01, 0x84, 0x9d, 0x7c,
+	0x01, 0x1b, 0x96, 0x7c,
+	0x01, 0x1a, 0x9c, 0x6c,
+	0x00, 0xe2, 0x4c, 0x44,
+	0x80, 0x4b, 0xa2, 0x6c,
+	0x01, 0x4c, 0x9e, 0x7c,
+	0x03, 0x42, 0x4c, 0x6c,
+	0x00, 0xe2, 0xe0, 0x5b,
 	0x80, 0xf9, 0xf2, 0x01,
-	0x04, 0x33, 0xf7, 0x79,
-	0x00, 0xe2, 0xf6, 0x41,
-	0x08, 0x5d, 0xc2, 0x6c,
+	0x04, 0x33, 0xf9, 0x79,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x08, 0x5d, 0xba, 0x6c,
 	0x00, 0xe2, 0x56, 0x58,
-	0x00, 0x30, 0x43, 0x59,
+	0x00, 0x30, 0x45, 0x59,
 	0x01, 0x30, 0x01, 0x30,
-	0x02, 0x1b, 0xb2, 0x7c,
-	0x08, 0x5d, 0xc0, 0x7c,
+	0x02, 0x1b, 0xaa, 0x7c,
+	0x08, 0x5d, 0xb8, 0x7c,
 	0x03, 0x68, 0x00, 0x37,
 	0x01, 0x84, 0x09, 0x07,
-	0x80, 0x1b, 0xcc, 0x7c,
-	0x80, 0x84, 0xcd, 0x6c,
+	0x80, 0x1b, 0xc4, 0x7c,
+	0x80, 0x84, 0xc5, 0x6c,
 	0xff, 0x85, 0x0b, 0x1b,
 	0xff, 0x86, 0x0d, 0x23,
 	0xff, 0x87, 0x0f, 0x23,
 	0xf8, 0x1b, 0x08, 0x0b,
-	0xff, 0xea, 0x4e, 0x09,
-	0x04, 0x1b, 0xd4, 0x7c,
-	0x01, 0xa7, 0x4e, 0x01,
 	0xff, 0xea, 0x06, 0x0b,
 	0x03, 0x68, 0x00, 0x37,
 	0x00, 0xe2, 0xc4, 0x58,
@@ -631,161 +624,161 @@
 	0xf9, 0xd9, 0xb2, 0x0d,
 	0x01, 0xd9, 0xb2, 0x05,
 	0x01, 0x52, 0x48, 0x31,
-	0x20, 0xa4, 0xfc, 0x7c,
-	0x20, 0x5b, 0xfc, 0x7c,
-	0x80, 0xf9, 0x0a, 0x7d,
+	0x20, 0xa4, 0xee, 0x7c,
+	0x20, 0x5b, 0xee, 0x7c,
+	0x80, 0xf9, 0xfc, 0x7c,
 	0x02, 0xea, 0xb4, 0x00,
 	0x11, 0x00, 0x00, 0x10,
-	0x04, 0x19, 0x16, 0x7d,
+	0x04, 0x19, 0x08, 0x7d,
 	0xdf, 0x19, 0x32, 0x08,
-	0x60, 0x5b, 0xf4, 0x6c,
-	0x01, 0x4c, 0xf0, 0x7c,
+	0x60, 0x5b, 0xe6, 0x6c,
+	0x01, 0x4c, 0xe2, 0x7c,
 	0x20, 0x19, 0x32, 0x00,
 	0x01, 0xd9, 0xb2, 0x05,
 	0x02, 0xea, 0xb4, 0x00,
 	0x01, 0xd9, 0xb2, 0x05,
-	0x10, 0x5b, 0x0e, 0x6d,
-	0x08, 0x5b, 0x18, 0x6d,
-	0x20, 0x5b, 0x08, 0x6d,
-	0x02, 0x5b, 0x38, 0x6d,
-	0x0e, 0xea, 0x4e, 0x59,
+	0x10, 0x5b, 0x00, 0x6d,
+	0x08, 0x5b, 0x0a, 0x6d,
+	0x20, 0x5b, 0xfa, 0x6c,
+	0x02, 0x5b, 0x2a, 0x6d,
+	0x0e, 0xea, 0x50, 0x59,
 	0x0e, 0xea, 0x04, 0x00,
-	0x80, 0xf9, 0xf8, 0x6c,
+	0x80, 0xf9, 0xea, 0x6c,
 	0xdf, 0x5c, 0xb8, 0x08,
 	0x01, 0xd9, 0xb2, 0x05,
-	0x01, 0x9c, 0xf3, 0x6d,
-	0x00, 0xe2, 0x32, 0x5c,
-	0x00, 0xe2, 0x42, 0x5d,
+	0x01, 0x9c, 0xe5, 0x6d,
+	0x00, 0xe2, 0x30, 0x5c,
+	0x00, 0xe2, 0x34, 0x5d,
 	0x01, 0xae, 0x5d, 0x1b,
 	0x01, 0xd9, 0xb2, 0x05,
-	0x00, 0xe2, 0x2c, 0x5b,
+	0x00, 0xe2, 0x32, 0x5b,
 	0xf3, 0xac, 0xd5, 0x19,
-	0x00, 0xe2, 0x26, 0x55,
-	0x80, 0xac, 0x27, 0x6d,
-	0x0f, 0xea, 0x4e, 0x59,
+	0x00, 0xe2, 0x18, 0x55,
+	0x80, 0xac, 0x19, 0x6d,
+	0x0f, 0xea, 0x50, 0x59,
 	0x0f, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x2e, 0x45,
+	0x00, 0xe2, 0x20, 0x45,
 	0x04, 0x8c, 0xe1, 0x30,
 	0x01, 0xea, 0xf2, 0x00,
 	0x02, 0xea, 0x36, 0x00,
 	0xa8, 0xea, 0x32, 0x00,
-	0xff, 0xad, 0x35, 0x7d,
-	0x14, 0xea, 0x4e, 0x59,
+	0xff, 0xad, 0x27, 0x7d,
+	0x14, 0xea, 0x50, 0x59,
 	0x14, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xa4, 0x5d,
+	0x00, 0xe2, 0x96, 0x5d,
 	0x01, 0xd9, 0xb2, 0x05,
 	0x09, 0x80, 0xe1, 0x30,
 	0x02, 0xea, 0x36, 0x00,
 	0xa8, 0xea, 0x32, 0x00,
-	0x00, 0xe2, 0x9c, 0x5d,
+	0x00, 0xe2, 0x8e, 0x5d,
 	0x01, 0xd9, 0xb2, 0x05,
-	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,
+	0x02, 0xa6, 0x44, 0x7d,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x20, 0x5b, 0x52, 0x6d,
+	0xfc, 0x42, 0x3e, 0x7d,
+	0x10, 0x40, 0x40, 0x6d,
+	0x20, 0x4d, 0x42, 0x7d,
+	0x08, 0x5d, 0x52, 0x6d,
+	0x02, 0xa6, 0xe6, 0x6b,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x20, 0x5b, 0x52, 0x6d,
+	0x01, 0x1b, 0x72, 0x6d,
+	0xfc, 0x42, 0x4e, 0x7d,
+	0x10, 0x40, 0x50, 0x6d,
 	0x20, 0x4d, 0x64, 0x78,
 	0x08, 0x5d, 0x64, 0x78,
 	0x02, 0x19, 0x32, 0x00,
 	0x01, 0x5b, 0x40, 0x31,
-	0x00, 0xe2, 0xba, 0x5c,
-	0x00, 0xe2, 0x98, 0x5b,
+	0x00, 0xe2, 0xb2, 0x5c,
+	0x00, 0xe2, 0x9e, 0x5b,
 	0x20, 0xea, 0xb6, 0x00,
-	0x00, 0xe2, 0xda, 0x5b,
+	0x00, 0xe2, 0xe0, 0x5b,
 	0x20, 0x5c, 0xb8, 0x00,
-	0x04, 0x19, 0x76, 0x6d,
-	0x01, 0x1a, 0x76, 0x6d,
-	0x00, 0xe2, 0x3c, 0x59,
+	0x04, 0x19, 0x68, 0x6d,
+	0x01, 0x1a, 0x68, 0x6d,
+	0x00, 0xe2, 0x3e, 0x59,
 	0x01, 0x1a, 0x64, 0x78,
 	0x80, 0xf9, 0xf2, 0x01,
-	0x20, 0xa0, 0xda, 0x7d,
+	0x20, 0xa0, 0xcc, 0x7d,
 	0xff, 0xae, 0x5d, 0x1b,
-	0x08, 0xa8, 0x3d, 0x6b,
+	0x08, 0xa8, 0x43, 0x6b,
 	0x02, 0xea, 0xb4, 0x04,
 	0x01, 0x9c, 0x39, 0x03,
-	0x40, 0x5b, 0x90, 0x6d,
-	0x00, 0xe2, 0x3c, 0x59,
-	0x40, 0x5b, 0x90, 0x6d,
-	0x04, 0x5d, 0xf4, 0x7d,
-	0x01, 0x1a, 0xf4, 0x7d,
+	0x40, 0x5b, 0x82, 0x6d,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x40, 0x5b, 0x82, 0x6d,
+	0x04, 0x5d, 0xe6, 0x7d,
+	0x01, 0x1a, 0xe6, 0x7d,
 	0x20, 0x4d, 0x64, 0x78,
-	0x40, 0x5b, 0xda, 0x7d,
-	0x04, 0x5d, 0xf4, 0x7d,
-	0x01, 0x1a, 0xf4, 0x7d,
+	0x40, 0x5b, 0xcc, 0x7d,
+	0x04, 0x5d, 0xe6, 0x7d,
+	0x01, 0x1a, 0xe6, 0x7d,
 	0x80, 0xf9, 0xf2, 0x01,
 	0xff, 0xae, 0x5d, 0x1b,
-	0x08, 0xa8, 0x3d, 0x6b,
+	0x08, 0xa8, 0x43, 0x6b,
 	0x02, 0xea, 0xb4, 0x04,
-	0x00, 0xe2, 0x3c, 0x59,
+	0x00, 0xe2, 0x3e, 0x59,
 	0x01, 0x1b, 0x64, 0x78,
 	0x80, 0xf9, 0xf2, 0x01,
 	0x02, 0xea, 0xb4, 0x04,
-	0x00, 0xe2, 0x3c, 0x59,
-	0x01, 0x1b, 0xb8, 0x6d,
-	0x40, 0x5b, 0xc6, 0x7d,
-	0x01, 0x1b, 0xb8, 0x6d,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x01, 0x1b, 0xaa, 0x6d,
+	0x40, 0x5b, 0xb8, 0x7d,
+	0x01, 0x1b, 0xaa, 0x6d,
 	0x02, 0x19, 0x32, 0x00,
 	0x01, 0x1a, 0x64, 0x78,
 	0x80, 0xf9, 0xf2, 0x01,
 	0xff, 0xea, 0x10, 0x03,
 	0x08, 0xa8, 0x51, 0x03,
-	0x00, 0xe2, 0x3c, 0x43,
-	0x01, 0x1a, 0xc2, 0x7d,
-	0x40, 0x5b, 0xbe, 0x7d,
-	0x01, 0x1a, 0xac, 0x6d,
+	0x00, 0xe2, 0x42, 0x43,
+	0x01, 0x1a, 0xb4, 0x7d,
+	0x40, 0x5b, 0xb0, 0x7d,
+	0x01, 0x1a, 0x9e, 0x6d,
 	0xfc, 0x42, 0x64, 0x78,
-	0x01, 0x1a, 0xc6, 0x6d,
-	0x10, 0xea, 0x4e, 0x59,
+	0x01, 0x1a, 0xb8, 0x6d,
+	0x10, 0xea, 0x50, 0x59,
 	0x10, 0xea, 0x04, 0x00,
 	0xfc, 0x42, 0x64, 0x78,
-	0x10, 0x40, 0xcc, 0x6d,
+	0x10, 0x40, 0xbe, 0x6d,
 	0x20, 0x4d, 0x64, 0x78,
-	0x40, 0x5b, 0xac, 0x6d,
+	0x40, 0x5b, 0x9e, 0x6d,
 	0x01, 0x1a, 0x64, 0x78,
 	0x01, 0xae, 0x5d, 0x1b,
 	0x30, 0x3f, 0xc0, 0x09,
 	0x30, 0xe0, 0x64, 0x60,
 	0x40, 0x4b, 0x64, 0x68,
 	0xff, 0xea, 0x52, 0x01,
-	0xee, 0x00, 0xe0, 0x6d,
+	0xee, 0x00, 0xd2, 0x6d,
 	0x80, 0xf9, 0xf2, 0x01,
 	0xff, 0xae, 0x5d, 0x1b,
 	0x02, 0xea, 0xb4, 0x00,
 	0x20, 0xea, 0x9a, 0x00,
-	0xf3, 0x42, 0xec, 0x6d,
-	0x12, 0xea, 0x4e, 0x59,
+	0xf3, 0x42, 0xde, 0x6d,
+	0x12, 0xea, 0x50, 0x59,
 	0x12, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xf6, 0x41,
-	0x0d, 0xea, 0x4e, 0x59,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x0d, 0xea, 0x50, 0x59,
 	0x0d, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xf6, 0x41,
+	0x00, 0xe2, 0xf8, 0x41,
 	0x01, 0xae, 0x5d, 0x1b,
-	0x11, 0xea, 0x4e, 0x59,
+	0x11, 0xea, 0x50, 0x59,
 	0x11, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x2c, 0x5b,
+	0x00, 0xe2, 0x32, 0x5b,
 	0x08, 0x5a, 0xb4, 0x00,
-	0x00, 0xe2, 0x1a, 0x5e,
+	0x00, 0xe2, 0x0c, 0x5e,
 	0xa8, 0xea, 0x32, 0x00,
-	0x00, 0xe2, 0x3c, 0x59,
-	0x80, 0x1a, 0x08, 0x7e,
-	0x00, 0xe2, 0x1a, 0x5e,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x80, 0x1a, 0xfa, 0x7d,
+	0x00, 0xe2, 0x0c, 0x5e,
 	0x80, 0x19, 0x32, 0x00,
-	0x40, 0x5b, 0x0e, 0x6e,
-	0x08, 0x5a, 0x0e, 0x7e,
+	0x40, 0x5b, 0x00, 0x6e,
+	0x08, 0x5a, 0x00, 0x7e,
 	0x20, 0x4d, 0x64, 0x78,
 	0x02, 0x84, 0x09, 0x03,
-	0x40, 0x5b, 0xda, 0x7d,
+	0x40, 0x5b, 0xcc, 0x7d,
 	0xff, 0xae, 0x5d, 0x1b,
 	0x80, 0xf9, 0xf2, 0x01,
-	0x08, 0xa8, 0x3d, 0x6b,
+	0x08, 0xa8, 0x43, 0x6b,
 	0x02, 0xea, 0xb4, 0x04,
 	0x01, 0x38, 0xe1, 0x30,
 	0x05, 0x39, 0xe3, 0x98,
@@ -801,12 +794,20 @@
 };
 
 typedef int ahd_patch_func_t (struct ahd_softc *ahd);
+static ahd_patch_func_t ahd_patch22_func;
+
+static int
+ahd_patch22_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0);
+}
+
 static ahd_patch_func_t ahd_patch21_func;
 
 static int
 ahd_patch21_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0);
+	return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0);
 }
 
 static ahd_patch_func_t ahd_patch20_func;
@@ -814,7 +815,7 @@
 static int
 ahd_patch20_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0);
+	return ((ahd->features & AHD_RTI) == 0);
 }
 
 static ahd_patch_func_t ahd_patch19_func;
@@ -822,7 +823,7 @@
 static int
 ahd_patch19_func(struct ahd_softc *ahd)
 {
-	return ((ahd->features & AHD_RTI) == 0);
+	return ((ahd->flags & AHD_INITIATORROLE) != 0);
 }
 
 static ahd_patch_func_t ahd_patch18_func;
@@ -830,7 +831,7 @@
 static int
 ahd_patch18_func(struct ahd_softc *ahd)
 {
-	return ((ahd->flags & AHD_INITIATORROLE) != 0);
+	return ((ahd->flags & AHD_TARGETROLE) != 0);
 }
 
 static ahd_patch_func_t ahd_patch17_func;
@@ -838,7 +839,7 @@
 static int
 ahd_patch17_func(struct ahd_softc *ahd)
 {
-	return ((ahd->flags & AHD_TARGETROLE) != 0);
+	return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch16_func;
@@ -846,7 +847,7 @@
 static int
 ahd_patch16_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0);
+	return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0);
 }
 
 static ahd_patch_func_t ahd_patch15_func;
@@ -854,7 +855,7 @@
 static int
 ahd_patch15_func(struct ahd_softc *ahd)
 {
-	return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0);
+	return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0);
 }
 
 static ahd_patch_func_t ahd_patch14_func;
@@ -862,7 +863,7 @@
 static int
 ahd_patch14_func(struct ahd_softc *ahd)
 {
-	return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0);
+	return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0);
 }
 
 static ahd_patch_func_t ahd_patch13_func;
@@ -870,7 +871,7 @@
 static int
 ahd_patch13_func(struct ahd_softc *ahd)
 {
-	return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0);
+	return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0);
 }
 
 static ahd_patch_func_t ahd_patch12_func;
@@ -878,7 +879,7 @@
 static int
 ahd_patch12_func(struct ahd_softc *ahd)
 {
-	return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0);
+	return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch11_func;
@@ -886,7 +887,7 @@
 static int
 ahd_patch11_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0);
+	return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch10_func;
@@ -894,7 +895,7 @@
 static int
 ahd_patch10_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0);
+	return ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0);
 }
 
 static ahd_patch_func_t ahd_patch9_func;
@@ -902,7 +903,7 @@
 static int
 ahd_patch9_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0);
+	return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch8_func;
@@ -910,7 +911,7 @@
 static int
 ahd_patch8_func(struct ahd_softc *ahd)
 {
-	return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0);
+	return ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch7_func;
@@ -918,7 +919,7 @@
 static int
 ahd_patch7_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0);
+	return ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch6_func;
@@ -926,7 +927,7 @@
 static int
 ahd_patch6_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0);
+	return ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch5_func;
@@ -934,7 +935,7 @@
 static int
 ahd_patch5_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0);
+	return ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch4_func;
@@ -942,7 +943,7 @@
 static int
 ahd_patch4_func(struct ahd_softc *ahd)
 {
-	return ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0);
+	return ((ahd->bugs & AHD_PKT_LUN_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch3_func;
@@ -1008,109 +1009,112 @@
 	{ 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_patch4_func, 107, 1, 1 },
+	{ ahd_patch2_func, 162, 6, 1 },
+	{ ahd_patch1_func, 168, 2, 1 },
+	{ ahd_patch5_func, 170, 1, 1 },
+	{ ahd_patch2_func, 179, 1, 2 },
+	{ ahd_patch0_func, 180, 1, 1 },
+	{ ahd_patch6_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_patch7_func, 193, 2, 1 },
+	{ ahd_patch5_func, 201, 16, 2 },
+	{ ahd_patch0_func, 217, 1, 1 },
+	{ ahd_patch8_func, 237, 2, 1 },
+	{ ahd_patch1_func, 241, 1, 2 },
+	{ ahd_patch0_func, 242, 1, 1 },
+	{ ahd_patch7_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, 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, 346, 1, 2 },
+	{ ahd_patch0_func, 347, 1, 1 },
+	{ ahd_patch9_func, 366, 1, 1 },
+	{ ahd_patch9_func, 369, 1, 1 },
+	{ ahd_patch9_func, 371, 1, 1 },
+	{ ahd_patch9_func, 383, 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, 396, 1, 2 },
+	{ ahd_patch0_func, 397, 1, 1 },
+	{ ahd_patch1_func, 405, 1, 2 },
+	{ ahd_patch0_func, 406, 1, 1 },
+	{ ahd_patch2_func, 419, 1, 2 },
+	{ ahd_patch0_func, 420, 1, 1 },
+	{ ahd_patch10_func, 450, 1, 1 },
+	{ ahd_patch1_func, 457, 1, 2 },
+	{ ahd_patch0_func, 458, 1, 1 },
+	{ ahd_patch2_func, 470, 1, 2 },
+	{ ahd_patch0_func, 471, 1, 1 },
+	{ ahd_patch11_func, 476, 6, 2 },
+	{ ahd_patch0_func, 482, 1, 1 },
+	{ ahd_patch12_func, 505, 1, 1 },
+	{ ahd_patch13_func, 514, 1, 1 },
+	{ ahd_patch14_func, 515, 1, 2 },
+	{ ahd_patch0_func, 516, 1, 1 },
+	{ ahd_patch15_func, 519, 1, 1 },
+	{ ahd_patch14_func, 520, 1, 1 },
+	{ ahd_patch16_func, 531, 1, 2 },
+	{ ahd_patch0_func, 532, 1, 1 },
+	{ ahd_patch1_func, 551, 1, 2 },
+	{ ahd_patch0_func, 552, 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_patch2_func, 561, 1, 2 },
+	{ ahd_patch0_func, 562, 1, 1 },
+	{ ahd_patch2_func, 566, 1, 2 },
+	{ ahd_patch0_func, 567, 1, 1 },
+	{ ahd_patch1_func, 568, 1, 2 },
+	{ ahd_patch0_func, 569, 1, 1 },
+	{ ahd_patch2_func, 580, 1, 2 },
+	{ ahd_patch0_func, 581, 1, 1 },
+	{ ahd_patch17_func, 585, 1, 1 },
+	{ ahd_patch18_func, 590, 1, 1 },
+	{ ahd_patch19_func, 591, 2, 1 },
+	{ ahd_patch18_func, 595, 1, 2 },
+	{ ahd_patch0_func, 596, 1, 1 },
+	{ ahd_patch2_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_patch2_func, 615, 1, 2 },
+	{ ahd_patch0_func, 616, 1, 1 },
+	{ ahd_patch20_func, 617, 14, 1 },
+	{ ahd_patch1_func, 635, 1, 2 },
+	{ ahd_patch0_func, 636, 1, 1 },
+	{ ahd_patch20_func, 637, 1, 1 },
+	{ ahd_patch1_func, 649, 1, 2 },
+	{ ahd_patch0_func, 650, 1, 1 },
+	{ ahd_patch1_func, 657, 1, 2 },
+	{ ahd_patch0_func, 658, 1, 1 },
+	{ ahd_patch17_func, 681, 1, 1 },
+	{ ahd_patch17_func, 719, 1, 1 },
+	{ ahd_patch1_func, 730, 1, 2 },
+	{ ahd_patch0_func, 731, 1, 1 },
+	{ ahd_patch1_func, 748, 1, 2 },
+	{ ahd_patch0_func, 749, 1, 1 },
+	{ ahd_patch1_func, 751, 1, 2 },
+	{ ahd_patch0_func, 752, 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 }
+	{ ahd_patch21_func, 758, 1, 2 },
+	{ ahd_patch0_func, 759, 2, 1 },
+	{ ahd_patch22_func, 762, 4, 2 },
+	{ ahd_patch0_func, 766, 1, 1 },
+	{ ahd_patch22_func, 774, 11, 1 }
 };
 
 static struct cs {
@@ -1121,14 +1125,14 @@
 	{ 13, 14 },
 	{ 29, 42 },
 	{ 56, 59 },
-	{ 101, 127 },
-	{ 128, 156 },
-	{ 158, 161 },
-	{ 169, 177 },
-	{ 200, 249 },
-	{ 688, 704 },
-	{ 704, 718 },
-	{ 728, 732 }
+	{ 101, 128 },
+	{ 129, 157 },
+	{ 159, 162 },
+	{ 170, 178 },
+	{ 201, 250 },
+	{ 681, 697 },
+	{ 697, 711 },
+	{ 721, 725 }
 };
 
 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	Thu Apr 24 11:10:32 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx.h	Fri May 23 10:40:46 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#75 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#77 $
  *
  * $FreeBSD$
  */
@@ -93,7 +93,7 @@
 #define	SCB_GET_CHANNEL(ahc, scb) \
 	SCSIID_CHANNEL(ahc, (scb)->hscb->scsiid)
 #define	SCB_GET_LUN(scb) \
-	((scb)->hscb->lun)
+	((scb)->hscb->lun & LID)
 #define SCB_GET_TARGET_OFFSET(ahc, scb)	\
 	(SCB_GET_TARGET(ahc, scb) + (SCB_IS_SCSIBUS_B(ahc, scb) ? 8 : 0))
 #define SCB_GET_TARGET_MASK(ahc, scb) \
@@ -1045,6 +1045,11 @@
 	 */
 	struct target_cmd	 *targetcmds;
 	uint8_t			  tqinfifonext;
+
+	/*
+	 * Cached copy of the sequencer control register.
+	 */
+	uint8_t			  seqctl;
 
 	/*
 	 * Incoming and outgoing message handling.
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg
--- a/drivers/scsi/aic7xxx/aic7xxx.reg	Fri Feb 21 15:50:42 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx.reg	Fri May 23 10:40:47 2003
@@ -39,7 +39,7 @@
  *
  * $FreeBSD$
  */
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $"
 
 /*
  * This file is processed by the aic7xxx_asm utility for use in assembling
@@ -1080,7 +1080,8 @@
 		mask	OID				0x0f
 	}
 	SCB_LUN {
-		mask	LID				0xff
+		field	SCB_XFERLEN_ODD			0x80
+		mask	LID				0x3f
 		size	1
 	}
 	SCB_TAG {
@@ -1239,7 +1240,6 @@
 	access_mode WO
 	address			0x0fc
 	mask	SG_ADDR_MASK	0xf8
-	field	ODD_SEG		0x04
 	field	LAST_SEG	0x02
 	field	LAST_SEG_DONE	0x01
 }
@@ -1248,7 +1248,6 @@
 	access_mode RO
 	address			0x0fc
 	mask	SG_ADDR_MASK	0xf8
-	field	ODD_SEG		0x04
 	field	LAST_SEG	0x02
 	field	LAST_SEG_DONE	0x01
 }
@@ -1477,14 +1476,6 @@
 		field	ENAUTOATNO	0x08
 		field	ENAUTOATNI	0x04
 		field	ENAUTOATNP	0x02
-	}
-
-	/*
-	 * Track whether the transfer byte count for
-	 * the current data phase is odd.
-	 */
-	DATA_COUNT_ODD {
-		size		1
 	}
 }
 
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq
--- a/drivers/scsi/aic7xxx/aic7xxx.seq	Fri Jan 17 12:17:42 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx.seq	Fri May 23 10:50:58 2003
@@ -40,7 +40,7 @@
  * $FreeBSD$
  */
 
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $"
 PATCH_ARG_LIST = "struct ahc_softc *ahc"
 PREFIX = "ahc_"
 
@@ -437,7 +437,7 @@
 	mov	SCBPTR, WAITING_SCBH;
 	mov	WAITING_SCBH,SCB_NEXT;
 	mov	SAVED_SCSIID, SCB_SCSIID;
-	mov	SAVED_LUN, SCB_LUN;
+	and	SAVED_LUN, LID, SCB_LUN;
 	call	set_transfer_settings;
 	if ((ahc->flags & AHC_TARGETROLE) != 0) {
 		test	SSTAT0, TARGET	jz initiator_select;
@@ -461,7 +461,7 @@
 		/*
 		 * Start out with a simple identify message.
 		 */
-		or	SCB_LUN, MSG_IDENTIFYFLAG call target_outb;
+		or	SAVED_LUN, MSG_IDENTIFYFLAG call target_outb;
 
 		/*
 		 * If we are the result of a tagged command, send
@@ -768,16 +768,12 @@
 		/* Does the hardware have space for another SG entry? */
 		test	DFSTATUS, PRELOAD_AVAIL jz return;
 		bmov 	HADDR, CCSGRAM, 7;
-		test	HCNT[0], 0x1 jz . + 2;
-		xor	DATA_COUNT_ODD, 0x1;
 		bmov	SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;
 		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
 			mov	SCB_RESIDUAL_DATACNT[3] call set_hhaddr;
 		}
 		call	sg_advance;
 		mov	SINDEX, SCB_RESIDUAL_SGPTR[0];
-		test	DATA_COUNT_ODD, 0x1 jz . + 2;
-		or	SINDEX, ODD_SEG;
 		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
 		or	SINDEX, LAST_SEG;
 		mov	SG_CACHE_PRE, SINDEX;
@@ -875,7 +871,6 @@
 		call	calc_mwi_residual;
 	}
 	and	SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID;
-	and	DATA_COUNT_ODD, 0x1, HCNT[0];
 
 	if ((ahc->features & AHC_ULTRA2) == 0) {
 		if ((ahc->features & AHC_CMD_CHAN) != 0) {
@@ -910,8 +905,6 @@
 		mov	SINDEX, SCB_RESIDUAL_SGPTR[0];
 		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
 		or	SINDEX, LAST_SEG;
-		test	DATA_COUNT_ODD, 0x1 jz . + 2;
-		or	SINDEX, ODD_SEG;
 		mov	SG_CACHE_PRE, SINDEX;
 		mov	DFCNTRL, DMAPARAMS;
 ultra2_dma_loop:
@@ -1006,10 +999,8 @@
 		adc	SCB_RESIDUAL_SGPTR[3], -1;
 sgptr_fixup_done:
 		and	SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW;
-		clr	DATA_COUNT_ODD;
-		test	SG_CACHE_SHADOW, ODD_SEG jz . + 2;
-		or	DATA_COUNT_ODD, 0x1;
-		clr	SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */
+		/* We are not the last seg */
+		and	SCB_RESIDUAL_DATACNT[3], ~SG_LAST_SEG;
 residuals_correct:
 		/*
 		 * Go ahead and shut down the DMA engine now.
@@ -1053,11 +1044,19 @@
 			 * LAST_SEG_DONE to come true on a completed transfer
 			 * and then test to see if the data FIFO is non-empty.
 			 */
-			test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 4;
+			test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL
+				jz ultra2_wait_fifoemp;
 			test	SG_CACHE_SHADOW, LAST_SEG_DONE jz .;
+			/*
+			 * FIFOEMP can lag LAST_SEG_DONE.  Wait a few
+			 * clocks before calling this an overrun.
+			 */
+			test	DFSTATUS, FIFOEMP jnz ultra2_fifoempty;
+			test	DFSTATUS, FIFOEMP jnz ultra2_fifoempty;
 			test	DFSTATUS, FIFOEMP jnz ultra2_fifoempty;
 			/* Overrun */
 			jmp	data_phase_loop;
+ultra2_wait_fifoemp:
 			test	DFSTATUS, FIFOEMP jz .;
 		}
 ultra2_fifoempty:
@@ -1246,9 +1245,6 @@
 		} else {
 			call	set_stcnt_from_hcnt;
 		}
-		/* Track odd'ness */
-		test	HCNT[0], 0x1 jz . + 2;
-		xor	DATA_COUNT_ODD, 0x1;
 
 		if ((ahc->flags & AHC_TARGETROLE) != 0) {
 			test	SSTAT0, TARGET jnz data_phase_loop;
@@ -1350,7 +1346,7 @@
 		 */
 		test	DFCNTRL, DIRECTION jz target_ITloop;
 		test	SSTAT1, REQINIT	jnz .;
-		test	DATA_COUNT_ODD, 0x1 jz target_ITloop;
+		test	SCB_LUN, SCB_XFERLEN_ODD jz target_ITloop;
 		test	SCSIRATE, WIDEXFER jz target_ITloop;
 		/*
 		 * Issue an Ignore Wide Residue Message.
@@ -1510,7 +1506,7 @@
 	cmp	SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
 	test	SCB_CONTROL,MK_MESSAGE	jnz host_message_loop;
 p_mesgout_identify:
-	or	SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN;
+	or	SINDEX, MSG_IDENTIFYFLAG|DISCENB, SAVED_LUN;
 	test	SCB_CONTROL, DISCENB jnz . + 2;
 	and	SINDEX, ~DISCENB;
 /*
@@ -1587,7 +1583,7 @@
 	mvi	ARG_1	call inb_next;
 	cmp	ARG_1, 0x01 jne mesgin_reject;
 	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2;
-	test	DATA_COUNT_ODD, 0x1	jz mesgin_done;
+	test	SCB_LUN, SCB_XFERLEN_ODD jnz mesgin_done;
 	mvi	IGN_WIDE_RES call set_seqint;
 	jmp	mesgin_done;
 }
@@ -1716,7 +1712,7 @@
 	}
 	test	SCB_CONTROL, TAG_ENB jnz await_busfree;
 	mov	ARG_1, SCB_TAG;
-	mov	SAVED_LUN, SCB_LUN;
+	and	SAVED_LUN, LID, SCB_LUN;
 	mov	SCB_SCSIID	call set_busy_target;
 	jmp	await_busfree;
 
@@ -1859,7 +1855,7 @@
 		 * at a time.  So, if the lun doesn't match, look
 		 * for a tag message.
 		 */
-		mov	A, SCB_LUN;
+		and	A, LID, SCB_LUN;
 		cmp	SAVED_LUN, A	je setup_SCB_id_lun_okay;
 		if ((ahc->flags & AHC_PAGESCBS) != 0) {
 			/*
@@ -1917,7 +1913,7 @@
 		or	SEQ_FLAGS, 0x8;
 	}
 setup_SCB_id_okay:
-	mov	A, SCB_LUN;
+	and	A, LID, SCB_LUN;
 	cmp	SAVED_LUN, A	jne not_found_cleanup_scb;
 setup_SCB_id_lun_okay:
 	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c	Wed Apr  9 12:01:02 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c	Fri May 23 10:58:24 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#128 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#131 $
  *
  * $FreeBSD$
  */
@@ -202,7 +202,7 @@
 					    struct ahc_devinfo *devinfo,
 					    cam_status status, char *message,
 					    int verbose_level);
-#if AHC_TARGET_MODE
+#ifdef AHC_TARGET_MODE
 static void		ahc_setup_target_msgin(struct ahc_softc *ahc,
 					       struct ahc_devinfo *devinfo,
 					       struct scb *scb);
@@ -291,7 +291,7 @@
 			 ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA);
 	}
 	ahc_outb(ahc, MWI_RESIDUAL, 0);
-	ahc_outb(ahc, SEQCTL, FASTMODE);
+	ahc_outb(ahc, SEQCTL, ahc->seqctl);
 	ahc_outb(ahc, SEQADDR0, 0);
 	ahc_outb(ahc, SEQADDR1, 0);
 	ahc_unpause(ahc);
@@ -705,7 +705,7 @@
 					ahc->msgin_index = 0;
 				}
 			}
-#if AHC_TARGET_MODE
+#ifdef AHC_TARGET_MODE
 			else {
 				if (bus_phase == P_MESGOUT) {
 					ahc->msg_type =
@@ -1467,7 +1467,7 @@
 			else
 				ahc_outb(ahc, SIMODE1, 0);
 			ahc_outb(ahc, CLRINT, CLRSCSIINT);
-			ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) | STEP);
+			ahc_outb(ahc, SEQCTL, ahc->seqctl | STEP);
 			stepping = TRUE;
 		}
 		if ((ahc->features & AHC_DT) != 0) {
@@ -1481,7 +1481,7 @@
 	if (stepping) {
 		ahc_outb(ahc, SIMODE0, simode0);
 		ahc_outb(ahc, SIMODE1, simode1);
-		ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) & ~STEP);
+		ahc_outb(ahc, SEQCTL, ahc->seqctl);
 	}
 }
 
@@ -3573,7 +3573,7 @@
 
 		sgptr = ahc_inb(ahc, SCB_RESIDUAL_SGPTR);
 		if ((sgptr & SG_LIST_NULL) != 0
-		 && ahc_inb(ahc, DATA_COUNT_ODD) == 1) {
+		 && (ahc_inb(ahc, SCB_LUN) & SCB_XFERLEN_ODD) != 0) {
 			/*
 			 * If the residual occurred on the last
 			 * transfer and the transfer request was
@@ -3586,25 +3586,27 @@
 			uint32_t data_addr;
 			uint32_t sglen;
 
-			/* Pull in the rest of the sgptr */
-			sgptr |= (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24)
-			      | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16)
-			      | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8);
-			sgptr &= SG_PTR_MASK;
-			data_cnt = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+3) << 24)
-				 | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+2) << 16)
-				 | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+1) << 8)
-				 | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT));
-
-			data_addr = (ahc_inb(ahc, SHADDR + 3) << 24)
-				  | (ahc_inb(ahc, SHADDR + 2) << 16)
-				  | (ahc_inb(ahc, SHADDR + 1) << 8)
-				  | (ahc_inb(ahc, SHADDR));
+			/* Pull in all of the sgptr */
+			sgptr = ahc_inl(ahc, SCB_RESIDUAL_SGPTR);
+			data_cnt = ahc_inl(ahc, SCB_RESIDUAL_DATACNT);
+
+			if ((sgptr & SG_LIST_NULL) != 0) {
+				/*
+				 * The residual data count is not updated
+				 * for the command run to completion case.
+				 * Explicitly zero the count.
+				 */
+				data_cnt &= ~AHC_SG_LEN_MASK;
+			}
+
+			data_addr = ahc_inl(ahc, SHADDR);
 
 			data_cnt += 1;
 			data_addr -= 1;
+			sgptr &= SG_PTR_MASK;
 
 			sg = ahc_sg_bus_to_virt(scb, sgptr);
+
 			/*
 			 * The residual sg ptr points to the next S/G
 			 * to load so we must go back one.
@@ -3630,19 +3632,17 @@
 				 */
 				sg++;
 				sgptr = ahc_sg_virt_to_bus(scb, sg);
-				ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 3,
-					 sgptr >> 24);
-				ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 2,
-					 sgptr >> 16);
-				ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 1,
-					 sgptr >> 8);
-				ahc_outb(ahc, SCB_RESIDUAL_SGPTR, sgptr);
 			}
-
-			ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 3, data_cnt >> 24);
-			ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 2, data_cnt >> 16);
-			ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 1, data_cnt >> 8);
-			ahc_outb(ahc, SCB_RESIDUAL_DATACNT, data_cnt);
+			ahc_outl(ahc, SCB_RESIDUAL_SGPTR, sgptr);
+			ahc_outl(ahc, SCB_RESIDUAL_DATACNT, data_cnt);
+			/*
+			 * Toggle the "oddness" of the transfer length
+			 * to handle this mid-transfer ignore wide
+			 * residue.  This ensures that the oddness is
+			 * correct for subsequent data transfers.
+			 */
+			ahc_outb(ahc, SCB_LUN,
+				 ahc_inb(ahc, SCB_LUN) ^ SCB_XFERLEN_ODD);
 		}
 	}
 }
@@ -3826,6 +3826,12 @@
 	ahc->features = AHC_FENONE;
 	ahc->bugs = AHC_BUGNONE;
 	ahc->flags = AHC_FNONE;
+	/*
+	 * Default to all error reporting enabled with the
+	 * sequencer operating at its fastest speed.
+	 * The bus attach code may modify this.
+	 */
+	ahc->seqctl = FASTMODE;
 
 	for (i = 0; i < AHC_NUM_TARGETS; i++)
 		TAILQ_INIT(&ahc->untagged_queues[i]);
@@ -3986,7 +3992,7 @@
 
 		tstate = ahc->enabled_targets[i];
 		if (tstate != NULL) {
-#if AHC_TARGET_MODE
+#ifdef AHC_TARGET_MODE
 			int j;
 
 			for (j = 0; j < AHC_NUM_LUNS; j++) {
@@ -4002,7 +4008,7 @@
 			free(tstate, M_DEVBUF);
 		}
 	}
-#if AHC_TARGET_MODE
+#ifdef AHC_TARGET_MODE
 	if (ahc->black_hole != NULL) {
 		xpt_free_path(ahc->black_hole->path);
 		free(ahc->black_hole, M_DEVBUF);
@@ -5120,7 +5126,7 @@
 		return (EBUSY);
 	}
 
-#if AHC_TARGET_MODE
+#ifdef AHC_TARGET_MODE
 	/*
 	 * XXX What about ATIOs that have not yet been serviced?
 	 * Perhaps we should just refuse to be suspended if we
@@ -5221,7 +5227,7 @@
 	if (match != 0)
 		match = ((lun == slun) || (lun == CAM_LUN_WILDCARD));
 	if (match != 0) {
-#if AHC_TARGET_MODE
+#ifdef AHC_TARGET_MODE
 		int group;
 
 		group = XPT_FC_GROUP(scb->io_ctx->ccb_h.func_code);
@@ -5964,7 +5970,7 @@
 	 * before the reset occurred.
 	 */
 	ahc_run_qoutfifo(ahc);
-#if AHC_TARGET_MODE
+#ifdef AHC_TARGET_MODE
 	/*
 	 * XXX - In Twin mode, the tqinfifo may have commands
 	 *	 for an unaffected channel in it.  However, if
@@ -5996,7 +6002,7 @@
 		 */
 		ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB);
 		simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST);
-#if AHC_TARGET_MODE
+#ifdef AHC_TARGET_MODE
 		/*
 		 * Bus resets clear ENSELI, so we cannot
 		 * defer re-enabling bus reset interrupts
@@ -6015,7 +6021,7 @@
 	} else {
 		/* Case 2: A command from this bus is active or we're idle */
 		simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST);
-#if AHC_TARGET_MODE
+#ifdef AHC_TARGET_MODE
 		/*
 		 * Bus resets clear ENSELI, so we cannot
 		 * defer re-enabling bus reset interrupts
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_inline.h b/drivers/scsi/aic7xxx/aic7xxx_inline.h
--- a/drivers/scsi/aic7xxx/aic7xxx_inline.h	Thu May  1 10:06:05 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx_inline.h	Fri May 23 10:40:47 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#42 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#43 $
  *
  * $FreeBSD$
  */
@@ -453,6 +453,13 @@
 	 || scb->hscb->next == SCB_LIST_NULL)
 		panic("Attempt to queue invalid SCB tag %x:%x\n",
 		      scb->hscb->tag, scb->hscb->next);
+
+	/*
+	 * Setup data "oddness".
+	 */
+	scb->hscb->lun &= LID;
+	if (ahc_get_transfer_length(scb) & 0x1)
+		scb->hscb->lun |= SCB_XFERLEN_ODD;
 
 	/*
 	 * Keep a history of SCBs we've downloaded in the qinfifo.
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c	Thu May 22 09:44:33 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c	Fri May 23 12:29:22 2003
@@ -1,7 +1,7 @@
 /*
  * Adaptec AIC7xxx device driver for Linux.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#221 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#232 $
  *
  * Copyright (c) 1994 John Aycock
  *   The University of Calgary Department of Computer Science.
@@ -141,11 +141,6 @@
 #include <linux/mm.h>		/* For fetching system memory size */
 #include <linux/blk.h>		/* For block_size() */
 
-#define __KERNEL_SYSCALLS__
- 
-#include <linux/unistd.h>
-static int errno;
-
 /*
  * Lock protecting manipulation of the ahc softc list.
  */
@@ -746,31 +741,11 @@
 	consumed = 1;
 	sg->addr = ahc_htole32(addr & 0xFFFFFFFF);
 	scb->platform_data->xfer_len += len;
+
 	if (sizeof(bus_addr_t) > 4
-	 && (ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
-		/*
-		 * Due to DAC restrictions, we can't
-		 * cross a 4GB boundary.
-		 */
-		if ((addr ^ (addr + len - 1)) & ~0xFFFFFFFF) {
-			struct	 ahc_dma_seg *next_sg;
-			uint32_t next_len;
-
-			printf("Crossed Seg\n");
-			if ((scb->sg_count + 2) > AHC_NSEG)
-				panic("Too few segs for dma mapping.  "
-				      "Increase AHC_NSEG\n");
-
-			consumed++;
-			next_sg = sg + 1;
-			next_sg->addr = 0;
-			next_len = 0x100000000 - (addr & 0xFFFFFFFF);
-			len -= next_len;
-			next_len |= ((addr >> 8) + 0x1000000) & 0x7F000000;
-			next_sg->len = ahc_htole32(next_len);
-		}
-		len |= (addr >> 8) & 0x7F000000;
-	}
+	 && (ahc->flags & AHC_39BIT_ADDRESSING) != 0)
+		len |= (addr >> 8) & AHC_SG_HIGH_ADDR_MASK;
+
 	sg->len = ahc_htole32(len);
 	return (consumed);
 }
@@ -1195,10 +1170,10 @@
 }
 #endif
 
+#if defined(__i386__)
 /*
  * 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,
@@ -1747,7 +1722,7 @@
 	struct	 Scsi_Host *host;
 	char	*new_name;
 	u_long	 s;
-	u_int	 target;
+	u_int	 targ_offset;
 
 	template->name = ahc->description;
 	host = scsi_register(template, sizeof(struct ahc_softc *));
@@ -1802,14 +1777,19 @@
 	 * negotiation will occur for the first command, and DV
 	 * will comence should that first command be successful.
 	 */
-	for (target = 0;
-	     target < host->max_id * (host->max_channel + 1); target++) {
+	for (targ_offset = 0;
+	     targ_offset < host->max_id * (host->max_channel + 1);
+	     targ_offset++) {
 		u_int channel;
+		u_int target;
 
 		channel = 0;
+		target = targ_offset;
 		if (target > 7
-		 && (ahc->features & AHC_TWIN) != 0)
+		 && (ahc->features & AHC_TWIN) != 0) {
 			channel = 1;
+			target &= 0x7;
+		}
 		/*
 		 * Skip our own ID.  Some Compaq/HP storage devices
 		 * have enclosure management devices that respond to
@@ -2443,8 +2423,10 @@
 		ahc_unlock(ahc, &s);
 		return;
 	}
-	ahc_compile_devinfo(&devinfo, ahc->our_id, targ->target, /*lun*/0,
-			    targ->channel + 'A', ROLE_INITIATOR);
+	ahc_compile_devinfo(&devinfo,
+			    targ->channel == 0 ? ahc->our_id : ahc->our_id_b,
+			    targ->target, /*lun*/0, targ->channel + 'A',
+			    ROLE_INITIATOR);
 #ifdef AHC_DEBUG
 	if (ahc_debug & AHC_SHOW_DV) {
 		ahc_print_devinfo(ahc, &devinfo);
@@ -2616,14 +2598,11 @@
 			struct ahc_devinfo *devinfo,
 			struct ahc_linux_target *targ)
 {
-	cam_status cam_status;
 	u_int32_t status;
-	u_int scsi_status;
-
-	scsi_status = ahc_cmd_get_scsi_status(cmd);
-	cam_status = ahc_cmd_get_transaction_status(cmd);
-	status = aic_error_action(cmd, targ->inq_data, cam_status, scsi_status);
 
+	status = aic_error_action(cmd, targ->inq_data,
+				  ahc_cmd_get_transaction_status(cmd),
+				  ahc_cmd_get_scsi_status(cmd));
 	
 #ifdef AHC_DEBUG
 	if (ahc_debug & AHC_SHOW_DV) {
@@ -3777,7 +3756,7 @@
 
 			cur_seg = (struct scatterlist *)cmd->request_buffer;
 			nseg = pci_map_sg(ahc->dev_softc, cur_seg, cmd->use_sg,
-				 scsi_to_pci_dma_dir(cmd ->sc_data_direction));
+			    scsi_to_pci_dma_dir(cmd->sc_data_direction));
 			end_seg = cur_seg + nseg;
 			/* Copy the segments into the SG list. */
 			sg = scb->sg_list;
@@ -3881,7 +3860,7 @@
 /*
  * SCSI controller interrupt handler.
  */
-AIC_LINUX_IRQRETURN_T
+irqreturn_t
 ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct	ahc_softc *ahc;
@@ -3895,7 +3874,7 @@
 		ahc_schedule_runq(ahc);
 	ahc_linux_run_complete_queue(ahc);
 	ahc_unlock(ahc, &flags);
-	AIC_LINUX_IRQRETURN(ours);
+	return IRQ_RETVAL(ours);
 }
 
 void
@@ -4910,7 +4889,7 @@
 			disconnected = FALSE;
 		else if (flag != SCB_ABORT
 		      && ahc_inb(ahc, SAVED_SCSIID) == pending_scb->hscb->scsiid
-		      && ahc_inb(ahc, SAVED_LUN) == pending_scb->hscb->lun)
+		      && ahc_inb(ahc, SAVED_LUN) == SCB_GET_LUN(pending_scb))
 			disconnected = FALSE;
 	}
 
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h	Mon May 12 20:52:59 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h	Mon May 26 19:01:56 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#142 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#147 $
  *
  */
 #ifndef _AIC7XXX_LINUX_H_
@@ -305,7 +305,7 @@
 #define AHC_SCSI_HAS_HOST_LOCK 0
 #endif
 
-#define AIC7XXX_DRIVER_VERSION "6.2.33"
+#define AIC7XXX_DRIVER_VERSION "6.2.35"
 
 /**************************** Front End Queues ********************************/
 /*
@@ -963,7 +963,7 @@
 	(((dev_softc)->dma_mask = mask) && 0)
 #endif
 /**************************** Proc FS Support *********************************/
-int	ahc_linux_proc_info(char *, char **, off_t, int, int, int);
+int	ahc_linux_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
 
 /*************************** Domain Validation ********************************/
 #define AHC_DV_CMD(cmd) ((cmd)->scsi_done == ahc_linux_dv_complete)
@@ -1165,7 +1165,7 @@
 int	ahc_platform_abort_scbs(struct ahc_softc *ahc, int target,
 				char channel, int lun, u_int tag,
 				role_t role, uint32_t status);
-AIC_LINUX_IRQRETURN_T
+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 *);
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c	Mon Mar 10 16:57:17 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c	Wed May 14 15:00:40 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/aic7xxx_osm_pci.c#44 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#45 $
  */
 
 #include "aic7xxx_osm.h"
@@ -110,6 +110,7 @@
 ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	char		 buf[80];
+	bus_addr_t	 mask_39bit;
 	struct		 ahc_softc *ahc;
 	ahc_dev_softc_t	 pci;
 	struct		 ahc_pci_identity *entry;
@@ -160,12 +161,12 @@
 	}
 	pci_set_master(pdev);
 
+	mask_39bit = (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0);
 	if (sizeof(bus_addr_t) > 4
 	 && ahc_linux_get_memsize() > 0x80000000
-	 && ahc_pci_set_dma_mask(pdev, 0x7FFFFFFFFFULL) == 0) {
+	 && ahc_pci_set_dma_mask(pdev, mask_39bit) == 0) {
 		ahc->flags |= AHC_39BIT_ADDRESSING;
-		ahc->platform_data->hw_dma_mask =
-		    (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0);
+		ahc->platform_data->hw_dma_mask = mask_39bit;
 	} else {
 		ahc_pci_set_dma_mask(pdev, 0xFFFFFFFF);
 		ahc->platform_data->hw_dma_mask = 0xFFFFFFFF;
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c	Mon May 12 20:53:00 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c	Fri May 23 10:31:47 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#63 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#66 $
  *
  * $FreeBSD$
  */
@@ -834,10 +834,10 @@
 	ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4);
 
 	/* Ensure busmastering is enabled */
-	command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1);
+	command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2);
 	command |= PCIM_CMD_BUSMASTEREN;
 
-	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/1);
+	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/2);
 
 	/* On all PCI adapters, we allow SCB paging */
 	ahc->flags |= AHC_PAGESCBS;
@@ -854,10 +854,8 @@
 	 * 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;
-	}
+	if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0)
+		ahc->seqctl |= FAILDIS;
 
 	ahc->bus_intr = ahc_pci_intr;
 	ahc->bus_chip_init = ahc_pci_chip_init;
@@ -2044,8 +2042,8 @@
 "%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->seqctl |= FAILDIS;
+		ahc_outb(ahc, SEQCTL, ahc->seqctl);
 	}
 	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 Apr 24 14:10:07 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c	Mon May 12 08:30:15 2003
@@ -289,8 +289,8 @@
  * Return information to handle /proc support for the driver.
  */
 int
-ahc_linux_proc_info(char *buffer, char **start, off_t offset,
-		  int length, int hostno, int inout)
+ahc_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset,
+		  int length, int inout)
 {
 	struct	ahc_softc *ahc;
 	struct	info_str info;
@@ -303,7 +303,7 @@
 	retval = -EINVAL;
 	ahc_list_lock(&s);
 	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
-		if (ahc->platform_data->host->host_no == hostno)
+		if (ahc->platform_data->host == shost)
 			break;
 	}
 
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped
--- a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped	Fri Feb 21 15:50:42 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped	Fri May 23 10:50:58 2003
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $
  */
 typedef int (ahc_reg_print_t)(u_int, u_int *, u_int);
 typedef struct ahc_reg_parse_entry {
@@ -433,13 +433,6 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahc_reg_print_t ahc_data_count_odd_print;
-#else
-#define ahc_data_count_odd_print(regvalue, cur_col, wrap) \
-    ahc_print_register(NULL, 0, "DATA_COUNT_ODD", 0x55, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahc_reg_print_t ahc_ha_274_biosglobal_print;
 #else
 #define ahc_ha_274_biosglobal_print(regvalue, cur_col, wrap) \
@@ -1396,8 +1389,6 @@
 #define		ENAUTOATNI      	0x04
 #define		ENAUTOATNP      	0x02
 
-#define	DATA_COUNT_ODD  		0x55
-
 #define	HA_274_BIOSGLOBAL		0x56
 #define	INITIATOR_TAG   		0x56
 #define		HA_274_EXTENDED_TRANS	0x01
@@ -1655,7 +1646,8 @@
 #define		TWIN_CHNLB      	0x80
 
 #define	SCB_LUN         		0xba
-#define		LID             	0xff
+#define		LID             	0x3f
+#define		SCB_XFERLEN_ODD 	0x80
 
 #define	SCB_TAG         		0xbb
 
@@ -1749,7 +1741,6 @@
 
 #define	SG_CACHE_SHADOW 		0xfc
 #define		SG_ADDR_MASK    	0xf8
-#define		ODD_SEG         	0x04
 #define		LAST_SEG        	0x02
 #define		LAST_SEG_DONE   	0x01
 
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped
--- a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped	Fri Feb 21 15:50:42 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped	Fri May 23 10:50:58 2003
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $
  */
 static uint8_t seqprog[] = {
 	0xb2, 0x00, 0x00, 0x08,
@@ -21,15 +21,15 @@
 	0x01, 0x4d, 0xc8, 0x30,
 	0x00, 0x4c, 0x12, 0x70,
 	0x01, 0x39, 0xa2, 0x30,
-	0x00, 0x6a, 0xd4, 0x5e,
+	0x00, 0x6a, 0xc0, 0x5e,
 	0x01, 0x51, 0x20, 0x31,
 	0x01, 0x57, 0xae, 0x00,
 	0x0d, 0x6a, 0x76, 0x00,
-	0x00, 0x51, 0x26, 0x5e,
+	0x00, 0x51, 0x12, 0x5e,
 	0x01, 0x51, 0xc8, 0x30,
 	0x00, 0x39, 0xc8, 0x60,
 	0x00, 0xbb, 0x30, 0x70,
-	0xc1, 0x6a, 0xec, 0x5e,
+	0xc1, 0x6a, 0xd8, 0x5e,
 	0x01, 0xbf, 0x72, 0x30,
 	0x01, 0x40, 0x7e, 0x31,
 	0x01, 0x90, 0x80, 0x30,
@@ -49,10 +49,10 @@
 	0x08, 0x6a, 0x78, 0x00,
 	0x01, 0x50, 0xc8, 0x30,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x48, 0x6a, 0x10, 0x5e,
+	0x48, 0x6a, 0xfc, 0x5d,
 	0x01, 0x6a, 0xdc, 0x01,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x48, 0x6a, 0x10, 0x5e,
+	0x48, 0x6a, 0xfc, 0x5d,
 	0x01, 0x6a, 0x26, 0x01,
 	0xf0, 0x19, 0x7a, 0x08,
 	0x0f, 0x18, 0xc8, 0x08,
@@ -93,7 +93,7 @@
 	0x00, 0x65, 0x20, 0x41,
 	0x02, 0x57, 0xae, 0x00,
 	0x00, 0x65, 0x9e, 0x40,
-	0x61, 0x6a, 0xec, 0x5e,
+	0x61, 0x6a, 0xd8, 0x5e,
 	0x08, 0x51, 0x20, 0x71,
 	0x02, 0x0b, 0xb2, 0x78,
 	0x00, 0x65, 0xae, 0x40,
@@ -106,7 +106,7 @@
 	0x80, 0x3d, 0x7a, 0x00,
 	0x20, 0x6a, 0x16, 0x00,
 	0x00, 0x65, 0xcc, 0x41,
-	0x00, 0x65, 0xc6, 0x5e,
+	0x00, 0x65, 0xb2, 0x5e,
 	0x00, 0x65, 0x12, 0x40,
 	0x20, 0x11, 0xd2, 0x68,
 	0x20, 0x6a, 0x18, 0x00,
@@ -135,20 +135,20 @@
 	0x01, 0x40, 0x20, 0x31,
 	0x01, 0xbf, 0x80, 0x30,
 	0x01, 0xb9, 0x7a, 0x30,
-	0x01, 0xba, 0x7c, 0x30,
+	0x3f, 0xba, 0x7c, 0x08,
 	0x00, 0x65, 0xea, 0x58,
 	0x80, 0x0b, 0xc4, 0x79,
 	0x12, 0x01, 0x02, 0x00,
 	0x01, 0xab, 0xac, 0x30,
-	0xe4, 0x6a, 0x82, 0x5d,
+	0xe4, 0x6a, 0x6e, 0x5d,
 	0x40, 0x6a, 0x16, 0x00,
-	0x80, 0xba, 0x98, 0x5d,
+	0x80, 0x3e, 0x84, 0x5d,
 	0x20, 0xb8, 0x18, 0x79,
-	0x20, 0x6a, 0x98, 0x5d,
-	0x00, 0xab, 0x98, 0x5d,
+	0x20, 0x6a, 0x84, 0x5d,
+	0x00, 0xab, 0x84, 0x5d,
 	0x01, 0xa9, 0x78, 0x30,
 	0x10, 0xb8, 0x20, 0x79,
-	0xe4, 0x6a, 0x82, 0x5d,
+	0xe4, 0x6a, 0x6e, 0x5d,
 	0x00, 0x65, 0xae, 0x40,
 	0x10, 0x03, 0x3c, 0x69,
 	0x08, 0x3c, 0x5a, 0x69,
@@ -157,10 +157,10 @@
 	0x01, 0x3c, 0x44, 0x79,
 	0xff, 0x6a, 0x70, 0x00,
 	0x00, 0x65, 0xa4, 0x59,
-	0x00, 0x6a, 0xd4, 0x5e,
+	0x00, 0x6a, 0xc0, 0x5e,
 	0xff, 0x38, 0x30, 0x71,
 	0x0d, 0x6a, 0x76, 0x00,
-	0x00, 0x38, 0x26, 0x5e,
+	0x00, 0x38, 0x12, 0x5e,
 	0x00, 0x65, 0xea, 0x58,
 	0x12, 0x01, 0x02, 0x00,
 	0x00, 0x65, 0x18, 0x41,
@@ -168,10 +168,10 @@
 	0x00, 0x65, 0xf2, 0x58,
 	0xfd, 0x57, 0xae, 0x08,
 	0x00, 0x65, 0xae, 0x40,
-	0xe4, 0x6a, 0x82, 0x5d,
+	0xe4, 0x6a, 0x6e, 0x5d,
 	0x20, 0x3c, 0x4a, 0x79,
-	0x02, 0x6a, 0x98, 0x5d,
-	0x04, 0x6a, 0x98, 0x5d,
+	0x02, 0x6a, 0x84, 0x5d,
+	0x04, 0x6a, 0x84, 0x5d,
 	0x01, 0x03, 0x4c, 0x69,
 	0xf7, 0x11, 0x22, 0x08,
 	0xff, 0x6a, 0x24, 0x08,
@@ -182,13 +182,13 @@
 	0x80, 0x86, 0xc8, 0x08,
 	0x01, 0x4f, 0xc8, 0x30,
 	0x00, 0x50, 0x6c, 0x61,
-	0xc4, 0x6a, 0x82, 0x5d,
+	0xc4, 0x6a, 0x6e, 0x5d,
 	0x40, 0x3c, 0x68, 0x79,
-	0x28, 0x6a, 0x98, 0x5d,
+	0x28, 0x6a, 0x84, 0x5d,
 	0x00, 0x65, 0x4c, 0x41,
-	0x08, 0x6a, 0x98, 0x5d,
+	0x08, 0x6a, 0x84, 0x5d,
 	0x00, 0x65, 0x4c, 0x41,
-	0x84, 0x6a, 0x82, 0x5d,
+	0x84, 0x6a, 0x6e, 0x5d,
 	0x00, 0x65, 0xf2, 0x58,
 	0x01, 0x66, 0xc8, 0x30,
 	0x01, 0x64, 0xd8, 0x31,
@@ -208,16 +208,16 @@
 	0xf7, 0x3c, 0x78, 0x08,
 	0x00, 0x65, 0x20, 0x41,
 	0x40, 0xaa, 0x7e, 0x10,
-	0x04, 0xaa, 0x82, 0x5d,
-	0x00, 0x65, 0x5e, 0x42,
-	0xc4, 0x6a, 0x82, 0x5d,
+	0x04, 0xaa, 0x6e, 0x5d,
+	0x00, 0x65, 0x56, 0x42,
+	0xc4, 0x6a, 0x6e, 0x5d,
 	0xc0, 0x6a, 0x7e, 0x00,
-	0x00, 0xa8, 0x98, 0x5d,
+	0x00, 0xa8, 0x84, 0x5d,
 	0xe4, 0x6a, 0x06, 0x00,
-	0x00, 0x6a, 0x98, 0x5d,
+	0x00, 0x6a, 0x84, 0x5d,
 	0x00, 0x65, 0x4c, 0x41,
 	0x10, 0x3c, 0xa8, 0x69,
-	0x00, 0xbb, 0x9e, 0x44,
+	0x00, 0xbb, 0x8a, 0x44,
 	0x18, 0x6a, 0xda, 0x01,
 	0x01, 0x69, 0xd8, 0x31,
 	0x1c, 0x6a, 0xd0, 0x01,
@@ -227,23 +227,23 @@
 	0x01, 0x93, 0x26, 0x01,
 	0x03, 0x6a, 0x2a, 0x01,
 	0x01, 0x69, 0x32, 0x31,
-	0x1c, 0x6a, 0xf4, 0x5d,
+	0x1c, 0x6a, 0xe0, 0x5d,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0xbc, 0x5e,
+	0x00, 0x65, 0xa8, 0x5e,
 	0x01, 0x50, 0xa0, 0x18,
 	0x02, 0x6a, 0x22, 0x05,
 	0x1a, 0x01, 0x02, 0x00,
 	0x80, 0x6a, 0x74, 0x00,
 	0x40, 0x6a, 0x78, 0x00,
 	0x40, 0x6a, 0x16, 0x00,
-	0x00, 0x65, 0xec, 0x5d,
+	0x00, 0x65, 0xd8, 0x5d,
 	0x01, 0x3f, 0xc8, 0x30,
-	0xbf, 0x64, 0x5e, 0x7a,
-	0x80, 0x64, 0xb2, 0x73,
-	0xa0, 0x64, 0x14, 0x74,
-	0xc0, 0x64, 0x08, 0x74,
-	0xe0, 0x64, 0x44, 0x74,
-	0x01, 0x6a, 0xec, 0x5e,
+	0xbf, 0x64, 0x56, 0x7a,
+	0x80, 0x64, 0x9e, 0x73,
+	0xa0, 0x64, 0x00, 0x74,
+	0xc0, 0x64, 0xf4, 0x73,
+	0xe0, 0x64, 0x30, 0x74,
+	0x01, 0x6a, 0xd8, 0x5e,
 	0x00, 0x65, 0xcc, 0x41,
 	0xf7, 0x11, 0x22, 0x08,
 	0x01, 0x06, 0xd4, 0x30,
@@ -251,7 +251,7 @@
 	0xf7, 0x01, 0x02, 0x08,
 	0x09, 0x0c, 0xe6, 0x79,
 	0x08, 0x0c, 0x04, 0x68,
-	0xb1, 0x6a, 0xec, 0x5e,
+	0xb1, 0x6a, 0xd8, 0x5e,
 	0xff, 0x6a, 0x26, 0x09,
 	0x12, 0x01, 0x02, 0x00,
 	0x02, 0x6a, 0x08, 0x30,
@@ -264,33 +264,29 @@
 	0x00, 0xa5, 0x4a, 0x21,
 	0x00, 0xa6, 0x4c, 0x21,
 	0x00, 0xa7, 0x4e, 0x25,
-	0x08, 0xeb, 0xf0, 0x7e,
+	0x08, 0xeb, 0xdc, 0x7e,
 	0x80, 0xeb, 0x06, 0x7a,
 	0xff, 0x6a, 0xd6, 0x09,
 	0x08, 0xeb, 0x0a, 0x6a,
 	0xff, 0x6a, 0xd4, 0x0c,
-	0x80, 0xa3, 0xf0, 0x6e,
+	0x80, 0xa3, 0xdc, 0x6e,
 	0x88, 0xeb, 0x20, 0x72,
-	0x08, 0xeb, 0xf0, 0x6e,
+	0x08, 0xeb, 0xdc, 0x6e,
 	0x04, 0xea, 0x24, 0xe2,
-	0x08, 0xee, 0xf0, 0x6e,
+	0x08, 0xee, 0xdc, 0x6e,
 	0x04, 0x6a, 0xd0, 0x81,
 	0x05, 0xa4, 0xc0, 0x89,
 	0x03, 0xa5, 0xc2, 0x31,
 	0x09, 0x6a, 0xd6, 0x05,
 	0x00, 0x65, 0x08, 0x5a,
 	0x06, 0xa4, 0xd4, 0x89,
-	0x80, 0x94, 0xf0, 0x7e,
+	0x80, 0x94, 0xdc, 0x7e,
 	0x07, 0xe9, 0x10, 0x31,
-	0x01, 0x8c, 0x2c, 0x7a,
-	0x01, 0x55, 0xaa, 0x10,
 	0x01, 0xe9, 0x46, 0x31,
-	0x00, 0xa3, 0xce, 0x5e,
+	0x00, 0xa3, 0xba, 0x5e,
 	0x00, 0x65, 0xfa, 0x59,
 	0x01, 0xa4, 0xca, 0x30,
-	0x01, 0x55, 0x38, 0x7a,
-	0x04, 0x65, 0xca, 0x00,
-	0x80, 0xa3, 0x3c, 0x7a,
+	0x80, 0xa3, 0x34, 0x7a,
 	0x02, 0x65, 0xca, 0x00,
 	0x01, 0x65, 0xf8, 0x31,
 	0x80, 0x93, 0x26, 0x01,
@@ -298,168 +294,162 @@
 	0x01, 0x8c, 0xc8, 0x30,
 	0x00, 0x88, 0xc8, 0x18,
 	0x02, 0x64, 0xc8, 0x88,
-	0xff, 0x64, 0xf0, 0x7e,
-	0xff, 0x8d, 0x52, 0x6a,
-	0xff, 0x8e, 0x52, 0x6a,
+	0xff, 0x64, 0xdc, 0x7e,
+	0xff, 0x8d, 0x4a, 0x6a,
+	0xff, 0x8e, 0x4a, 0x6a,
 	0x03, 0x8c, 0xd4, 0x98,
-	0x00, 0x65, 0xf0, 0x56,
+	0x00, 0x65, 0xdc, 0x56,
 	0x01, 0x64, 0x70, 0x30,
 	0xff, 0x64, 0xc8, 0x10,
 	0x01, 0x64, 0xc8, 0x18,
 	0x00, 0x8c, 0x18, 0x19,
 	0xff, 0x8d, 0x1a, 0x21,
 	0xff, 0x8e, 0x1c, 0x25,
-	0xc0, 0x3c, 0x62, 0x7a,
-	0x21, 0x6a, 0xec, 0x5e,
+	0xc0, 0x3c, 0x5a, 0x7a,
+	0x21, 0x6a, 0xd8, 0x5e,
 	0xa8, 0x6a, 0x76, 0x00,
 	0x79, 0x6a, 0x76, 0x00,
-	0x40, 0x3f, 0x6a, 0x6a,
+	0x40, 0x3f, 0x62, 0x6a,
 	0x04, 0x3b, 0x76, 0x00,
 	0x04, 0x6a, 0xd4, 0x81,
-	0x20, 0x3c, 0x72, 0x7a,
-	0x51, 0x6a, 0xec, 0x5e,
-	0x00, 0x65, 0x8c, 0x42,
+	0x20, 0x3c, 0x6a, 0x7a,
+	0x51, 0x6a, 0xd8, 0x5e,
+	0x00, 0x65, 0x82, 0x42,
 	0x20, 0x3c, 0x78, 0x00,
-	0x00, 0xb3, 0xce, 0x5e,
+	0x00, 0xb3, 0xba, 0x5e,
 	0x07, 0xac, 0x10, 0x31,
 	0x05, 0xb3, 0x46, 0x31,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xac, 0x6a, 0x02, 0x5e,
+	0xac, 0x6a, 0xee, 0x5d,
 	0xa3, 0x6a, 0xcc, 0x00,
-	0xb3, 0x6a, 0x06, 0x5e,
-	0x00, 0x65, 0x42, 0x5a,
+	0xb3, 0x6a, 0xf2, 0x5d,
+	0x00, 0x65, 0x3a, 0x5a,
 	0xfd, 0xa4, 0x48, 0x09,
-	0x01, 0x8c, 0xaa, 0x08,
 	0x03, 0x8c, 0x10, 0x30,
-	0x00, 0x65, 0xfa, 0x5d,
-	0x01, 0xa4, 0x9e, 0x7a,
+	0x00, 0x65, 0xe6, 0x5d,
+	0x01, 0xa4, 0x94, 0x7a,
 	0x04, 0x3b, 0x76, 0x08,
 	0x01, 0x3b, 0x26, 0x31,
 	0x80, 0x02, 0x04, 0x00,
-	0x10, 0x0c, 0x94, 0x7a,
-	0x03, 0x9e, 0x96, 0x6a,
+	0x10, 0x0c, 0x8a, 0x7a,
+	0x03, 0x9e, 0x8c, 0x6a,
 	0x7f, 0x02, 0x04, 0x08,
-	0x91, 0x6a, 0xec, 0x5e,
+	0x91, 0x6a, 0xd8, 0x5e,
 	0x00, 0x65, 0xcc, 0x41,
 	0x01, 0xa4, 0xca, 0x30,
-	0x80, 0xa3, 0xa4, 0x7a,
+	0x80, 0xa3, 0x9a, 0x7a,
 	0x02, 0x65, 0xca, 0x00,
-	0x01, 0x55, 0xa8, 0x7a,
-	0x04, 0x65, 0xca, 0x00,
 	0x01, 0x65, 0xf8, 0x31,
 	0x01, 0x3b, 0x26, 0x31,
 	0x00, 0x65, 0x0e, 0x5a,
-	0x01, 0xfc, 0xb6, 0x6a,
-	0x80, 0x0b, 0xac, 0x6a,
-	0x10, 0x0c, 0xac, 0x7a,
-	0x20, 0x93, 0xac, 0x6a,
+	0x01, 0xfc, 0xa8, 0x6a,
+	0x80, 0x0b, 0x9e, 0x6a,
+	0x10, 0x0c, 0x9e, 0x7a,
+	0x20, 0x93, 0x9e, 0x6a,
 	0x02, 0x93, 0x26, 0x01,
-	0x02, 0xfc, 0xc0, 0x7a,
-	0x40, 0x0d, 0xda, 0x6a,
-	0x01, 0xa4, 0x48, 0x01,
-	0x00, 0x65, 0xda, 0x42,
+	0x02, 0xfc, 0xb2, 0x7a,
 	0x40, 0x0d, 0xc6, 0x6a,
+	0x01, 0xa4, 0x48, 0x01,
+	0x00, 0x65, 0xc6, 0x42,
+	0x40, 0x0d, 0xb8, 0x6a,
 	0x00, 0x65, 0x0e, 0x5a,
-	0x00, 0x65, 0xb8, 0x42,
-	0x80, 0xfc, 0xd0, 0x7a,
-	0x80, 0xa4, 0xd0, 0x6a,
+	0x00, 0x65, 0xaa, 0x42,
+	0x80, 0xfc, 0xc2, 0x7a,
+	0x80, 0xa4, 0xc2, 0x6a,
 	0xff, 0xa5, 0x4a, 0x19,
 	0xff, 0xa6, 0x4c, 0x21,
 	0xff, 0xa7, 0x4e, 0x21,
 	0xf8, 0xfc, 0x48, 0x09,
-	0xff, 0x6a, 0xaa, 0x08,
-	0x04, 0xfc, 0xd8, 0x7a,
-	0x01, 0x55, 0xaa, 0x00,
-	0xff, 0x6a, 0x46, 0x09,
-	0x04, 0x3b, 0xf2, 0x6a,
+	0x7f, 0xa3, 0x46, 0x09,
+	0x04, 0x3b, 0xe2, 0x6a,
 	0x02, 0x93, 0x26, 0x01,
-	0x01, 0x94, 0xdc, 0x7a,
-	0x01, 0x94, 0xdc, 0x7a,
-	0x01, 0x94, 0xdc, 0x7a,
-	0x01, 0x94, 0xdc, 0x7a,
-	0x01, 0x94, 0xdc, 0x7a,
-	0x01, 0xa4, 0xf0, 0x7a,
-	0x01, 0xfc, 0xea, 0x7a,
-	0x01, 0x94, 0xf2, 0x6a,
-	0x00, 0x65, 0x8c, 0x42,
-	0x01, 0x94, 0xf0, 0x7a,
-	0x10, 0x94, 0xf2, 0x6a,
+	0x01, 0x94, 0xc8, 0x7a,
+	0x01, 0x94, 0xc8, 0x7a,
+	0x01, 0x94, 0xc8, 0x7a,
+	0x01, 0x94, 0xc8, 0x7a,
+	0x01, 0x94, 0xc8, 0x7a,
+	0x01, 0xa4, 0xe0, 0x7a,
+	0x01, 0xfc, 0xd6, 0x7a,
+	0x01, 0x94, 0xe2, 0x6a,
+	0x01, 0x94, 0xe2, 0x6a,
+	0x01, 0x94, 0xe2, 0x6a,
+	0x00, 0x65, 0x82, 0x42,
+	0x01, 0x94, 0xe0, 0x7a,
+	0x10, 0x94, 0xe2, 0x6a,
 	0xd7, 0x93, 0x26, 0x09,
-	0x28, 0x93, 0xf6, 0x6a,
+	0x28, 0x93, 0xe6, 0x6a,
 	0x01, 0x85, 0x0a, 0x01,
-	0x02, 0xfc, 0xfe, 0x6a,
+	0x02, 0xfc, 0xee, 0x6a,
 	0x01, 0x14, 0x46, 0x31,
 	0xff, 0x6a, 0x10, 0x09,
 	0xfe, 0x85, 0x0a, 0x09,
-	0xff, 0x38, 0x0c, 0x6b,
-	0x80, 0xa3, 0x0c, 0x7b,
-	0x80, 0x0b, 0x0a, 0x7b,
-	0x04, 0x3b, 0x0c, 0x7b,
+	0xff, 0x38, 0xfc, 0x6a,
+	0x80, 0xa3, 0xfc, 0x7a,
+	0x80, 0x0b, 0xfa, 0x7a,
+	0x04, 0x3b, 0xfc, 0x7a,
 	0xbf, 0x3b, 0x76, 0x08,
 	0x01, 0x3b, 0x26, 0x31,
 	0x00, 0x65, 0x0e, 0x5a,
-	0x01, 0x0b, 0x1a, 0x6b,
-	0x10, 0x0c, 0x0e, 0x7b,
-	0x04, 0x93, 0x18, 0x6b,
-	0x01, 0x94, 0x16, 0x7b,
-	0x10, 0x94, 0x18, 0x6b,
+	0x01, 0x0b, 0x0a, 0x6b,
+	0x10, 0x0c, 0xfe, 0x7a,
+	0x04, 0x93, 0x08, 0x6b,
+	0x01, 0x94, 0x06, 0x7b,
+	0x10, 0x94, 0x08, 0x6b,
 	0xc7, 0x93, 0x26, 0x09,
 	0x01, 0x99, 0xd4, 0x30,
-	0x38, 0x93, 0x1c, 0x6b,
-	0xff, 0x08, 0x6e, 0x6b,
-	0xff, 0x09, 0x6e, 0x6b,
-	0xff, 0x0a, 0x6e, 0x6b,
-	0xff, 0x38, 0x38, 0x7b,
+	0x38, 0x93, 0x0c, 0x6b,
+	0xff, 0x08, 0x5a, 0x6b,
+	0xff, 0x09, 0x5a, 0x6b,
+	0xff, 0x0a, 0x5a, 0x6b,
+	0xff, 0x38, 0x28, 0x7b,
 	0x04, 0x14, 0x10, 0x31,
 	0x01, 0x38, 0x18, 0x31,
 	0x02, 0x6a, 0x1a, 0x31,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x14, 0x6a, 0x08, 0x5e,
-	0x00, 0x38, 0xf4, 0x5d,
+	0x14, 0x6a, 0xf4, 0x5d,
+	0x00, 0x38, 0xe0, 0x5d,
 	0xff, 0x6a, 0x70, 0x08,
-	0x00, 0x65, 0x64, 0x43,
-	0x80, 0xa3, 0x3e, 0x7b,
+	0x00, 0x65, 0x54, 0x43,
+	0x80, 0xa3, 0x2e, 0x7b,
 	0x01, 0xa4, 0x48, 0x01,
-	0x00, 0x65, 0x6e, 0x43,
-	0x08, 0xeb, 0x44, 0x7b,
+	0x00, 0x65, 0x5a, 0x43,
+	0x08, 0xeb, 0x34, 0x7b,
 	0x00, 0x65, 0x0e, 0x5a,
-	0x08, 0xeb, 0x40, 0x6b,
+	0x08, 0xeb, 0x30, 0x6b,
 	0x07, 0xe9, 0x10, 0x31,
 	0x01, 0xe9, 0xca, 0x30,
 	0x01, 0x65, 0x46, 0x31,
-	0x00, 0x6a, 0xce, 0x5e,
+	0x00, 0x6a, 0xba, 0x5e,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xa4, 0x6a, 0x08, 0x5e,
-	0x08, 0x6a, 0xf4, 0x5d,
+	0xa4, 0x6a, 0xf4, 0x5d,
+	0x08, 0x6a, 0xe0, 0x5d,
 	0x0d, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0xbc, 0x5e,
+	0x00, 0x65, 0xa8, 0x5e,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x00, 0x65, 0x9e, 0x5e,
+	0x00, 0x65, 0x8a, 0x5e,
 	0x01, 0x99, 0x46, 0x31,
-	0x00, 0xa3, 0xce, 0x5e,
+	0x00, 0xa3, 0xba, 0x5e,
 	0x01, 0x88, 0x10, 0x31,
-	0x00, 0x65, 0x42, 0x5a,
+	0x00, 0x65, 0x3a, 0x5a,
 	0x00, 0x65, 0xfa, 0x59,
 	0x03, 0x8c, 0x10, 0x30,
-	0x00, 0x65, 0xfa, 0x5d,
-	0x01, 0x8c, 0x6c, 0x7b,
-	0x01, 0x55, 0xaa, 0x10,
-	0x80, 0x0b, 0x8c, 0x6a,
-	0x80, 0x0b, 0x76, 0x6b,
-	0x01, 0x0c, 0x70, 0x7b,
-	0x10, 0x0c, 0x8c, 0x7a,
-	0x03, 0x9e, 0x8c, 0x6a,
+	0x00, 0x65, 0xe6, 0x5d,
+	0x80, 0x0b, 0x82, 0x6a,
+	0x80, 0x0b, 0x62, 0x6b,
+	0x01, 0x0c, 0x5c, 0x7b,
+	0x10, 0x0c, 0x82, 0x7a,
+	0x03, 0x9e, 0x82, 0x6a,
 	0x00, 0x65, 0x04, 0x5a,
-	0x00, 0x6a, 0xce, 0x5e,
-	0x01, 0xa4, 0x96, 0x6b,
-	0xff, 0x38, 0x8c, 0x7b,
+	0x00, 0x6a, 0xba, 0x5e,
+	0x01, 0xa4, 0x82, 0x6b,
+	0xff, 0x38, 0x78, 0x7b,
 	0x01, 0x38, 0xc8, 0x30,
 	0x00, 0x08, 0x40, 0x19,
 	0xff, 0x6a, 0xc8, 0x08,
 	0x00, 0x09, 0x42, 0x21,
 	0x00, 0x0a, 0x44, 0x21,
 	0xff, 0x6a, 0x70, 0x08,
-	0x00, 0x65, 0x8e, 0x43,
+	0x00, 0x65, 0x7a, 0x43,
 	0x03, 0x08, 0x40, 0x31,
 	0x03, 0x08, 0x40, 0x31,
 	0x01, 0x08, 0x40, 0x31,
@@ -471,16 +461,16 @@
 	0x04, 0x3c, 0xcc, 0x79,
 	0xfb, 0x3c, 0x78, 0x08,
 	0x04, 0x93, 0x20, 0x79,
-	0x01, 0x0c, 0xa2, 0x6b,
-	0x01, 0x55, 0x20, 0x79,
+	0x01, 0x0c, 0x8e, 0x6b,
+	0x80, 0xba, 0x20, 0x79,
 	0x80, 0x04, 0x20, 0x79,
-	0xe4, 0x6a, 0x82, 0x5d,
-	0x23, 0x6a, 0x98, 0x5d,
-	0x01, 0x6a, 0x98, 0x5d,
+	0xe4, 0x6a, 0x6e, 0x5d,
+	0x23, 0x6a, 0x84, 0x5d,
+	0x01, 0x6a, 0x84, 0x5d,
 	0x00, 0x65, 0x20, 0x41,
 	0x00, 0x65, 0xcc, 0x41,
-	0x80, 0x3c, 0xb6, 0x7b,
-	0x21, 0x6a, 0xec, 0x5e,
+	0x80, 0x3c, 0xa2, 0x7b,
+	0x21, 0x6a, 0xd8, 0x5e,
 	0x01, 0xbc, 0x18, 0x31,
 	0x02, 0x6a, 0x1a, 0x31,
 	0x02, 0x6a, 0xf8, 0x01,
@@ -490,16 +480,16 @@
 	0xff, 0x6a, 0x12, 0x08,
 	0xff, 0x6a, 0x14, 0x08,
 	0xf3, 0xbc, 0xd4, 0x18,
-	0xa0, 0x6a, 0xdc, 0x53,
+	0xa0, 0x6a, 0xc8, 0x53,
 	0x04, 0xa0, 0x10, 0x31,
 	0xac, 0x6a, 0x26, 0x01,
 	0x04, 0xa0, 0x10, 0x31,
 	0x03, 0x08, 0x18, 0x31,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xa0, 0x6a, 0x08, 0x5e,
-	0x00, 0xbc, 0xf4, 0x5d,
+	0xa0, 0x6a, 0xf4, 0x5d,
+	0x00, 0xbc, 0xe0, 0x5d,
 	0x3d, 0x6a, 0x26, 0x01,
-	0x00, 0x65, 0xf4, 0x43,
+	0x00, 0x65, 0xe0, 0x43,
 	0xff, 0x6a, 0x10, 0x09,
 	0xa4, 0x6a, 0x26, 0x01,
 	0x0c, 0xa0, 0x32, 0x31,
@@ -509,128 +499,128 @@
 	0x36, 0x6a, 0x26, 0x01,
 	0x02, 0x93, 0x26, 0x01,
 	0x35, 0x6a, 0x26, 0x01,
-	0x00, 0x65, 0xb0, 0x5e,
-	0x00, 0x65, 0xb0, 0x5e,
+	0x00, 0x65, 0x9c, 0x5e,
+	0x00, 0x65, 0x9c, 0x5e,
 	0x02, 0x93, 0x26, 0x01,
 	0xbf, 0x3c, 0x78, 0x08,
-	0x04, 0x0b, 0xfa, 0x6b,
-	0x10, 0x0c, 0xf6, 0x7b,
-	0x01, 0x03, 0xfa, 0x6b,
-	0x20, 0x93, 0xfc, 0x6b,
-	0x04, 0x0b, 0x02, 0x6c,
+	0x04, 0x0b, 0xe6, 0x6b,
+	0x10, 0x0c, 0xe2, 0x7b,
+	0x01, 0x03, 0xe6, 0x6b,
+	0x20, 0x93, 0xe8, 0x6b,
+	0x04, 0x0b, 0xee, 0x6b,
 	0x40, 0x3c, 0x78, 0x00,
 	0xc7, 0x93, 0x26, 0x09,
-	0x38, 0x93, 0x04, 0x6c,
+	0x38, 0x93, 0xf0, 0x6b,
 	0x00, 0x65, 0xcc, 0x41,
-	0x80, 0x3c, 0x6a, 0x6c,
+	0x80, 0x3c, 0x56, 0x6c,
 	0x01, 0x06, 0x50, 0x31,
 	0x80, 0xb8, 0x70, 0x01,
 	0x00, 0x65, 0xcc, 0x41,
 	0x10, 0x3f, 0x06, 0x00,
 	0x10, 0x6a, 0x06, 0x00,
 	0x01, 0x3a, 0xca, 0x30,
-	0x80, 0x65, 0x30, 0x64,
-	0x10, 0xb8, 0x54, 0x6c,
-	0xc0, 0xba, 0xca, 0x00,
-	0x40, 0xb8, 0x20, 0x6c,
+	0x80, 0x65, 0x1c, 0x64,
+	0x10, 0xb8, 0x40, 0x6c,
+	0xc0, 0x3e, 0xca, 0x00,
+	0x40, 0xb8, 0x0c, 0x6c,
 	0xbf, 0x65, 0xca, 0x08,
-	0x20, 0xb8, 0x34, 0x7c,
+	0x20, 0xb8, 0x20, 0x7c,
 	0x01, 0x65, 0x0c, 0x30,
-	0x00, 0x65, 0xec, 0x5d,
-	0xa0, 0x3f, 0x3c, 0x64,
+	0x00, 0x65, 0xd8, 0x5d,
+	0xa0, 0x3f, 0x28, 0x64,
 	0x23, 0xb8, 0x0c, 0x08,
-	0x00, 0x65, 0xec, 0x5d,
-	0xa0, 0x3f, 0x3c, 0x64,
-	0x00, 0xbb, 0x34, 0x44,
-	0xff, 0x65, 0x34, 0x64,
-	0x00, 0x65, 0x54, 0x44,
+	0x00, 0x65, 0xd8, 0x5d,
+	0xa0, 0x3f, 0x28, 0x64,
+	0x00, 0xbb, 0x20, 0x44,
+	0xff, 0x65, 0x20, 0x64,
+	0x00, 0x65, 0x40, 0x44,
 	0x40, 0x6a, 0x18, 0x00,
 	0x01, 0x65, 0x0c, 0x30,
-	0x00, 0x65, 0xec, 0x5d,
-	0xa0, 0x3f, 0x10, 0x74,
+	0x00, 0x65, 0xd8, 0x5d,
+	0xa0, 0x3f, 0xfc, 0x73,
 	0x40, 0x6a, 0x18, 0x00,
 	0x01, 0x3a, 0xa6, 0x30,
 	0x08, 0x6a, 0x74, 0x00,
 	0x00, 0x65, 0xcc, 0x41,
-	0x64, 0x6a, 0x7c, 0x5d,
-	0x80, 0x64, 0xec, 0x6c,
-	0x04, 0x64, 0xae, 0x74,
-	0x02, 0x64, 0xbe, 0x74,
-	0x00, 0x6a, 0x74, 0x74,
-	0x03, 0x64, 0xdc, 0x74,
-	0x23, 0x64, 0x5c, 0x74,
-	0x08, 0x64, 0x70, 0x74,
-	0x61, 0x6a, 0xec, 0x5e,
-	0x00, 0x65, 0xec, 0x5d,
+	0x64, 0x6a, 0x68, 0x5d,
+	0x80, 0x64, 0xd8, 0x6c,
+	0x04, 0x64, 0x9a, 0x74,
+	0x02, 0x64, 0xaa, 0x74,
+	0x00, 0x6a, 0x60, 0x74,
+	0x03, 0x64, 0xc8, 0x74,
+	0x23, 0x64, 0x48, 0x74,
+	0x08, 0x64, 0x5c, 0x74,
+	0x61, 0x6a, 0xd8, 0x5e,
+	0x00, 0x65, 0xd8, 0x5d,
 	0x08, 0x51, 0xce, 0x71,
-	0x00, 0x65, 0x54, 0x44,
-	0x80, 0x04, 0x6e, 0x7c,
-	0x51, 0x6a, 0x72, 0x5d,
-	0x01, 0x51, 0x6e, 0x64,
-	0x01, 0xa4, 0x66, 0x7c,
-	0x01, 0x55, 0x70, 0x7c,
-	0x41, 0x6a, 0xec, 0x5e,
-	0x00, 0x65, 0x70, 0x44,
-	0x21, 0x6a, 0xec, 0x5e,
-	0x00, 0x65, 0x70, 0x44,
-	0x07, 0x6a, 0x68, 0x5d,
+	0x00, 0x65, 0x40, 0x44,
+	0x80, 0x04, 0x5a, 0x7c,
+	0x51, 0x6a, 0x5e, 0x5d,
+	0x01, 0x51, 0x5a, 0x64,
+	0x01, 0xa4, 0x52, 0x7c,
+	0x80, 0xba, 0x5c, 0x6c,
+	0x41, 0x6a, 0xd8, 0x5e,
+	0x00, 0x65, 0x5c, 0x44,
+	0x21, 0x6a, 0xd8, 0x5e,
+	0x00, 0x65, 0x5c, 0x44,
+	0x07, 0x6a, 0x54, 0x5d,
 	0x01, 0x06, 0xd4, 0x30,
 	0x00, 0x65, 0xcc, 0x41,
-	0x80, 0xb8, 0x6a, 0x7c,
-	0xc0, 0x3c, 0x7e, 0x7c,
-	0x80, 0x3c, 0x6a, 0x6c,
-	0xff, 0xa8, 0x7e, 0x6c,
-	0x40, 0x3c, 0x6a, 0x6c,
-	0x10, 0xb8, 0x82, 0x7c,
-	0xa1, 0x6a, 0xec, 0x5e,
-	0x01, 0xb4, 0x88, 0x6c,
-	0x02, 0xb4, 0x8a, 0x6c,
-	0x01, 0xa4, 0x8a, 0x7c,
-	0xff, 0xa8, 0x9a, 0x7c,
+	0x80, 0xb8, 0x56, 0x7c,
+	0xc0, 0x3c, 0x6a, 0x7c,
+	0x80, 0x3c, 0x56, 0x6c,
+	0xff, 0xa8, 0x6a, 0x6c,
+	0x40, 0x3c, 0x56, 0x6c,
+	0x10, 0xb8, 0x6e, 0x7c,
+	0xa1, 0x6a, 0xd8, 0x5e,
+	0x01, 0xb4, 0x74, 0x6c,
+	0x02, 0xb4, 0x76, 0x6c,
+	0x01, 0xa4, 0x76, 0x7c,
+	0xff, 0xa8, 0x86, 0x7c,
 	0x04, 0xb4, 0x68, 0x01,
 	0x01, 0x6a, 0x76, 0x00,
-	0x00, 0xbb, 0x26, 0x5e,
-	0xff, 0xa8, 0x9a, 0x7c,
-	0x71, 0x6a, 0xec, 0x5e,
-	0x40, 0x51, 0x9a, 0x64,
-	0x00, 0x65, 0xc6, 0x5e,
+	0x00, 0xbb, 0x12, 0x5e,
+	0xff, 0xa8, 0x86, 0x7c,
+	0x71, 0x6a, 0xd8, 0x5e,
+	0x40, 0x51, 0x86, 0x64,
+	0x00, 0x65, 0xb2, 0x5e,
 	0x00, 0x65, 0xde, 0x41,
-	0x00, 0xbb, 0x9e, 0x5c,
+	0x00, 0xbb, 0x8a, 0x5c,
 	0x00, 0x65, 0xde, 0x41,
-	0x00, 0x65, 0xc6, 0x5e,
+	0x00, 0x65, 0xb2, 0x5e,
 	0x01, 0x65, 0xa2, 0x30,
 	0x01, 0xf8, 0xc8, 0x30,
 	0x01, 0x4e, 0xc8, 0x30,
-	0x00, 0x6a, 0xca, 0xdd,
-	0x00, 0x51, 0xdc, 0x5d,
+	0x00, 0x6a, 0xb6, 0xdd,
+	0x00, 0x51, 0xc8, 0x5d,
 	0x01, 0x4e, 0x9c, 0x18,
 	0x02, 0x6a, 0x22, 0x05,
-	0xc0, 0x3c, 0x6a, 0x6c,
+	0xc0, 0x3c, 0x56, 0x6c,
 	0x04, 0xb8, 0x70, 0x01,
-	0x00, 0x65, 0xe8, 0x5e,
+	0x00, 0x65, 0xd4, 0x5e,
 	0x20, 0xb8, 0xde, 0x69,
 	0x01, 0xbb, 0xa2, 0x30,
-	0x01, 0xba, 0x7c, 0x30,
-	0x00, 0xb9, 0xe2, 0x5c,
+	0x3f, 0xba, 0x7c, 0x08,
+	0x00, 0xb9, 0xce, 0x5c,
 	0x00, 0x65, 0xde, 0x41,
 	0x01, 0x06, 0xd4, 0x30,
 	0x20, 0x3c, 0xcc, 0x79,
-	0x20, 0x3c, 0x70, 0x7c,
-	0x01, 0xa4, 0xcc, 0x7c,
+	0x20, 0x3c, 0x5c, 0x7c,
+	0x01, 0xa4, 0xb8, 0x7c,
 	0x01, 0xb4, 0x68, 0x01,
 	0x00, 0x65, 0xcc, 0x41,
-	0x00, 0x65, 0x70, 0x44,
+	0x00, 0x65, 0x5c, 0x44,
 	0x04, 0x14, 0x58, 0x31,
 	0x01, 0x06, 0xd4, 0x30,
 	0x08, 0xa0, 0x60, 0x31,
 	0xac, 0x6a, 0xcc, 0x00,
-	0x14, 0x6a, 0x08, 0x5e,
+	0x14, 0x6a, 0xf4, 0x5d,
 	0x01, 0x06, 0xd4, 0x30,
-	0xa0, 0x6a, 0x00, 0x5e,
+	0xa0, 0x6a, 0xec, 0x5d,
 	0x00, 0x65, 0xcc, 0x41,
 	0xdf, 0x3c, 0x78, 0x08,
 	0x12, 0x01, 0x02, 0x00,
-	0x00, 0x65, 0x70, 0x44,
+	0x00, 0x65, 0x5c, 0x44,
 	0x4c, 0x65, 0xcc, 0x28,
 	0x01, 0x3e, 0x20, 0x31,
 	0xd0, 0x66, 0xcc, 0x18,
@@ -641,102 +631,102 @@
 	0xd0, 0x65, 0xca, 0x18,
 	0x01, 0x3e, 0x20, 0x31,
 	0x30, 0x65, 0xd4, 0x18,
-	0x00, 0x65, 0xfa, 0x4c,
+	0x00, 0x65, 0xe6, 0x4c,
 	0xe1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
 	0x20, 0x65, 0xd4, 0x18,
-	0x00, 0x65, 0x02, 0x55,
+	0x00, 0x65, 0xee, 0x54,
 	0xe1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
 	0x20, 0x65, 0xca, 0x18,
 	0xe0, 0x65, 0xd4, 0x18,
-	0x00, 0x65, 0x0c, 0x4d,
+	0x00, 0x65, 0xf8, 0x4c,
 	0xe1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
 	0xd0, 0x65, 0xd4, 0x18,
-	0x00, 0x65, 0x14, 0x55,
+	0x00, 0x65, 0x00, 0x55,
 	0xe1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
 	0x01, 0x6c, 0xa2, 0x30,
-	0xff, 0x51, 0x26, 0x75,
-	0x00, 0x51, 0xa2, 0x5d,
+	0xff, 0x51, 0x12, 0x75,
+	0x00, 0x51, 0x8e, 0x5d,
 	0x01, 0x51, 0x20, 0x31,
-	0x00, 0x65, 0x48, 0x45,
-	0x01, 0xba, 0xc8, 0x30,
-	0x00, 0x3e, 0x48, 0x75,
-	0x00, 0x65, 0xc4, 0x5e,
+	0x00, 0x65, 0x34, 0x45,
+	0x3f, 0xba, 0xc8, 0x08,
+	0x00, 0x3e, 0x34, 0x75,
+	0x00, 0x65, 0xb0, 0x5e,
 	0x80, 0x3c, 0x78, 0x00,
 	0x01, 0x06, 0xd4, 0x30,
-	0x00, 0x65, 0xec, 0x5d,
+	0x00, 0x65, 0xd8, 0x5d,
 	0x01, 0x3c, 0x78, 0x00,
-	0xe0, 0x3f, 0x64, 0x65,
+	0xe0, 0x3f, 0x50, 0x65,
 	0x02, 0x3c, 0x78, 0x00,
-	0x20, 0x12, 0x64, 0x65,
-	0x51, 0x6a, 0x72, 0x5d,
-	0x00, 0x51, 0xa2, 0x5d,
-	0x51, 0x6a, 0x72, 0x5d,
+	0x20, 0x12, 0x50, 0x65,
+	0x51, 0x6a, 0x5e, 0x5d,
+	0x00, 0x51, 0x8e, 0x5d,
+	0x51, 0x6a, 0x5e, 0x5d,
 	0x01, 0x51, 0x20, 0x31,
 	0x04, 0x3c, 0x78, 0x00,
 	0x01, 0xb9, 0xc8, 0x30,
-	0x00, 0x3d, 0x62, 0x65,
+	0x00, 0x3d, 0x4e, 0x65,
 	0x08, 0x3c, 0x78, 0x00,
-	0x01, 0xba, 0xc8, 0x30,
-	0x00, 0x3e, 0x62, 0x65,
+	0x3f, 0xba, 0xc8, 0x08,
+	0x00, 0x3e, 0x4e, 0x65,
 	0x10, 0x3c, 0x78, 0x00,
-	0x04, 0xb8, 0x62, 0x7d,
+	0x04, 0xb8, 0x4e, 0x7d,
 	0xfb, 0xb8, 0x70, 0x09,
-	0x20, 0xb8, 0x58, 0x6d,
+	0x20, 0xb8, 0x44, 0x6d,
 	0x01, 0x90, 0xc8, 0x30,
 	0xff, 0x6a, 0xa2, 0x00,
-	0x00, 0x3d, 0xe2, 0x5c,
+	0x00, 0x3d, 0xce, 0x5c,
 	0x01, 0x64, 0x20, 0x31,
 	0xff, 0x6a, 0x78, 0x08,
 	0x00, 0x65, 0xea, 0x58,
-	0x10, 0xb8, 0x70, 0x7c,
-	0xff, 0x6a, 0x68, 0x5d,
-	0x00, 0x65, 0x70, 0x44,
-	0x00, 0x65, 0xc4, 0x5e,
-	0x31, 0x6a, 0xec, 0x5e,
-	0x00, 0x65, 0x70, 0x44,
+	0x10, 0xb8, 0x5c, 0x7c,
+	0xff, 0x6a, 0x54, 0x5d,
+	0x00, 0x65, 0x5c, 0x44,
+	0x00, 0x65, 0xb0, 0x5e,
+	0x31, 0x6a, 0xd8, 0x5e,
+	0x00, 0x65, 0x5c, 0x44,
 	0x10, 0x3f, 0x06, 0x00,
 	0x10, 0x6a, 0x06, 0x00,
 	0x01, 0x65, 0x74, 0x34,
-	0x81, 0x6a, 0xec, 0x5e,
-	0x00, 0x65, 0x74, 0x45,
+	0x81, 0x6a, 0xd8, 0x5e,
+	0x00, 0x65, 0x60, 0x45,
 	0x01, 0x06, 0xd4, 0x30,
-	0x01, 0x0c, 0x74, 0x7d,
-	0x04, 0x0c, 0x6e, 0x6d,
+	0x01, 0x0c, 0x60, 0x7d,
+	0x04, 0x0c, 0x5a, 0x6d,
 	0xe0, 0x03, 0x7e, 0x08,
 	0xe0, 0x3f, 0xcc, 0x61,
 	0x01, 0x65, 0xcc, 0x30,
 	0x01, 0x12, 0xda, 0x34,
 	0x01, 0x06, 0xd4, 0x34,
-	0x01, 0x03, 0x82, 0x6d,
+	0x01, 0x03, 0x6e, 0x6d,
 	0x40, 0x03, 0xcc, 0x08,
 	0x01, 0x65, 0x06, 0x30,
 	0x40, 0x65, 0xc8, 0x08,
-	0x00, 0x66, 0x90, 0x75,
-	0x40, 0x65, 0x90, 0x7d,
-	0x00, 0x65, 0x90, 0x5d,
+	0x00, 0x66, 0x7c, 0x75,
+	0x40, 0x65, 0x7c, 0x7d,
+	0x00, 0x65, 0x7c, 0x5d,
 	0xff, 0x6a, 0xd4, 0x08,
 	0xff, 0x6a, 0xd4, 0x08,
 	0xff, 0x6a, 0xd4, 0x08,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0x08, 0x01, 0x02, 0x00,
-	0x02, 0x0b, 0x9a, 0x7d,
+	0x02, 0x0b, 0x86, 0x7d,
 	0x01, 0x65, 0x0c, 0x30,
-	0x02, 0x0b, 0x9e, 0x7d,
+	0x02, 0x0b, 0x8a, 0x7d,
 	0xf7, 0x01, 0x02, 0x0c,
 	0x01, 0x65, 0xc8, 0x30,
-	0xff, 0x41, 0xc2, 0x75,
+	0xff, 0x41, 0xae, 0x75,
 	0x01, 0x41, 0x20, 0x31,
 	0xff, 0x6a, 0xa4, 0x00,
-	0x00, 0x65, 0xb2, 0x45,
-	0xff, 0xbf, 0xc2, 0x75,
+	0x00, 0x65, 0x9e, 0x45,
+	0xff, 0xbf, 0xae, 0x75,
 	0x01, 0x90, 0xa4, 0x30,
 	0x01, 0xbf, 0x20, 0x31,
-	0x00, 0xbb, 0xac, 0x65,
-	0xff, 0x52, 0xc0, 0x75,
+	0x00, 0xbb, 0x98, 0x65,
+	0xff, 0x52, 0xac, 0x75,
 	0x01, 0xbf, 0xcc, 0x30,
 	0x01, 0x90, 0xca, 0x30,
 	0x01, 0x52, 0x20, 0x31,
@@ -744,28 +734,28 @@
 	0x01, 0x65, 0x20, 0x35,
 	0x01, 0xbf, 0x82, 0x34,
 	0x01, 0x64, 0xa2, 0x30,
-	0x00, 0x6a, 0xd4, 0x5e,
+	0x00, 0x6a, 0xc0, 0x5e,
 	0x0d, 0x6a, 0x76, 0x00,
-	0x00, 0x51, 0x26, 0x46,
+	0x00, 0x51, 0x12, 0x46,
 	0x01, 0x65, 0xa4, 0x30,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x48, 0x6a, 0x1a, 0x5e,
+	0x48, 0x6a, 0x06, 0x5e,
 	0x01, 0x6a, 0xd0, 0x01,
 	0x01, 0x6a, 0xdc, 0x05,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x48, 0x6a, 0x1a, 0x5e,
-	0x01, 0x6a, 0xf4, 0x5d,
+	0x48, 0x6a, 0x06, 0x5e,
+	0x01, 0x6a, 0xe0, 0x5d,
 	0x01, 0x6a, 0x26, 0x05,
 	0x01, 0x65, 0xd8, 0x31,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0xe0, 0x7d,
+	0x80, 0xee, 0xcc, 0x7d,
 	0xff, 0x6a, 0xdc, 0x0d,
 	0x01, 0x65, 0x32, 0x31,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0xbc, 0x46,
-	0x81, 0x6a, 0xec, 0x5e,
-	0x01, 0x0c, 0xec, 0x7d,
-	0x04, 0x0c, 0xea, 0x6d,
+	0x00, 0x65, 0xa8, 0x46,
+	0x81, 0x6a, 0xd8, 0x5e,
+	0x01, 0x0c, 0xd8, 0x7d,
+	0x04, 0x0c, 0xd6, 0x6d,
 	0xe0, 0x03, 0x06, 0x08,
 	0xe0, 0x03, 0x7e, 0x0c,
 	0x01, 0x65, 0x18, 0x31,
@@ -784,7 +774,7 @@
 	0x01, 0x6c, 0xda, 0x34,
 	0x3d, 0x64, 0xa4, 0x28,
 	0x55, 0x64, 0xc8, 0x28,
-	0x00, 0x65, 0x1a, 0x46,
+	0x00, 0x65, 0x06, 0x46,
 	0x2e, 0x64, 0xa4, 0x28,
 	0x66, 0x64, 0xc8, 0x28,
 	0x00, 0x6c, 0xda, 0x18,
@@ -795,63 +785,63 @@
 	0x00, 0x6c, 0xda, 0x24,
 	0x01, 0x65, 0xc8, 0x30,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x44, 0x6a, 0x16, 0x5e,
+	0x44, 0x6a, 0x02, 0x5e,
 	0x01, 0x90, 0xe2, 0x31,
-	0x04, 0x3b, 0x3a, 0x7e,
+	0x04, 0x3b, 0x26, 0x7e,
 	0x30, 0x6a, 0xd0, 0x01,
 	0x20, 0x6a, 0xd0, 0x01,
 	0x1d, 0x6a, 0xdc, 0x01,
-	0xdc, 0xee, 0x36, 0x66,
-	0x00, 0x65, 0x52, 0x46,
+	0xdc, 0xee, 0x22, 0x66,
+	0x00, 0x65, 0x3e, 0x46,
 	0x20, 0x6a, 0xd0, 0x01,
 	0x01, 0x6a, 0xdc, 0x01,
 	0x20, 0xa0, 0xd8, 0x31,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0x42, 0x7e,
+	0x80, 0xee, 0x2e, 0x7e,
 	0x11, 0x6a, 0xdc, 0x01,
-	0x50, 0xee, 0x46, 0x66,
+	0x50, 0xee, 0x32, 0x66,
 	0x20, 0x6a, 0xd0, 0x01,
 	0x09, 0x6a, 0xdc, 0x01,
-	0x88, 0xee, 0x4c, 0x66,
+	0x88, 0xee, 0x38, 0x66,
 	0x19, 0x6a, 0xdc, 0x01,
-	0xd8, 0xee, 0x50, 0x66,
+	0xd8, 0xee, 0x3c, 0x66,
 	0xff, 0x6a, 0xdc, 0x09,
-	0x18, 0xee, 0x54, 0x6e,
+	0x18, 0xee, 0x40, 0x6e,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x44, 0x6a, 0x16, 0x5e,
-	0x20, 0x6a, 0xf4, 0x5d,
+	0x44, 0x6a, 0x02, 0x5e,
+	0x20, 0x6a, 0xe0, 0x5d,
 	0x01, 0x3b, 0x26, 0x31,
-	0x04, 0x3b, 0x6e, 0x6e,
+	0x04, 0x3b, 0x5a, 0x6e,
 	0xa0, 0x6a, 0xca, 0x00,
 	0x20, 0x65, 0xc8, 0x18,
-	0x00, 0x65, 0xac, 0x5e,
-	0x00, 0x65, 0x66, 0x66,
+	0x00, 0x65, 0x98, 0x5e,
+	0x00, 0x65, 0x52, 0x66,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0xbc, 0x46,
+	0x00, 0x65, 0xa8, 0x46,
 	0xa0, 0x6a, 0xcc, 0x00,
 	0xff, 0x6a, 0xc8, 0x08,
-	0x20, 0x94, 0x72, 0x6e,
-	0x10, 0x94, 0x74, 0x6e,
-	0x08, 0x94, 0x8e, 0x6e,
-	0x08, 0x94, 0x8e, 0x6e,
-	0x08, 0x94, 0x8e, 0x6e,
+	0x20, 0x94, 0x5e, 0x6e,
+	0x10, 0x94, 0x60, 0x6e,
+	0x08, 0x94, 0x7a, 0x6e,
+	0x08, 0x94, 0x7a, 0x6e,
+	0x08, 0x94, 0x7a, 0x6e,
 	0xff, 0x8c, 0xc8, 0x10,
 	0xc1, 0x64, 0xc8, 0x18,
 	0xf8, 0x64, 0xc8, 0x08,
 	0x01, 0x99, 0xda, 0x30,
-	0x00, 0x66, 0x82, 0x66,
-	0xc0, 0x66, 0xbe, 0x76,
+	0x00, 0x66, 0x6e, 0x66,
+	0xc0, 0x66, 0xaa, 0x76,
 	0x60, 0x66, 0xc8, 0x18,
 	0x3d, 0x64, 0xc8, 0x28,
-	0x00, 0x65, 0x72, 0x46,
+	0x00, 0x65, 0x5e, 0x46,
 	0xf7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0x90, 0x6e,
+	0x08, 0x93, 0x7c, 0x6e,
 	0x00, 0x62, 0xc4, 0x18,
-	0x00, 0x65, 0xbc, 0x5e,
-	0x00, 0x65, 0x9c, 0x5e,
-	0x00, 0x65, 0x9c, 0x5e,
-	0x00, 0x65, 0x9c, 0x5e,
+	0x00, 0x65, 0xa8, 0x5e,
+	0x00, 0x65, 0x88, 0x5e,
+	0x00, 0x65, 0x88, 0x5e,
+	0x00, 0x65, 0x88, 0x5e,
 	0x01, 0x99, 0xda, 0x30,
 	0x01, 0x99, 0xda, 0x30,
 	0x01, 0x99, 0xda, 0x30,
@@ -868,11 +858,11 @@
 	0x01, 0x6c, 0x32, 0x31,
 	0x01, 0x6c, 0x32, 0x31,
 	0x01, 0x6c, 0x32, 0x35,
-	0x08, 0x94, 0xbc, 0x7e,
+	0x08, 0x94, 0xa8, 0x7e,
 	0xf7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0xc0, 0x6e,
+	0x08, 0x93, 0xac, 0x6e,
 	0xff, 0x6a, 0xd4, 0x0c,
-	0x04, 0xb8, 0xe8, 0x6e,
+	0x04, 0xb8, 0xd4, 0x6e,
 	0x01, 0x42, 0x7e, 0x31,
 	0xff, 0x6a, 0x76, 0x01,
 	0x01, 0x90, 0x84, 0x34,
@@ -880,14 +870,14 @@
 	0x01, 0x85, 0x0a, 0x01,
 	0x7f, 0x65, 0x10, 0x09,
 	0xfe, 0x85, 0x0a, 0x0d,
-	0xff, 0x42, 0xe4, 0x66,
-	0xff, 0x41, 0xdc, 0x66,
-	0xd1, 0x6a, 0xec, 0x5e,
+	0xff, 0x42, 0xd0, 0x66,
+	0xff, 0x41, 0xc8, 0x66,
+	0xd1, 0x6a, 0xd8, 0x5e,
 	0xff, 0x6a, 0xca, 0x04,
 	0x01, 0x41, 0x20, 0x31,
 	0x01, 0xbf, 0x82, 0x30,
 	0x01, 0x6a, 0x76, 0x00,
-	0x00, 0xbb, 0x26, 0x46,
+	0x00, 0xbb, 0x12, 0x46,
 	0x01, 0x42, 0x20, 0x31,
 	0x01, 0xbf, 0x84, 0x34,
 	0x01, 0x41, 0x7e, 0x31,
@@ -1157,147 +1147,147 @@
 	{ ahc_patch1_func, 248, 1, 2 },
 	{ ahc_patch0_func, 249, 2, 2 },
 	{ ahc_patch11_func, 250, 1, 1 },
-	{ ahc_patch9_func, 258, 31, 3 },
-	{ ahc_patch1_func, 274, 14, 2 },
-	{ ahc_patch13_func, 279, 1, 1 },
-	{ ahc_patch14_func, 289, 14, 1 },
-	{ ahc_patch1_func, 305, 1, 2 },
-	{ ahc_patch0_func, 306, 1, 1 },
-	{ ahc_patch9_func, 309, 1, 1 },
-	{ ahc_patch13_func, 314, 1, 1 },
-	{ ahc_patch9_func, 315, 2, 2 },
-	{ ahc_patch0_func, 317, 4, 1 },
-	{ ahc_patch14_func, 321, 1, 1 },
-	{ ahc_patch15_func, 324, 2, 3 },
-	{ ahc_patch9_func, 324, 1, 2 },
-	{ ahc_patch0_func, 325, 1, 1 },
-	{ ahc_patch6_func, 330, 1, 2 },
-	{ ahc_patch0_func, 331, 1, 1 },
-	{ ahc_patch1_func, 335, 50, 11 },
-	{ ahc_patch6_func, 344, 2, 4 },
-	{ ahc_patch7_func, 344, 1, 1 },
-	{ ahc_patch8_func, 345, 1, 1 },
-	{ ahc_patch0_func, 346, 1, 1 },
-	{ ahc_patch16_func, 347, 1, 1 },
-	{ ahc_patch6_func, 366, 6, 3 },
-	{ ahc_patch16_func, 366, 5, 1 },
-	{ ahc_patch0_func, 372, 5, 1 },
-	{ ahc_patch13_func, 380, 5, 1 },
-	{ ahc_patch0_func, 385, 54, 17 },
-	{ ahc_patch14_func, 385, 1, 1 },
-	{ ahc_patch7_func, 387, 2, 2 },
-	{ ahc_patch17_func, 388, 1, 1 },
-	{ ahc_patch9_func, 391, 1, 1 },
-	{ ahc_patch18_func, 398, 1, 1 },
-	{ ahc_patch14_func, 403, 9, 3 },
-	{ ahc_patch9_func, 404, 3, 2 },
-	{ ahc_patch0_func, 407, 3, 1 },
-	{ ahc_patch9_func, 415, 6, 2 },
-	{ ahc_patch0_func, 421, 9, 2 },
-	{ ahc_patch13_func, 421, 1, 1 },
-	{ ahc_patch13_func, 430, 2, 1 },
-	{ ahc_patch14_func, 432, 1, 1 },
-	{ ahc_patch9_func, 434, 1, 2 },
-	{ ahc_patch0_func, 435, 1, 1 },
-	{ ahc_patch7_func, 438, 1, 1 },
-	{ ahc_patch7_func, 439, 1, 1 },
-	{ ahc_patch8_func, 440, 3, 3 },
-	{ ahc_patch6_func, 441, 1, 2 },
-	{ ahc_patch0_func, 442, 1, 1 },
-	{ ahc_patch9_func, 443, 1, 1 },
-	{ ahc_patch15_func, 444, 1, 2 },
-	{ ahc_patch13_func, 444, 1, 1 },
-	{ ahc_patch14_func, 446, 9, 4 },
-	{ ahc_patch9_func, 446, 1, 1 },
-	{ ahc_patch9_func, 453, 2, 1 },
-	{ ahc_patch0_func, 455, 4, 3 },
-	{ ahc_patch9_func, 455, 1, 2 },
-	{ ahc_patch0_func, 456, 3, 1 },
-	{ ahc_patch1_func, 460, 2, 1 },
-	{ ahc_patch7_func, 462, 10, 2 },
-	{ ahc_patch0_func, 472, 1, 1 },
-	{ ahc_patch8_func, 473, 118, 22 },
-	{ ahc_patch1_func, 475, 3, 2 },
-	{ ahc_patch0_func, 478, 5, 3 },
-	{ ahc_patch9_func, 478, 2, 2 },
-	{ ahc_patch0_func, 480, 3, 1 },
+	{ ahc_patch9_func, 258, 27, 3 },
+	{ ahc_patch1_func, 274, 10, 2 },
+	{ ahc_patch13_func, 277, 1, 1 },
+	{ ahc_patch14_func, 285, 14, 1 },
+	{ ahc_patch1_func, 301, 1, 2 },
+	{ ahc_patch0_func, 302, 1, 1 },
+	{ ahc_patch9_func, 305, 1, 1 },
+	{ ahc_patch13_func, 310, 1, 1 },
+	{ ahc_patch9_func, 311, 2, 2 },
+	{ ahc_patch0_func, 313, 4, 1 },
+	{ ahc_patch14_func, 317, 1, 1 },
+	{ ahc_patch15_func, 319, 2, 3 },
+	{ ahc_patch9_func, 319, 1, 2 },
+	{ ahc_patch0_func, 320, 1, 1 },
+	{ ahc_patch6_func, 325, 1, 2 },
+	{ ahc_patch0_func, 326, 1, 1 },
+	{ ahc_patch1_func, 330, 47, 11 },
+	{ ahc_patch6_func, 337, 2, 4 },
+	{ ahc_patch7_func, 337, 1, 1 },
+	{ ahc_patch8_func, 338, 1, 1 },
+	{ ahc_patch0_func, 339, 1, 1 },
+	{ ahc_patch16_func, 340, 1, 1 },
+	{ ahc_patch6_func, 356, 6, 3 },
+	{ ahc_patch16_func, 356, 5, 1 },
+	{ ahc_patch0_func, 362, 7, 1 },
+	{ ahc_patch13_func, 372, 5, 1 },
+	{ ahc_patch0_func, 377, 52, 17 },
+	{ ahc_patch14_func, 377, 1, 1 },
+	{ ahc_patch7_func, 379, 2, 2 },
+	{ ahc_patch17_func, 380, 1, 1 },
+	{ ahc_patch9_func, 383, 1, 1 },
+	{ ahc_patch18_func, 390, 1, 1 },
+	{ ahc_patch14_func, 395, 9, 3 },
+	{ ahc_patch9_func, 396, 3, 2 },
+	{ ahc_patch0_func, 399, 3, 1 },
+	{ ahc_patch9_func, 407, 6, 2 },
+	{ ahc_patch0_func, 413, 9, 2 },
+	{ ahc_patch13_func, 413, 1, 1 },
+	{ ahc_patch13_func, 422, 2, 1 },
+	{ ahc_patch14_func, 424, 1, 1 },
+	{ ahc_patch9_func, 426, 1, 2 },
+	{ ahc_patch0_func, 427, 1, 1 },
+	{ ahc_patch7_func, 428, 1, 1 },
+	{ ahc_patch7_func, 429, 1, 1 },
+	{ ahc_patch8_func, 430, 3, 3 },
+	{ ahc_patch6_func, 431, 1, 2 },
+	{ ahc_patch0_func, 432, 1, 1 },
+	{ ahc_patch9_func, 433, 1, 1 },
+	{ ahc_patch15_func, 434, 1, 2 },
+	{ ahc_patch13_func, 434, 1, 1 },
+	{ ahc_patch14_func, 436, 9, 4 },
+	{ ahc_patch9_func, 436, 1, 1 },
+	{ ahc_patch9_func, 443, 2, 1 },
+	{ ahc_patch0_func, 445, 4, 3 },
+	{ ahc_patch9_func, 445, 1, 2 },
+	{ ahc_patch0_func, 446, 3, 1 },
+	{ ahc_patch1_func, 450, 2, 1 },
+	{ ahc_patch7_func, 452, 10, 2 },
+	{ ahc_patch0_func, 462, 1, 1 },
+	{ ahc_patch8_func, 463, 118, 22 },
+	{ ahc_patch1_func, 465, 3, 2 },
+	{ ahc_patch0_func, 468, 5, 3 },
+	{ ahc_patch9_func, 468, 2, 2 },
+	{ ahc_patch0_func, 470, 3, 1 },
+	{ ahc_patch1_func, 475, 2, 2 },
+	{ ahc_patch0_func, 477, 6, 3 },
+	{ ahc_patch9_func, 477, 2, 2 },
+	{ ahc_patch0_func, 479, 3, 1 },
 	{ ahc_patch1_func, 485, 2, 2 },
-	{ ahc_patch0_func, 487, 6, 3 },
-	{ ahc_patch9_func, 487, 2, 2 },
-	{ ahc_patch0_func, 489, 3, 1 },
-	{ ahc_patch1_func, 495, 2, 2 },
-	{ ahc_patch0_func, 497, 9, 7 },
-	{ ahc_patch9_func, 497, 5, 6 },
-	{ ahc_patch19_func, 497, 1, 2 },
-	{ ahc_patch0_func, 498, 1, 1 },
-	{ ahc_patch19_func, 500, 1, 2 },
-	{ ahc_patch0_func, 501, 1, 1 },
-	{ ahc_patch0_func, 502, 4, 1 },
-	{ ahc_patch6_func, 507, 3, 2 },
-	{ ahc_patch0_func, 510, 1, 1 },
-	{ ahc_patch6_func, 520, 1, 2 },
-	{ ahc_patch0_func, 521, 1, 1 },
-	{ ahc_patch20_func, 558, 7, 1 },
-	{ ahc_patch3_func, 593, 1, 2 },
-	{ ahc_patch0_func, 594, 1, 1 },
-	{ ahc_patch21_func, 597, 1, 1 },
-	{ ahc_patch8_func, 599, 106, 33 },
-	{ ahc_patch4_func, 601, 1, 1 },
-	{ ahc_patch1_func, 607, 2, 2 },
-	{ ahc_patch0_func, 609, 1, 1 },
-	{ ahc_patch1_func, 612, 1, 2 },
-	{ ahc_patch0_func, 613, 1, 1 },
-	{ ahc_patch9_func, 614, 3, 3 },
-	{ ahc_patch15_func, 615, 1, 1 },
-	{ ahc_patch0_func, 617, 4, 1 },
-	{ ahc_patch19_func, 626, 2, 2 },
-	{ ahc_patch0_func, 628, 1, 1 },
-	{ ahc_patch19_func, 632, 10, 3 },
-	{ ahc_patch5_func, 634, 8, 1 },
-	{ ahc_patch0_func, 642, 9, 2 },
-	{ ahc_patch5_func, 643, 8, 1 },
-	{ ahc_patch4_func, 653, 1, 2 },
-	{ ahc_patch0_func, 654, 1, 1 },
-	{ ahc_patch19_func, 655, 1, 2 },
-	{ ahc_patch0_func, 656, 3, 2 },
-	{ ahc_patch4_func, 658, 1, 1 },
-	{ ahc_patch5_func, 659, 1, 1 },
-	{ ahc_patch5_func, 662, 1, 1 },
-	{ ahc_patch5_func, 664, 1, 1 },
-	{ ahc_patch4_func, 666, 2, 2 },
-	{ ahc_patch0_func, 668, 2, 1 },
-	{ ahc_patch5_func, 670, 1, 1 },
-	{ ahc_patch5_func, 673, 1, 1 },
-	{ ahc_patch5_func, 676, 1, 1 },
-	{ ahc_patch19_func, 680, 1, 1 },
-	{ ahc_patch19_func, 683, 1, 1 },
-	{ ahc_patch4_func, 689, 1, 1 },
-	{ ahc_patch6_func, 692, 1, 2 },
-	{ ahc_patch0_func, 693, 1, 1 },
-	{ ahc_patch7_func, 705, 16, 1 },
-	{ ahc_patch4_func, 721, 20, 1 },
-	{ ahc_patch9_func, 742, 4, 2 },
-	{ ahc_patch0_func, 746, 4, 1 },
-	{ ahc_patch9_func, 750, 4, 2 },
-	{ ahc_patch0_func, 754, 3, 1 },
-	{ ahc_patch6_func, 760, 1, 1 },
-	{ ahc_patch22_func, 762, 14, 1 },
-	{ ahc_patch7_func, 776, 3, 1 },
-	{ ahc_patch9_func, 788, 24, 8 },
-	{ ahc_patch19_func, 792, 1, 2 },
-	{ ahc_patch0_func, 793, 1, 1 },
-	{ ahc_patch15_func, 798, 4, 2 },
-	{ ahc_patch0_func, 802, 7, 3 },
-	{ ahc_patch23_func, 802, 5, 2 },
-	{ ahc_patch0_func, 807, 2, 1 },
-	{ ahc_patch0_func, 812, 42, 3 },
-	{ ahc_patch18_func, 824, 18, 2 },
-	{ ahc_patch0_func, 842, 1, 1 },
-	{ ahc_patch4_func, 866, 1, 1 },
-	{ ahc_patch4_func, 867, 3, 2 },
-	{ ahc_patch0_func, 870, 1, 1 },
-	{ ahc_patch13_func, 871, 3, 1 },
-	{ ahc_patch4_func, 874, 12, 1 }
+	{ ahc_patch0_func, 487, 9, 7 },
+	{ ahc_patch9_func, 487, 5, 6 },
+	{ ahc_patch19_func, 487, 1, 2 },
+	{ ahc_patch0_func, 488, 1, 1 },
+	{ ahc_patch19_func, 490, 1, 2 },
+	{ ahc_patch0_func, 491, 1, 1 },
+	{ ahc_patch0_func, 492, 4, 1 },
+	{ ahc_patch6_func, 497, 3, 2 },
+	{ ahc_patch0_func, 500, 1, 1 },
+	{ ahc_patch6_func, 510, 1, 2 },
+	{ ahc_patch0_func, 511, 1, 1 },
+	{ ahc_patch20_func, 548, 7, 1 },
+	{ ahc_patch3_func, 583, 1, 2 },
+	{ ahc_patch0_func, 584, 1, 1 },
+	{ ahc_patch21_func, 587, 1, 1 },
+	{ ahc_patch8_func, 589, 106, 33 },
+	{ ahc_patch4_func, 591, 1, 1 },
+	{ ahc_patch1_func, 597, 2, 2 },
+	{ ahc_patch0_func, 599, 1, 1 },
+	{ ahc_patch1_func, 602, 1, 2 },
+	{ ahc_patch0_func, 603, 1, 1 },
+	{ ahc_patch9_func, 604, 3, 3 },
+	{ ahc_patch15_func, 605, 1, 1 },
+	{ ahc_patch0_func, 607, 4, 1 },
+	{ ahc_patch19_func, 616, 2, 2 },
+	{ ahc_patch0_func, 618, 1, 1 },
+	{ ahc_patch19_func, 622, 10, 3 },
+	{ ahc_patch5_func, 624, 8, 1 },
+	{ ahc_patch0_func, 632, 9, 2 },
+	{ ahc_patch5_func, 633, 8, 1 },
+	{ ahc_patch4_func, 643, 1, 2 },
+	{ ahc_patch0_func, 644, 1, 1 },
+	{ ahc_patch19_func, 645, 1, 2 },
+	{ ahc_patch0_func, 646, 3, 2 },
+	{ ahc_patch4_func, 648, 1, 1 },
+	{ ahc_patch5_func, 649, 1, 1 },
+	{ ahc_patch5_func, 652, 1, 1 },
+	{ ahc_patch5_func, 654, 1, 1 },
+	{ ahc_patch4_func, 656, 2, 2 },
+	{ ahc_patch0_func, 658, 2, 1 },
+	{ ahc_patch5_func, 660, 1, 1 },
+	{ ahc_patch5_func, 663, 1, 1 },
+	{ ahc_patch5_func, 666, 1, 1 },
+	{ ahc_patch19_func, 670, 1, 1 },
+	{ ahc_patch19_func, 673, 1, 1 },
+	{ ahc_patch4_func, 679, 1, 1 },
+	{ ahc_patch6_func, 682, 1, 2 },
+	{ ahc_patch0_func, 683, 1, 1 },
+	{ ahc_patch7_func, 695, 16, 1 },
+	{ ahc_patch4_func, 711, 20, 1 },
+	{ ahc_patch9_func, 732, 4, 2 },
+	{ ahc_patch0_func, 736, 4, 1 },
+	{ ahc_patch9_func, 740, 4, 2 },
+	{ ahc_patch0_func, 744, 3, 1 },
+	{ ahc_patch6_func, 750, 1, 1 },
+	{ ahc_patch22_func, 752, 14, 1 },
+	{ ahc_patch7_func, 766, 3, 1 },
+	{ ahc_patch9_func, 778, 24, 8 },
+	{ ahc_patch19_func, 782, 1, 2 },
+	{ ahc_patch0_func, 783, 1, 1 },
+	{ ahc_patch15_func, 788, 4, 2 },
+	{ ahc_patch0_func, 792, 7, 3 },
+	{ ahc_patch23_func, 792, 5, 2 },
+	{ ahc_patch0_func, 797, 2, 1 },
+	{ ahc_patch0_func, 802, 42, 3 },
+	{ ahc_patch18_func, 814, 18, 2 },
+	{ ahc_patch0_func, 832, 1, 1 },
+	{ ahc_patch4_func, 856, 1, 1 },
+	{ ahc_patch4_func, 857, 3, 2 },
+	{ ahc_patch0_func, 860, 1, 1 },
+	{ ahc_patch13_func, 861, 3, 1 },
+	{ ahc_patch4_func, 864, 12, 1 }
 };
 
 static struct cs {
@@ -1306,11 +1296,11 @@
 } critical_sections[] = {
 	{ 11, 18 },
 	{ 21, 30 },
-	{ 721, 737 },
-	{ 867, 870 },
-	{ 874, 880 },
-	{ 882, 884 },
-	{ 884, 886 }
+	{ 711, 727 },
+	{ 857, 860 },
+	{ 864, 870 },
+	{ 872, 874 },
+	{ 874, 876 }
 };
 
 static const int num_critical_sections = sizeof(critical_sections)
diff -Nru a/drivers/scsi/aic7xxx/aiclib.h b/drivers/scsi/aic7xxx/aiclib.h
--- a/drivers/scsi/aic7xxx/aiclib.h	Thu Apr 24 14:12:34 2003
+++ b/drivers/scsi/aic7xxx/aiclib.h	Wed May 14 15:00:40 2003
@@ -60,12 +60,9 @@
 /*
  * Linux Interrupt Support.
  */
-#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
+#ifndef IRQ_RETVAL
+typedef void irqreturn_t;
+#define	IRQ_RETVAL(x)
 #endif
 
 /*
diff -Nru a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
--- a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c	Tue Feb  4 11:14:05 2003
+++ b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c	Mon May 12 07:40:10 2003
@@ -80,10 +80,9 @@
  *   Return information to handle /proc support for the driver.
  *-F*************************************************************************/
 int
-aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, 
-                    int hostno, int inout)
+aic7xxx_proc_info ( struct Scsi_Host *HBAptr, char *buffer, char **start, off_t offset, int length, 
+                    int inout)
 {
-  struct Scsi_Host *HBAptr;
   struct aic7xxx_host *p;
   struct aic_dev_data *aic_dev;
   struct scsi_device *sdptr;
@@ -93,12 +92,12 @@
 
   HBAptr = NULL;
 
-  for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next)
+  for(p=first_aic7xxx; p->host != HBAptr; p=p->next)
     ;
 
   if (!p)
   {
-    size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno);
+    size += sprintf(buffer, "Can't find adapter for host number %d\n", HBAptr->host_no);
     if (size > length)
     {
       return (size);
@@ -108,8 +107,6 @@
       return (length);
     }
   }
-
-  HBAptr = p->host;
 
   if (inout == TRUE) /* Has data been written to the file? */ 
   {
diff -Nru a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
--- a/drivers/scsi/arm/acornscsi.c	Sat May 17 11:00:48 2003
+++ b/drivers/scsi/arm/acornscsi.c	Mon May 19 19:40:43 2003
@@ -2857,18 +2857,15 @@
     return string;
 }
 
-int acornscsi_proc_info(char *buffer, char **start, off_t offset,
-			int length, int host_no, int inout)
+int acornscsi_proc_info(struct Scsi_Host *instance, char *buffer, char **start, off_t offset,
+			int length, 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)
+    if (inout == 1)
 	return -EINVAL;
 
     host  = (AS_Host *)instance->hostdata;
diff -Nru a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c
--- a/drivers/scsi/arm/arxescsi.c	Sat May 17 08:48:41 2003
+++ b/drivers/scsi/arm/arxescsi.c	Mon May 19 19:40:44 2003
@@ -236,17 +236,12 @@
  * Returns : length of data written to buffer.
  */
 static int
-arxescsi_proc_info(char *buffer, char **start, off_t offset, int length,
+arxescsi_proc_info(struct Scsi_Host *host, 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)
diff -Nru a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
--- a/drivers/scsi/arm/cumana_1.c	Sat May 17 08:48:41 2003
+++ b/drivers/scsi/arm/cumana_1.c	Mon May 19 19:40:44 2003
@@ -35,9 +35,6 @@
 #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
 
diff -Nru a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
--- a/drivers/scsi/arm/cumana_2.c	Sat May 17 11:02:30 2003
+++ b/drivers/scsi/arm/cumana_2.c	Mon May 19 19:40:45 2003
@@ -353,17 +353,12 @@
  *	      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 cumanascsi_2_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+			    int length, 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);
diff -Nru a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c
--- a/drivers/scsi/arm/ecoscsi.c	Sat May 17 06:52:32 2003
+++ b/drivers/scsi/arm/ecoscsi.c	Mon May 19 19:40:45 2003
@@ -233,9 +233,6 @@
 #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
 
diff -Nru a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c
--- a/drivers/scsi/arm/eesox.c	Sat May 17 11:00:49 2003
+++ b/drivers/scsi/arm/eesox.c	Mon May 19 19:40:46 2003
@@ -427,17 +427,12 @@
  *	      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 eesoxscsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+			    int length, 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);
diff -Nru a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
--- a/drivers/scsi/arm/oak.c	Sat May 17 08:48:42 2003
+++ b/drivers/scsi/arm/oak.c	Mon May 19 19:40:46 2003
@@ -30,9 +30,6 @@
 #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
diff -Nru a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
--- a/drivers/scsi/arm/powertec.c	Sat May 17 08:48:43 2003
+++ b/drivers/scsi/arm/powertec.c	Mon May 19 19:40:47 2003
@@ -239,19 +239,14 @@
  *	      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 powertecscsi_proc_info(struct Scsi_Host *host, 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)
+	If (inout == 1)
 		return powertecscsi_set_proc_info(host, buffer, length);
 
 	info = (struct powertec_info *)host->hostdata;
diff -Nru a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
--- a/drivers/scsi/atari_NCR5380.c	Fri May  9 03:21:34 2003
+++ b/drivers/scsi/atari_NCR5380.c	Mon May 26 18:54:33 2003
@@ -746,11 +746,10 @@
 #ifndef NCR5380_proc_info
 static
 #endif
-int NCR5380_proc_info (char *buffer, char **start, off_t offset,
-		       int length, int hostno, int inout)
+int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, off_t offset,
+		       int length, int inout)
 {
     char *pos = buffer;
-    struct Scsi_Host *instance;
     struct NCR5380_hostdata *hostdata;
     Scsi_Cmnd *ptr;
     unsigned long flags;
@@ -763,9 +762,6 @@
 	}					\
     } while (0)
 
-    instance = scsi_host_hn_get(hostno);
-    if (!instance)
-	return(-ESRCH);
     hostdata = (struct NCR5380_hostdata *)instance->hostdata;
 
     if (inout) { /* Has data been written to the file ? */
diff -Nru a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h
--- a/drivers/scsi/atari_scsi.h	Sun Feb  9 11:14:51 2003
+++ b/drivers/scsi/atari_scsi.h	Mon May 12 07:26:11 2003
@@ -21,7 +21,6 @@
 int atari_scsi_detect (Scsi_Host_Template *);
 const char *atari_scsi_info (struct Scsi_Host *);
 int atari_scsi_reset (Scsi_Cmnd *, unsigned int);
-int atari_scsi_proc_info (char *, char **, off_t, int, int, int);
 #ifdef MODULE
 int atari_scsi_release (struct Scsi_Host *);
 #else
diff -Nru a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
--- a/drivers/scsi/atp870u.c	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/atp870u.c	Mon May 12 08:07:29 2003
@@ -2657,33 +2657,14 @@
 }
 
 #define BLS buffer + len + size
-int atp870u_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+int atp870u_proc_info(struct Scsi_Host *HBAptr, char *buffer, char **start, off_t offset, int length, int inout)
 {
-	struct Scsi_Host *HBAptr;
 	static u8 buff[512];
-	int i;
 	int size = 0;
 	int len = 0;
 	off_t begin = 0;
 	off_t pos = 0;
 
-	HBAptr = NULL;
-	for (i = 0; i < MAX_ATP; i++) {
-		if ((HBAptr = atp_host[i]) != NULL) {
-			if (HBAptr->host_no == hostno) {
-				break;
-			}
-			HBAptr = NULL;
-		}
-	}
-
-	if (HBAptr == NULL) {
-		size += sprintf(BLS, "Can't find adapter for host number %d\n", hostno);
-		len += size;
-		pos = begin + len;
-		size = 0;
-		goto stop_output;
-	}
 	if (inout == TRUE) {	/* Has data been written to the file? */
 		return (atp870u_set_info(buffer, length, HBAptr));
 	}
@@ -2701,9 +2682,7 @@
 	size += sprintf(BLS, "                   IRQ: %d\n", HBAptr->irq);
 	len += size;
 	pos = begin + len;
-	size = 0;
 
-stop_output:
 	*start = buffer + (offset - begin);	/* Start of wanted data */
 	len -= (offset - begin);	/* Start slop */
 	if (len > length) {
diff -Nru a/drivers/scsi/atp870u.h b/drivers/scsi/atp870u.h
--- a/drivers/scsi/atp870u.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/atp870u.h	Mon May 12 07:26:11 2003
@@ -35,6 +35,4 @@
 
 extern const char *atp870u_info(struct Scsi_Host *);
 
-extern int atp870u_proc_info(char *, char **, off_t, int, int, int);
-
 #endif
diff -Nru a/drivers/scsi/cpqfcTS.h b/drivers/scsi/cpqfcTS.h
--- a/drivers/scsi/cpqfcTS.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/cpqfcTS.h	Mon May 12 07:26:11 2003
@@ -6,7 +6,7 @@
 extern int cpqfcTS_detect(Scsi_Host_Template *);
 extern int cpqfcTS_release(struct Scsi_Host *);
 extern const char * cpqfcTS_info(struct Scsi_Host *);
-extern int cpqfcTS_proc_info(char *, char **, off_t, int, int, int);
+extern int cpqfcTS_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
 extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
 extern int cpqfcTS_abort(Scsi_Cmnd *);
 extern int cpqfcTS_reset(Scsi_Cmnd *, unsigned int);
diff -Nru a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
--- a/drivers/scsi/cpqfcTSinit.c	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/cpqfcTSinit.c	Mon May 12 07:26:11 2003
@@ -921,10 +921,9 @@
 
 // Routine to get data for /proc RAM filesystem
 //
-int cpqfcTS_proc_info (char *buffer, char **start, off_t offset, int length, 
-		       int hostno, int inout)
+int cpqfcTS_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, 
+		       int inout)
 {
-  struct Scsi_Host *host;
   Scsi_Cmnd DumCmnd;
   int Chan, Targ, i;
   struct info_str info;
@@ -933,11 +932,6 @@
   PFC_LOGGEDIN_PORT pLoggedInPort;
   char buf[81];
 
-  // Search the Scsi host list for our controller
-  host = scsi_host_hn_get(hostno);
-
-  if (!host) return -ESRCH;
-
   if (inout) return -EINVAL;
 
   // get the pointer to our Scsi layer HBA buffer  
@@ -969,7 +963,7 @@
     				NULL,     // DON'T search list for FC WWN
     				NULL))){   // DON'T care about end of list
 	copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ",
-			   hostno, Chan, Targ);
+			   host->host_no, Chan, Targ);
         for( i=3; i>=0; i--)        // copy the LOGIN port's WWN
           copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
         for( i=7; i>3; i--)             // copy the LOGIN port's WWN
diff -Nru a/drivers/scsi/dc390.h b/drivers/scsi/dc390.h
--- a/drivers/scsi/dc390.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/dc390.h	Mon May 12 08:06:40 2003
@@ -33,8 +33,6 @@
 # define USE_NEW_EH
 #endif
 
-#if defined(HOSTS_C) || defined(MODULE) || LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99)
-
 extern int DC390_detect(Scsi_Host_Template *psht);
 extern int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
 extern int DC390_abort(Scsi_Cmnd *cmd);
@@ -47,7 +45,5 @@
 #else
 # define DC390_release NULL
 #endif
-
-extern int DC390_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
 
 #endif /* DC390_H */
diff -Nru a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
--- a/drivers/scsi/dc395x.c	Tue May  6 13:16:34 2003
+++ b/drivers/scsi/dc395x.c	Mon May 19 19:40:42 2003
@@ -5364,7 +5364,7 @@
 	eeprom = &dc395x_trm_eepromBuf[index];
 	pTempACB = DC395x_pACB_start;
 	if (pTempACB != NULL) {
-		for (; (pTempACB != (struct AdapterCtlBlk *) -1);) {
+		while (pTempACB) {
 			if (pTempACB->IRQLevel == irq) {
 				used_irq = 1;
 				break;
@@ -5842,11 +5842,11 @@
 		if (!DC395x_pACB_start) {
 			DC395x_pACB_start = pACB;
 			DC395x_pACB_current = pACB;
-			pACB->pNextACB = (struct AdapterCtlBlk *) -1;
+			pACB->pNextACB = NULL;
 		} else {
 			DC395x_pACB_current->pNextACB = pACB;
 			DC395x_pACB_current = pACB;
-			pACB->pNextACB = (struct AdapterCtlBlk *) -1;
+			pACB->pNextACB = NULL;
 		}
 		/*DC395x_ACB_UNLOCK(pACB,acb_flags); */
 		return host;
@@ -6062,12 +6062,11 @@
  else SPRINTF(" No  ")
 
 static int
-DC395x_proc_info(char *buffer, char **start, off_t offset, int length,
-		 int hostno, int inout)
+DC395x_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length,
+		 int inout)
 {
 	int dev, spd, spd1;
 	char *pos = buffer;
-	struct Scsi_Host *shpnt = NULL;
 	struct AdapterCtlBlk *pACB;
 	struct DeviceCtlBlk *pDCB;
 	unsigned long flags;
@@ -6077,16 +6076,12 @@
 
 	pACB = DC395x_pACB_start;
 
-	while (pACB != (struct AdapterCtlBlk *) -1) {
-		shpnt = pACB->pScsiHost;
-		if (shpnt->host_no == hostno)
+	while (pACB) {
+		if (pACB->pScsiHost == shpnt)
 			break;
 		pACB = pACB->pNextACB;
 	}
-	if (pACB == (struct AdapterCtlBlk *) -1)
-		return -ESRCH;
-
-	if (!shpnt)
+	if (!pACB)
 		return -ESRCH;
 
 	if (inout)		/* Has data been written to the file ? */
@@ -6306,7 +6301,7 @@
 		 */
 		int irq_count;
 		for (irq_count = 0, pACB = DC395x_pACB_start;
-		     pACB != (struct AdapterCtlBlk *) -1;
+		     pACB;
 		     pACB = pACB->pNextACB) {
 			if (pACB->IRQLevel == host->irq)
 				++irq_count;
diff -Nru a/drivers/scsi/dmx3191d.h b/drivers/scsi/dmx3191d.h
--- a/drivers/scsi/dmx3191d.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/dmx3191d.h	Mon May 12 08:01:09 2003
@@ -1,4 +1,3 @@
-
 /*
     dmx3191d.h - defines for the Domex DMX3191D SCSI card.
     Copyright (C) 2000 by Massimo Piccioni <dafastidio@libero.it>
@@ -23,7 +22,6 @@
 static int dmx3191d_abort(Scsi_Cmnd *);
 static int dmx3191d_detect(Scsi_Host_Template *);
 static const char* dmx3191d_info(struct Scsi_Host *);
-static int dmx3191d_proc_info(char *, char **, off_t, int, int, int);
 static int dmx3191d_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 static int dmx3191d_release_resources(struct Scsi_Host *);
 static int dmx3191d_bus_reset(Scsi_Cmnd *);
diff -Nru a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
--- a/drivers/scsi/dpt_i2o.c	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/dpt_i2o.c	Mon May 12 07:26:11 2003
@@ -505,8 +505,8 @@
 	return (char *) (pHba->detail);
 }
 
-static int adpt_proc_info(char *buffer, char **start, off_t offset,
-		  int length, int hostno, int inout)
+static int adpt_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+		  int length, int inout)
 {
 	struct adpt_device* d;
 	int id;
@@ -515,7 +515,6 @@
 	int begin = 0;
 	int pos = 0;
 	adpt_hba* pHba;
-	struct Scsi_Host *host;
 	int unit;
 
 	*start = buffer;
@@ -539,7 +538,7 @@
 	// Find HBA (host bus adapter) we are looking for
 	down(&adpt_configuration_lock);
 	for (pHba = hba_chain; pHba; pHba = pHba->next) {
-		if (pHba->host->host_no == hostno) {
+		if (pHba->host == host) {
 			break;	/* found adapter */
 		}
 	}
diff -Nru a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
--- a/drivers/scsi/dpti.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/dpti.h	Mon May 12 07:26:11 2003
@@ -37,8 +37,6 @@
  * SCSI interface function Prototypes
  */
 
-static int adpt_proc_info(char *buffer, char **start, off_t offset,
-		  int length, int inode, int inout);
 static int adpt_detect(Scsi_Host_Template * sht);
 static int adpt_queue(Scsi_Cmnd * cmd, void (*cmdcomplete) (Scsi_Cmnd *));
 static int adpt_abort(Scsi_Cmnd * cmd);
diff -Nru a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h
--- a/drivers/scsi/dtc.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/dtc.h	Mon May 12 07:26:11 2003
@@ -36,8 +36,6 @@
 static int dtc_bus_reset(Scsi_Cmnd *);
 static int dtc_device_reset(Scsi_Cmnd *);
 static int dtc_host_reset(Scsi_Cmnd *);
-static int dtc_proc_info (char *buffer, char **start, off_t offset,
-		   int length, int hostno, int inout);
 
 #ifndef CMD_PER_LUN
 #define CMD_PER_LUN 2
diff -Nru a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
--- a/drivers/scsi/eata_pio.c	Sun May 25 17:00:00 2003
+++ b/drivers/scsi/eata_pio.c	Mon May 26 18:54:34 2003
@@ -102,20 +102,15 @@
  * length: If inout==FALSE max number of bytes to be written into the buffer 
  *         else number of bytes in the buffer
  */
-static int eata_pio_proc_info(char *buffer, char **start, off_t offset,
-			      int length, int hostno, int rw)
+static int eata_pio_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset,
+			      int length, int rw)
 {
-    struct Scsi_Host *shost;
     static u8 buff[512];
     int size, len = 0;
     off_t begin = 0, pos = 0;
 
     if (rw)
     	return -ENOSYS;
-    shost = scsi_host_hn_get(hostno);
-    if (!shost)
-    	return -EINVAL;
-
     if (offset == 0)
 	memset(buff, 0, sizeof(buff));
 
diff -Nru a/drivers/scsi/esp.c b/drivers/scsi/esp.c
--- a/drivers/scsi/esp.c	Sun May 18 03:04:59 2003
+++ b/drivers/scsi/esp.c	Mon May 26 18:54:35 2003
@@ -1408,8 +1408,8 @@
 }
 
 /* ESP proc filesystem code. */
-static int esp_proc_info(char *buffer, char **start, off_t offset,
-			 int length, int hostno, int inout)
+static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+			 int length, int inout)
 {
 	struct esp *esp;
 
@@ -1417,7 +1417,7 @@
 		return -EINVAL; /* not yet */
 
 	for_each_esp(esp) {
-		if (esp->ehost->host_no == hostno)
+		if (esp->ehost == host)
 			break;
 	}
 	if (!esp)
diff -Nru a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c
--- a/drivers/scsi/fcal.c	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/fcal.c	Mon May 12 07:26:12 2003
@@ -209,17 +209,12 @@
 #undef SPRINTF
 #define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); }
 
-int fcal_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+int fcal_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout)
 {
-	struct Scsi_Host *host = NULL;
 	struct fcal *fcal;
 	fc_channel *fc;
 	char *pos = buffer;
 	int i, j;
-
-	host = scsi_host_hn_get(hostno);
-
-	if (!host) return -ESRCH;
 
 	if (inout) return length;
     
diff -Nru a/drivers/scsi/fcal.h b/drivers/scsi/fcal.h
--- a/drivers/scsi/fcal.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/fcal.h	Mon May 12 07:26:12 2003
@@ -22,7 +22,6 @@
 
 int fcal_detect(Scsi_Host_Template *);
 int fcal_release(struct Scsi_Host *);
-int fcal_proc_info (char *, char **, off_t, int, int, int);
 int fcal_slave_configure(Scsi_Device *);
 
 #endif /* !(_FCAL_H) */
diff -Nru a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
--- a/drivers/scsi/fd_mcs.c	Thu May  8 11:24:14 2003
+++ b/drivers/scsi/fd_mcs.c	Mon May 12 07:26:12 2003
@@ -586,9 +586,8 @@
  * length: If inout==FALSE max number of bytes to be written into the buffer 
  *         else number of bytes in the buffer
  */
-static int fd_mcs_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+static int fd_mcs_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout)
 {
-	struct Scsi_Host *shpnt;
 	int len = 0;
 	int i;
 
@@ -597,20 +596,10 @@
 
 	*start = buffer + offset;
 
-	for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++);
-	shpnt = hosts[i];
-
-	if (!shpnt) {
-		return (-ENOENT);
-	} else {
-		len += sprintf(buffer + len, "Future Domain MCS-600/700 Driver %s\n", DRIVER_VERSION);
-
-		len += sprintf(buffer + len, "HOST #%d: %s\n", hostno, adapter_name);
-
-		len += sprintf(buffer + len, "FIFO Size=0x%x, FIFO Count=%d\n", FIFO_Size, FIFO_COUNT);
-
-		len += sprintf(buffer + len, "DriverCalls=%d, Interrupts=%d, BytesRead=%d, BytesWrite=%d\n\n", TOTAL_INTR, INTR_Processed, Bytes_Read, Bytes_Written);
-	}
+	len += sprintf(buffer + len, "Future Domain MCS-600/700 Driver %s\n", DRIVER_VERSION);
+	len += sprintf(buffer + len, "HOST #%d: %s\n", shpnt->host_no, adapter_name);
+	len += sprintf(buffer + len, "FIFO Size=0x%x, FIFO Count=%d\n", FIFO_Size, FIFO_COUNT);
+	len += sprintf(buffer + len, "DriverCalls=%d, Interrupts=%d, BytesRead=%d, BytesWrite=%d\n\n", TOTAL_INTR, INTR_Processed, Bytes_Read, Bytes_Written);
 
 	if ((len -= offset) <= 0)
 		return 0;
diff -Nru a/drivers/scsi/fd_mcs.h b/drivers/scsi/fd_mcs.h
--- a/drivers/scsi/fd_mcs.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/fd_mcs.h	Mon May 12 07:26:12 2003
@@ -32,7 +32,6 @@
 static int fd_mcs_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 static int fd_mcs_biosparam(struct scsi_device *, struct block_device *,
 			    sector_t, int *);
-static int fd_mcs_proc_info(char *, char **, off_t, int, int, int);
 static const char *fd_mcs_info(struct Scsi_Host *);
 
 #endif				/* _FD_MCS_H */
diff -Nru a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
--- a/drivers/scsi/fdomain.c	Sat Apr 26 07:28:20 2003
+++ b/drivers/scsi/fdomain.c	Mon May 12 07:26:12 2003
@@ -1068,45 +1068,6 @@
    return buffer;
 }
 
-				/* First pass at /proc information routine. */
-/*
- * inout : decides on the direction of the dataflow and the meaning of the 
- *         variables
- * buffer: If inout==FALSE data is being written to it else read from it
- * *start: If inout==FALSE start of the valid data in the buffer
- * offset: If inout==FALSE offset from the beginning of the imaginary file 
- *         from which we start writing into the buffer
- * length: If inout==FALSE max number of bytes to be written into the buffer 
- *         else number of bytes in the buffer
- */
-static int fdomain_16x0_proc_info( char *buffer, char **start, off_t offset,
-			    int length, int hostno, int inout )
-{
-   const char *info = fdomain_16x0_info( NULL );
-   int        len;
-   int        pos;
-   int        begin;
-
-   if (inout) return(-EINVAL);
-    
-   begin = 0;
-   strcpy( buffer, info );
-   strcat( buffer, "\n" );
-
-   pos = len = strlen( buffer );
-
-   if(pos < offset) {
-      len = 0;
-      begin = pos;
-   }
-    
-   *start = buffer + (offset - begin);   /* Start of wanted data */
-   len -= (offset - begin);
-   if(len > length) len = length;
-   
-   return(len);
-}
-   
 #if 0
 static int fdomain_arbitrate( void )
 {
@@ -1870,7 +1831,6 @@
 	.module			= THIS_MODULE,
 	.name			= "fdomain",
 	.proc_name		= "fdomain",
-	.proc_info		= fdomain_16x0_proc_info,
 	.detect			= fdomain_16x0_detect,
 	.info			= fdomain_16x0_info,
 	.command		= fdomain_16x0_command,
diff -Nru a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
--- a/drivers/scsi/g_NCR5380.c	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/g_NCR5380.c	Mon May 12 07:26:12 2003
@@ -770,14 +770,13 @@
  *	Locks: global cli/lock for queue walk
  */
  
-int generic_NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+int generic_NCR5380_proc_info(struct Scsi_Host *scsi_ptr, char *buffer, char **start, off_t offset, int length, int inout)
 {
 	int len = 0;
 	NCR5380_local_declare();
 	unsigned long flags;
 	unsigned char status;
 	int i;
-	struct Scsi_Host *scsi_ptr;
 	Scsi_Cmnd *ptr;
 	struct NCR5380_hostdata *hostdata;
 #ifdef NCR5380_STATS
@@ -785,9 +784,6 @@
 	extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
 #endif
 
-	/* For now this is constant so we may walk it */
-	scsi_ptr = scsi_host_hn_get(hostno);
-	
 	NCR5380_setup(scsi_ptr);
 	hostdata = (struct NCR5380_hostdata *) scsi_ptr->hostdata;
 
diff -Nru a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
--- a/drivers/scsi/g_NCR5380.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/g_NCR5380.h	Thu May 22 18:23:21 2003
@@ -51,11 +51,8 @@
 static int generic_NCR5380_bus_reset(Scsi_Cmnd *);
 static int generic_NCR5380_host_reset(Scsi_Cmnd *);
 static int generic_NCR5380_device_reset(Scsi_Cmnd *);
-static int notyet_generic_proc_info (char *buffer ,char **start, off_t offset,
-                     int length, int hostno, int inout);
 static const char* generic_NCR5380_info(struct Scsi_Host *);
 static int generic_NCR5380_biosparam(struct scsi_device *, struct block_device *, sector_t, int *);
-static int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout);
 
 #ifndef CMD_PER_LUN
 #define CMD_PER_LUN 2
@@ -102,7 +99,7 @@
 #define NCR5380_region_size 0x3a00
 
 #define NCR5380_read(reg) isa_readb(NCR5380_map_name + NCR53C400_mem_base + (reg))
-#define NCR5380_write(reg, value) isa_writeb(NCR5380_map_name + NCR53C400_mem_base + (reg), value)
+#define NCR5380_write(reg, value) isa_writeb(value, NCR5380_map_name + NCR53C400_mem_base + (reg))
 #endif
 
 #define NCR5380_implementation_fields \
diff -Nru a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
--- a/drivers/scsi/gdth.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/gdth.h	Mon May 12 07:26:12 2003
@@ -978,7 +978,7 @@
 
 #if LINUX_VERSION_CODE >= 0x020501
 int gdth_bios_param(struct scsi_device *,struct block_device *,sector_t,int *);
-int gdth_proc_info(char *,char **,off_t,int,int,int);
+int gdth_proc_info(struct Scsi_Host *, char *,char **,off_t,int,int);
 int gdth_eh_abort(Scsi_Cmnd *scp);
 int gdth_eh_device_reset(Scsi_Cmnd *scp);
 int gdth_eh_bus_reset(Scsi_Cmnd *scp);
diff -Nru a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
--- a/drivers/scsi/gdth_proc.c	Thu Apr 17 15:01:39 2003
+++ b/drivers/scsi/gdth_proc.c	Mon May 12 08:08:27 2003
@@ -6,31 +6,24 @@
 #include <linux/completion.h>
 #endif
 
-int gdth_proc_info(char *buffer,char **start,off_t offset,int length,   
-                   int hostno,int inout)
+int gdth_proc_info(struct Scsi_Host *host, char *buffer,char **start,off_t offset,int length,   
+                   int inout)
 {
-    int hanum,busnum,i;
+    int hanum,busnum;
 
     TRACE2(("gdth_proc_info() length %d ha %d offs %d inout %d\n",
             length,hostno,(int)offset,inout));
 
-    for (i=0; i<gdth_ctr_vcount; ++i) {
-        if (gdth_ctr_vtab[i]->host_no == hostno)
-            break;
-    }
-    if (i==gdth_ctr_vcount)
-        return(-EINVAL);
-
-    hanum = NUMDATA(gdth_ctr_vtab[i])->hanum;
-    busnum= NUMDATA(gdth_ctr_vtab[i])->busnum;
+    hanum = NUMDATA(host)->hanum;
+    busnum= NUMDATA(host)->busnum;
 
     if (inout)
-        return(gdth_set_info(buffer,length,i,hanum,busnum));
+        return(gdth_set_info(buffer,length,hanum,busnum));
     else
-        return(gdth_get_info(buffer,start,offset,length,i,hanum,busnum));
+        return(gdth_get_info(buffer,start,offset,length,hanum,busnum));
 }
 
-static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
+static int gdth_set_info(char *buffer,int length,int hanum,int busnum)
 {
     int             ret_val = -EINVAL;
 #if LINUX_VERSION_CODE >= 0x020503
@@ -763,7 +756,7 @@
 #endif
 
 static int gdth_get_info(char *buffer,char **start,off_t offset,
-                         int length,int vh,int hanum,int busnum)
+                         int length,int hanum,int busnum)
 {
     int size = 0,len = 0;
     off_t begin = 0,pos = 0;
diff -Nru a/drivers/scsi/gdth_proc.h b/drivers/scsi/gdth_proc.h
--- a/drivers/scsi/gdth_proc.h	Thu Mar  6 15:10:14 2003
+++ b/drivers/scsi/gdth_proc.h	Mon May 12 08:13:36 2003
@@ -5,9 +5,9 @@
  * $Id: gdth_proc.h,v 1.13 2003/02/27 14:59:25 achim Exp $
  */
 
-static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum);
+static int gdth_set_info(char *buffer,int length,int hanum,int busnum);
 static int gdth_get_info(char *buffer,char **start,off_t offset,
-                         int length,int vh,int hanum,int busnum);
+                         int length,int hanum,int busnum);
 
 #if LINUX_VERSION_CODE >= 0x020503
 static void gdth_do_req(Scsi_Request *srp, gdth_cmd_str *cmd, 
diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
--- a/drivers/scsi/hosts.c	Sun Apr 20 05:51:54 2003
+++ b/drivers/scsi/hosts.c	Mon May 26 18:54:35 2003
@@ -216,6 +216,10 @@
 	scsi_proc_host_rm(shost);
 	scsi_forget_host(shost);
 	scsi_sysfs_remove_host(shost);
+
+	if (shost->hostt->release)
+		(*shost->hostt->release)(shost);
+
 	return 0;
 }
 
@@ -318,7 +322,12 @@
            shost_tp->eh_host_reset_handler == NULL) {
 		printk(KERN_ERR "ERROR: SCSI host `%s' has no error handling\nERROR: This is not a safe way to run your SCSI host\nERROR: The error handling must be added to this driver\n", shost_tp->proc_name);
 		dump_stack();
-        } 
+        }
+	if(shost_tp->shost_attrs == NULL)
+		/* if its not set in the template, use the default */
+		 shost_tp->shost_attrs = scsi_sysfs_shost_attrs;
+	if(shost_tp->sdev_attrs == NULL)
+		 shost_tp->sdev_attrs = scsi_sysfs_sdev_attrs;
 	gfp_mask = GFP_KERNEL;
 	if (shost_tp->unchecked_isa_dma && xtr_bytes)
 		gfp_mask |= __GFP_DMA;
diff -Nru a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
--- a/drivers/scsi/hosts.h	Thu May  8 11:24:14 2003
+++ b/drivers/scsi/hosts.h	Mon May 26 14:47:09 2003
@@ -68,7 +68,7 @@
      * outside the kernel ie. userspace and it also provides an interface
      * to feed the driver with information. Check eata_dma_proc.c for reference
      */
-    int (*proc_info)(char *, char **, off_t, int, int, int);
+    int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int);
 
     /*
      * The name pointer is a pointer to the name of the SCSI
@@ -356,6 +356,16 @@
      * FIXME: This should probably be a value in the template */
     #define SCSI_DEFAULT_HOST_BLOCKED	7
 
+    /*
+     * pointer to the sysfs class properties for this host
+     */
+    struct class_device_attribute **shost_attrs;
+
+    /*
+     * Pointer to the SCSI device properties for this host
+     */
+    struct device_attribute **sdev_attrs;
+
 } Scsi_Host_Template;
 
 /*
@@ -570,9 +580,6 @@
 extern int scsi_register_host(Scsi_Host_Template *);
 extern int scsi_unregister_host(Scsi_Host_Template *);
 
-extern struct Scsi_Host *scsi_host_hn_get(unsigned short);
-extern void scsi_host_put(struct Scsi_Host *);
-
 /**
  * scsi_find_device - find a device given the host
  * @shost:	SCSI host pointer
@@ -590,5 +597,7 @@
                         return sdev;
         return NULL;
 }
+
+extern void scsi_sysfs_release_attributes(struct SHT *hostt);
 
 #endif
diff -Nru a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
--- a/drivers/scsi/ibmmca.c	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/ibmmca.c	Mon May 12 07:26:12 2003
@@ -2384,7 +2384,7 @@
 }
 
 /* routine to display info in the proc-fs-structure (a deluxe feature) */
-static int ibmmca_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+static int ibmmca_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout)
 {
 	int len = 0;
 	int i, id, lun, host_index;
@@ -2392,13 +2392,13 @@
 	unsigned long flags;
 	int max_pun;
 
-	for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++);
+	for (i = 0; hosts[i] && hosts[i] != shpnt; i++);
 	
 	spin_lock_irqsave(hosts[i]->host_lock, flags);	/* Check it */
-	shpnt = hosts[i];
 	host_index = i;
 	if (!shpnt) {
-		len += sprintf(buffer + len, "\nIBM MCA SCSI: Can't find adapter for host number %d\n", hostno);
+		len += sprintf(buffer + len, "\nIBM MCA SCSI: Can't find adapter for host number %d\n",
+				shpnt->host_no);
 		return len;
 	}
 	max_pun = subsystem_maxid(host_index);
@@ -2411,7 +2411,7 @@
 #else
 	len += sprintf(buffer + len, "               Multiple LUN probing.....: No\n");
 #endif
-	len += sprintf(buffer + len, "               This Hostnumber..........: %d\n", hostno);
+	len += sprintf(buffer + len, "               This Hostnumber..........: %d\n", shpnt->host_no);
 	len += sprintf(buffer + len, "               Base I/O-Port............: 0x%x\n", (unsigned int) (IM_CMD_REG(host_index)));
 	len += sprintf(buffer + len, "               (Shared) IRQ.............: %d\n", IM_IRQ);
 	len += sprintf(buffer + len, "               Total Interrupts.........: %d\n", IBM_DS(host_index).total_interrupts);
diff -Nru a/drivers/scsi/ibmmca.h b/drivers/scsi/ibmmca.h
--- a/drivers/scsi/ibmmca.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/ibmmca.h	Mon May 12 07:26:12 2003
@@ -11,7 +11,6 @@
 /* Common forward declarations for all Linux-versions: */
 
 /* Interfaces to the midlevel Linux SCSI driver */
-static int ibmmca_proc_info (char *, char **, off_t, int, int, int);
 static int ibmmca_detect (Scsi_Host_Template *);
 static int ibmmca_release (struct Scsi_Host *);
 static int ibmmca_command (Scsi_Cmnd *);
diff -Nru a/drivers/scsi/imm.c b/drivers/scsi/imm.c
--- a/drivers/scsi/imm.c	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/imm.c	Mon May 12 07:26:12 2003
@@ -253,14 +253,14 @@
     return (-EINVAL);
 }
 
-int imm_proc_info(char *buffer, char **start, off_t offset,
+int imm_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
 		  int length, int hostno, int inout)
 {
     int i;
     int len = 0;
 
     for (i = 0; i < 4; i++)
-	if (imm_hosts[i].host == hostno)
+	if (imm_hosts[i].host == host->host_no)
 	    break;
 
     if (inout)
diff -Nru a/drivers/scsi/imm.h b/drivers/scsi/imm.h
--- a/drivers/scsi/imm.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/imm.h	Mon May 12 07:26:13 2003
@@ -159,7 +159,6 @@
 int imm_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 int imm_abort(Scsi_Cmnd *);
 int imm_reset(Scsi_Cmnd *);
-int imm_proc_info(char *, char **, off_t, int, int, int);
 int imm_biosparam(struct scsi_device *, struct block_device *,
 		sector_t, int *);
 
diff -Nru a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
--- a/drivers/scsi/in2000.c	Sun May 25 17:00:00 2003
+++ b/drivers/scsi/in2000.c	Mon May 26 18:54:36 2003
@@ -2154,7 +2154,7 @@
 }
 
 
-static int in2000_proc_info(char *buf, char **start, off_t off, int len, int hn, int in)
+static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off, int len, int in)
 {
 
 #ifdef PROC_INTERFACE
@@ -2162,17 +2162,11 @@
 	char *bp;
 	char tbuf[128];
 	unsigned long flags;
-	struct Scsi_Host *instance;
 	struct IN2000_hostdata *hd;
 	Scsi_Cmnd *cmd;
 	int x, i;
 	static int stop = 0;
 
-	instance = scsi_host_hn_get(hn);
-	if (!instance) {
-		printk("*** Hmm... Can't find host #%d!\n", hn);
-		return (-ESRCH);
-	}
 	hd = (struct IN2000_hostdata *) instance->hostdata;
 
 /* If 'in' is TRUE we need to _read_ the proc file. We accept the following
diff -Nru a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h
--- a/drivers/scsi/in2000.h	Sun May  4 02:56:43 2003
+++ b/drivers/scsi/in2000.h	Mon May 12 07:26:13 2003
@@ -401,7 +401,6 @@
 static int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 static int in2000_abort(Scsi_Cmnd *);
 static void in2000_setup(char *, int *) in2000__INIT;
-static int in2000_proc_info(char *, char **, off_t, int, int, int);
 static int in2000_biosparam(struct scsi_device *, struct block_device *,
 		sector_t, int *);
 static int in2000_host_reset(Scsi_Cmnd *);
diff -Nru a/drivers/scsi/ips.c b/drivers/scsi/ips.c
--- a/drivers/scsi/ips.c	Tue May  6 10:19:58 2003
+++ b/drivers/scsi/ips.c	Mon May 12 07:26:13 2003
@@ -488,7 +488,7 @@
 static void ips_scmd_buf_write(Scsi_Cmnd *scmd, void *data, unsigned int count);
 static void ips_scmd_buf_read(Scsi_Cmnd *scmd, void *data, unsigned int count);
 
-int  ips_proc_info(char *, char **, off_t, int, int, int);
+int  ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
 static int ips_host_info(ips_ha_t *, char *, off_t, int);
 static void copy_mem_info(IPS_INFOSTR *, char *, int);
 static int copy_info(IPS_INFOSTR *, char *, ...);
@@ -1496,8 +1496,8 @@
 /*                                                                          */
 /****************************************************************************/
 int
-ips_proc_info(char *buffer, char **start, off_t offset,
-              int length, int hostno, int func) {
+ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+              int length, int func) {
    int           i;
    int           ret;
    ips_ha_t     *ha = NULL;
@@ -1507,7 +1507,7 @@
    /* Find our host structure */
    for (i = 0; i < ips_next_controller; i++) {
       if (ips_sh[i]) {
-         if (ips_sh[i]->host_no == hostno) {
+         if (ips_sh[i] == host) {
             ha = (ips_ha_t *) ips_sh[i]->hostdata;
             break;
          }
diff -Nru a/drivers/scsi/mac_NCR5380.c b/drivers/scsi/mac_NCR5380.c
--- a/drivers/scsi/mac_NCR5380.c	Fri May  9 03:21:35 2003
+++ b/drivers/scsi/mac_NCR5380.c	Mon May 26 18:54:37 2003
@@ -740,7 +740,7 @@
 	printk("NCR5380_print_status: no memory for print buffer\n");
 	return;
     }
-    len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0);
+    len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0);
     pr_bfr[len] = 0;
     printk("\n%s\n", pr_bfr);
     free_page((unsigned long) pr_bfr);
@@ -771,11 +771,10 @@
 #ifndef NCR5380_proc_info
 static
 #endif
-int NCR5380_proc_info (char *buffer, char **start, off_t offset,
-		       int length, int hostno, int inout)
+int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, off_t offset,
+		       int length, int inout)
 {
     char *pos = buffer;
-    struct Scsi_Host *instance;
     struct NCR5380_hostdata *hostdata;
     Scsi_Cmnd *ptr;
     unsigned long flags;
@@ -787,13 +786,6 @@
 	    pos = buffer;			\
 	}					\
     } while (0)
-
-    for (instance = first_instance; instance && HOSTNO != hostno;
-	 instance = instance->next)
-	;
-    if (!instance)
-	return(-ESRCH);
-    hostdata = (struct NCR5380_hostdata *)instance->hostdata;
 
     if (inout) { /* Has data been written to the file ? */
 	return(-ENOSYS);  /* Currently this is a no-op */
diff -Nru a/drivers/scsi/mac_scsi.h b/drivers/scsi/mac_scsi.h
--- a/drivers/scsi/mac_scsi.h	Fri Dec 20 06:37:31 2002
+++ b/drivers/scsi/mac_scsi.h	Mon May 12 07:26:13 2003
@@ -32,9 +32,6 @@
 #define MACSCSI_PUBLIC_RELEASE 2
 
 #ifndef ASM
-int macscsi_proc_info (char *buffer, char **start, off_t offset,
-			int length, int hostno, int inout);
-
 #ifndef NULL
 #define NULL 0
 #endif
diff -Nru a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
--- a/drivers/scsi/megaraid.c	Sat May 17 14:09:51 2003
+++ b/drivers/scsi/megaraid.c	Mon May 19 19:40:43 2003
@@ -2392,21 +2392,6 @@
 		enquiry3->pdrv_state[i] = inquiry->pdrv_info.pdrv_state[i];
 }
 
-
-/*
- * megaraid_proc_info()
- *
- * Returns data to be displayed in /proc/scsi/megaraid/X
- */
-static int
-megaraid_proc_info(char *buffer, char **start, off_t offset, int length,
-		int host_no, int inout)
-{
-	*start = buffer;
-	return 0;
-}
-
-
 /*
  * Release the controller's resources
  */
@@ -5379,7 +5364,6 @@
 
 static Scsi_Host_Template driver_template = {
 	.name =				"MegaRAID",
-	.proc_info =			megaraid_proc_info,
 	.detect =			megaraid_detect,
 	.release =			megaraid_release,
 	.info =				megaraid_info,
diff -Nru a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
--- a/drivers/scsi/megaraid.h	Sun May  4 02:56:44 2003
+++ b/drivers/scsi/megaraid.h	Mon May 12 07:26:13 2003
@@ -1007,7 +1007,6 @@
 static int megaraid_abort_and_reset(adapter_t *, Scsi_Cmnd *, int);
 static int megaraid_biosparam(struct scsi_device *, struct block_device *,
 		sector_t, int []);
-static int megaraid_proc_info (char *, char **, off_t, int, int, int);
 static int mega_print_inquiry(char *, char *);
 
 static int mega_build_sglist (adapter_t *adapter, scb_t *scb,
diff -Nru a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
--- a/drivers/scsi/ncr53c8xx.c	Sun May 25 17:00:00 2003
+++ b/drivers/scsi/ncr53c8xx.c	Mon May 26 18:54:38 2003
@@ -399,8 +399,8 @@
 
 static irqreturn_t ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
 static void ncr53c8xx_timeout(unsigned long np);
-static int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset,
-			int length, int hostno, int func);
+static int ncr53c8xx_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+			int length, int func);
 
 #define initverbose (driver_setup.verbose)
 #define bootverbose (np->verbose)
@@ -9249,21 +9249,17 @@
 **	- func = 1 means write (parse user control command)
 */
 
-static int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset,
-			int length, int hostno, int func)
+static int ncr53c8xx_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+			int length, int func)
 {
-	struct Scsi_Host *host;
 	struct host_data *host_data;
 	ncb_p ncb = 0;
 	int retv;
 
 #ifdef DEBUG_PROC_INFO
-printk("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func);
+printk("ncr53c8xx_proc_info: hostno=%d, func=%d\n", host->host_no, func);
 #endif
 
-	if((host = scsi_host_hn_get(hostno))==NULL)
-		return -EINVAL;
-		
 	host_data = (struct host_data *) host->hostdata;
 	ncb = host_data->ncb;
 
diff -Nru a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
--- a/drivers/scsi/nsp32.c	Thu May  8 11:24:14 2003
+++ b/drivers/scsi/nsp32.c	Mon May 12 07:26:14 2003
@@ -286,7 +286,7 @@
 static int nsp32_eh_host_reset(Scsi_Cmnd *);
 static int nsp32_reset(Scsi_Cmnd *, unsigned int);
 static int nsp32_release(struct Scsi_Host *);
-static int nsp32_proc_info(char *, char **, off_t, int, int, int);
+static int nsp32_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
 static int __devinit nsp32_probe(struct pci_dev *, const struct pci_device_id *);
 static void __devexit nsp32_remove(struct pci_dev *);
 static int __init init_nsp32(void);
@@ -1555,18 +1555,16 @@
 #undef SPRINTF
 #define SPRINTF(args...) \
         do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
-static int nsp32_proc_info(char  *buffer,
+static int nsp32_proc_info(struct Scsi_Host *host, char  *buffer,
 			   char **start,
 			   off_t  offset,
 			   int    length,
-			   int    hostno,
 			   int    inout)
 {
 	char *pos = buffer;
 	int thislength;
 	unsigned long flags;
 	nsp32_hw_data *data;
-	struct Scsi_Host *host = NULL;
 	unsigned int base;
 	unsigned char mode_reg;
 
@@ -1575,19 +1573,12 @@
 		return -EINVAL;
 	}
 
-	/* search this HBA host */
-	
-	host = scsi_host_hn_get(hostno);
-	
-	if (host == NULL) {
-		return -ESRCH;
-	}
 	data = (nsp32_hw_data *)host->hostdata;
 	base = host->io_port;
 
 	SPRINTF("NinjaSCSI-32 status\n\n");
 	SPRINTF("Driver version:        %s\n",		nsp32_release_version);
-	SPRINTF("SCSI host No.:         %d\n",		hostno);
+	SPRINTF("SCSI host No.:         %d\n",		host->host_no);
 	SPRINTF("IRQ:                   %d\n",		host->irq);
 	SPRINTF("IO:                    0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
 	SPRINTF("MMIO(virtual address): 0x%lx\n",	host->base);
diff -Nru a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
--- a/drivers/scsi/pas16.h	Sun May  4 02:56:44 2003
+++ b/drivers/scsi/pas16.h	Mon May 12 07:26:14 2003
@@ -122,8 +122,6 @@
 static int pas16_bus_reset(Scsi_Cmnd *);
 static int pas16_host_reset(Scsi_Cmnd *);
 static int pas16_device_reset(Scsi_Cmnd *);
-static int pas16_proc_info (char *buffer ,char **start, off_t offset,
-		     int length, int hostno, int inout);
 
 #ifndef NULL
 #define NULL 0
diff -Nru a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
--- a/drivers/scsi/pcmcia/nsp_cs.c	Thu May  1 09:44:53 2003
+++ b/drivers/scsi/pcmcia/nsp_cs.c	Mon May 12 08:14:55 2003
@@ -1291,11 +1291,10 @@
 #undef SPRINTF
 #define SPRINTF(args...) \
         do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
-static int nsp_proc_info(char  *buffer,
+static int nsp_proc_info(struct Scsi_Host *host, char  *buffer,
 			 char **start,
 			 off_t  offset,
 			 int    length,
-			 int    hostno,
 			 int    inout)
 {
 	int id;
@@ -1304,29 +1303,14 @@
 	int speed;
 	unsigned long flags;
 	nsp_hw_data *data = &nsp_data;
-	struct Scsi_Host *host = NULL;
 
 	if (inout) {
 		return -EINVAL;
 	}
 
-	/* search this HBA host */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45))
-	host = scsi_host_hn_get(hostno);
-#else
-	for (host=scsi_hostlist; host; host=host->next) {
-                if (host->host_no == hostno) {
-                        break;
-                }
-        }
-#endif
-	if (host == NULL) {
-		return -ESRCH;
-	}
-
 	SPRINTF("NinjaSCSI status\n\n");
 	SPRINTF("Driver version:        $Revision: 1.5 $\n");
-	SPRINTF("SCSI host No.:         %d\n",          hostno);
+	SPRINTF("SCSI host No.:         %d\n",          host->host_no);
 	SPRINTF("IRQ:                   %d\n",          host->irq);
 	SPRINTF("IO:                    0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
 	SPRINTF("MMIO(virtual address): 0x%lx\n",       host->base);
diff -Nru a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h
--- a/drivers/scsi/pcmcia/nsp_cs.h	Sun Mar  2 23:32:33 2003
+++ b/drivers/scsi/pcmcia/nsp_cs.h	Mon May 12 07:26:17 2003
@@ -281,8 +281,8 @@
 static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time);
 
 static const char *nsp_info(struct Scsi_Host *shpnt);
-static int nsp_proc_info(char *buffer, char **start, off_t offset,
-			 int length, int hostno, int inout);
+static int nsp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+			 int length, int inout);
 static int nsp_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
 
 /*static int nsp_eh_abort(Scsi_Cmnd * SCpnt);*/
diff -Nru a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
--- a/drivers/scsi/ppa.c	Sun May  4 02:56:44 2003
+++ b/drivers/scsi/ppa.c	Mon May 12 07:26:14 2003
@@ -270,14 +270,14 @@
     return (-EINVAL);
 }
 
-int ppa_proc_info(char *buffer, char **start, off_t offset,
-		  int length, int hostno, int inout)
+int ppa_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+		  int length, int inout)
 {
     int i;
     int len = 0;
 
     for (i = 0; i < 4; i++)
-	if (ppa_hosts[i].host == hostno)
+	if (ppa_hosts[i] == host)
 	    break;
 
     if (inout)
diff -Nru a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h
--- a/drivers/scsi/ppa.h	Sun May  4 02:56:44 2003
+++ b/drivers/scsi/ppa.h	Mon May 12 07:26:14 2003
@@ -167,7 +167,7 @@
 int ppa_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 int ppa_abort(Scsi_Cmnd *);
 int ppa_reset(Scsi_Cmnd *);
-int ppa_proc_info(char *, char **, off_t, int, int, int);
+int ppa_proc_info(struct Scsi_Host *host, char *, char **, off_t, int, int);
 int ppa_biosparam(struct scsi_device *, struct block_device *,
 		sector_t, int *);
 
diff -Nru a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
--- a/drivers/scsi/qla1280.c	Sun May  4 02:56:45 2003
+++ b/drivers/scsi/qla1280.c	Mon May 26 16:33:44 2003
@@ -332,6 +332,23 @@
 #define pci_dma_lo32(a)		(a & 0xffffffff)
 #define pci_dma_hi32(a)		0
 #endif
+/* MACROS for managing the endian addresses */
+static inline uint16_t qla1280_addr0_15(dma_addr_t dma)
+{
+	return ((uint16_t)(dma & 0xffff));
+}
+static inline uint16_t qla1280_addr16_31(dma_addr_t dma)
+{
+	return ((uint16_t)((dma >> 16) & 0xffff));
+}
+static inline uint16_t qla1280_addr32_47(dma_addr_t dma)
+{
+	return ((uint16_t)(pci_dma_hi32(dma) & 0xffff));
+}
+static inline uint16_t qla1280_addr48_63(dma_addr_t dma)
+{
+	return ((uint16_t)((pci_dma_hi32(dma) >> 16) & 0xffff));
+}
 
 #define NVRAM_DELAY()		udelay(500)	/* 2 microsecond delay */
 
@@ -442,6 +459,35 @@
 static void qla12160_get_target_parameters(struct scsi_qla_host *,
 					   uint32_t, uint32_t, uint32_t);
 
+/* convert scsi data direction to request_t control flags
+ */
+static inline uint16_t
+qla1280_data_direction(struct scsi_cmnd *cmnd)
+{
+	uint16_t flags = 0;
+
+	switch(cmnd->sc_data_direction) {
+
+	case SCSI_DATA_NONE:
+		flags = 0;
+		break;
+
+	case SCSI_DATA_READ:
+		flags = BIT_5;
+		break;
+
+	case SCSI_DATA_WRITE:
+		flags = BIT_6;
+		break;
+
+	case SCSI_DATA_UNKNOWN:
+	default:
+		flags = BIT_5 | BIT_6;
+		break;
+	}
+	return flags;
+}
+		
 #if QL1280_LUN_SUPPORT
 static void qla1280_enable_lun(struct scsi_qla_host *, int, int);
 #endif
@@ -623,11 +669,10 @@
 #define	PROC_BUF	&qla1280_buffer[len]
 
 int
-qla1280_proc_info(char *buffer, char **start, off_t offset, int length,
-		  int hostno, int inout)
+qla1280_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length,
+		  int inout)
 {
 #if QLA1280_PROFILE
-	struct Scsi_Host *host;
 	struct scsi_qla_host *ha;
 	int size = 0;
 	scsi_lu_t *up;
@@ -637,22 +682,9 @@
 	host = NULL;
 
 	/* Find the host that was specified */
-	for (ha = qla1280_hostlist; (ha != NULL) && ha->host->host_no != hostno;
+	for (ha = qla1280_hostlist; (ha != NULL) && ha->host != host;
 	     ha = ha->next) ;
 
-	/* if host wasn't found then exit */
-	if (!ha) {
-		size =  sprintf(buffer, "Can't find adapter for host "
-				"number %d\n", hostno);
-		if (size > length) {
-			return size;
-		} else {
-			return 0;
-		}
-	}
-
-	host = ha->host;
-
 	if (inout == TRUE) {	/* Has data been written to the file? */
 		printk(KERN_INFO
 		       "qla1280_proc: has data been written to the file.\n");
@@ -1226,280 +1258,36 @@
 	return 0;
 }
 
-/**************************************************************************
- *   qla1200_abort
- *     Abort the speciifed SCSI command(s).
- **************************************************************************/
-int
-qla1280_abort(Scsi_Cmnd * cmd)
-{
-	struct scsi_qla_host *ha;
-	srb_t *sp;
-	struct Scsi_Host *host;
-	unsigned int bus, target, lun;
-	scsi_lu_t *q;
-	int return_status = SCSI_ABORT_SUCCESS;
-	int found = 0;
-	int i;
-	unsigned char *handle;
-	u16 data;
-
-	ENTER("qla1280_abort");
-	ha = (struct scsi_qla_host *)cmd->device->host->hostdata;
-	host = cmd->device->host;
-
-	/* Get the SCSI request ptr */
-	sp = (srb_t *)CMD_SP(cmd);
-	handle = CMD_HANDLE(cmd);
-	if (qla1280_verbose)
-		printk(KERN_ERR "scsi(%li): ABORT Command=0x%p, handle=0x%p\n",
-		       ha->host_no, (void *) cmd, (void *) handle);
-
-	/* Check for pending interrupts. */
-	if (handle == NULL) {
-		/* we never got this command */
-		printk(KERN_INFO "qla1280: Aborting a NULL handle\n");
-		return SCSI_ABORT_NOT_RUNNING;	/* no action - we don't have command */
-	}
-	data = qla1280_debounce_register(&ha->iobase->istatus);
-	/*
-	 * The io_request_lock is held when the reset handler is called, hence
-	 * the interrupt handler cannot be running in parallel as it also
-	 * grabs the lock. No reason to play funny games with set_bit() in
-	 * order to test for interrupt handler entry as the driver used to
-	 * do here.
-	 * /Jes
-	 */
-	if (data & RISC_INT) {
-		/* put any pending command in done queue */
-		qla1280_isr(ha, &ha->done_q_first, &ha->done_q_last);
-	}
+typedef enum {
+	ABORT_COMMAND,
+	ABORT_DEVICE,
+	DEVICE_RESET,
+	BUS_RESET,
+	ADAPTER_RESET,
+	FAIL
+} action_t;
 
-	/*
-	 * This seems unnecessary, it's not used below! / Jes
-	 */
-#ifdef UNUSED
-	handle = CMD_HANDLE(cmd);
-#endif
-
-	/* Generate LU queue on bus, target, LUN */
-	bus = SCSI_BUS_32(cmd);
-	target = SCSI_TCN_32(cmd);
-	lun = SCSI_LUN_32(cmd);
-	if ((q = LU_Q(ha, bus, target, lun)) == NULL) {
-		/* No lun queue -- command must not be active */
-		printk(KERN_WARNING "qla1280 (%d:%d:%d): No LUN queue for the "
-		       "specified device\n", bus, target, lun);
-		return SCSI_ABORT_NOT_RUNNING;	/* no action - we don't have command */
-	}
-#if AUTO_ESCALATE_ABORT
-	if ((sp->flags & SRB_ABORTED)) {
-		dprintk(1, "qla1280_abort: Abort escalayted - returning "
-			"SCSI_ABORT_SNOOZE.\n");
-		return SCSI_ABORT_SNOOZE;
-	}
-#endif
-
-	if ((sp->flags & SRB_ABORT_PENDING)) {
-		if (qla1280_verbose)
-			printk(KERN_WARNING
-			       "scsi(): Command has a pending abort "
-			       "message - ABORT_PENDING.\n");
-
-		return SCSI_ABORT_PENDING;
-	}
-#if STOP_ON_ABORT
-	printk(KERN_WARNING "Scsi layer issued a ABORT command= 0x%p\n", cmd);
-	qla1280_print_scsi_cmd(2, cmd);
-#endif
-
-	/*
-	 * Normally, would would need to search our queue for the specified command
-	 * but; since our sp contains the cmd ptr, we can just remove it from our
-	 * LUN queue.
-	 */
-	if (!(sp->flags & SRB_SENT)) {
-		found++;
-		if (qla1280_verbose)
-			printk(KERN_WARNING
-			       "scsi(): Command returned from queue "
-			       "aborted.\n");
-
-		/* Remove srb from SCSI LU queue. */
-		qla1280_removeq(q, sp);
-		sp->flags |= SRB_ABORTED;
-		CMD_RESULT(cmd) = DID_ABORT << 16;
-		qla1280_done_q_put(sp, &ha->done_q_first, &ha->done_q_last);
-		return_status = SCSI_ABORT_SUCCESS;
-	} else {		/* find the command in our active list */
-		for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
-			if (sp == ha->outstanding_cmds[i]) {
-				found++;
-				dprintk(1,
-					"qla1280: RISC aborting command.\n");
-				qla1280_abort_command(ha, sp);
-				return_status = SCSI_ABORT_PENDING;
-				break;
-			}
-		}
-	}
-
-#if STOP_ON_ABORT
-	qla1280_panic("qla1280_abort", ha->host);
-#endif
-	if (found == 0)
-		return_status = SCSI_ABORT_NOT_RUNNING;	/* no action - we don't have command */
-
-	dprintk(1, "qla1280_abort: Aborted status returned = 0x%x.\n",
-		return_status);
-
-	if (ha->done_q_first)
-		qla1280_done(ha, &ha->done_q_first, &ha->done_q_last);
-	if (found)
-		qla1280_restart_queues(ha);
-
-	LEAVE("qla1280_abort");
-	return return_status;
-}
-
-int
-qla1280_new_abort(Scsi_Cmnd * cmd)
+/* timer action for error action processor */
+static void qla1280_error_wait_timeout(unsigned long __data)
 {
-	struct scsi_qla_host *ha;
-	srb_t *sp;
-	struct Scsi_Host *host;
-	int bus, target, lun;
-	scsi_lu_t *q;
-	unsigned long cpu_flags;
-	int return_status = SCSI_ABORT_SUCCESS;
-	int found = 0;
-	int i;
-	unsigned char *handle;
-	u16 data;
-
-	ENTER("qla1280_abort");
-	host = cmd->device->host;
-	ha = (struct scsi_qla_host *)host->hostdata;
-
-	/* Get the SCSI request ptr */
-	sp = (srb_t *) CMD_SP(cmd);
-	handle = CMD_HANDLE(cmd);
-	if (qla1280_verbose)
-		printk(KERN_ERR "scsi(%li): ABORT Command=0x%p, handle=0x%p\n",
-		       ha->host_no, cmd, handle);
-
-	/* Check for pending interrupts. */
-	if (handle == NULL) {
-		/* we never got this command */
-		printk(KERN_INFO "qla1280: Aborting a NULL handle\n");
-		return SUCCESS;	/* no action - we don't have command */
-	}
+	struct scsi_cmnd *cmd = (struct scsi_cmnd *)__data;
+	srb_t *sp = (srb_t *)CMD_SP(cmd);
 
-	spin_lock_irqsave (ha->host->host_lock, cpu_flags);
-	data = qla1280_debounce_register(&ha->iobase->istatus);
-	/*
-	 * We grab the host lock in the interrupt handler to
-	 * prevent racing here.
-	 *
-	 * Then again, running the interrupt handler from here is somewhat
-	 * questionable.
-	 * /Jes
-	 */
-	if (data & RISC_INT) {
-		/* put any pending command in done queue */
-		qla1280_isr(ha, &ha->done_q_first, &ha->done_q_last);
-	}
-
-	/* Generate LU queue on bus, target, LUN */
-	bus = SCSI_BUS_32(cmd);
-	target = SCSI_TCN_32(cmd);
-	lun = SCSI_LUN_32(cmd);
-	if ((q = LU_Q(ha, bus, target, lun)) == NULL) {
-		/* No lun queue -- command must not be active */
-		printk(KERN_WARNING "qla1280 (%d:%d:%d): No LUN queue for the "
-		       "specified device\n", bus, target, lun);
-		return_status = SUCCESS;	/* no action - we don't have command */
-		goto out;
-	}
-
-	if ((sp->flags & SRB_ABORT_PENDING)) {
-		if (qla1280_verbose)
-			printk(KERN_WARNING
-			       "scsi(): Command has a pending abort "
-			       "message - ABORT_PENDING.\n");
-
-		return_status = SCSI_ABORT_PENDING;
-		goto out;
-	}
-#if STOP_ON_ABORT
-	printk(KERN_WARNING "Scsi layer issued a ABORT command= 0x%p\n", cmd);
-	qla1280_print_scsi_cmd(2, cmd);
-#endif
-
-	/*
-	 * Normally, would would need to search our queue for the specified command
-	 * but; since our sp contains the cmd ptr, we can just remove it from our
-	 * LUN queue.
-	 */
-	if (!(sp->flags & SRB_SENT)) {
-		found++;
-		if (qla1280_verbose)
-			printk(KERN_WARNING
-			       "scsi(): Command returned from queue "
-			       "aborted.\n");
-
-		/* Remove srb from SCSI LU queue. */
-		qla1280_removeq(q, sp);
-		sp->flags |= SRB_ABORTED;
-		CMD_RESULT(cmd) = DID_ABORT << 16;
-		qla1280_done_q_put(sp, &ha->done_q_first, &ha->done_q_last);
-		return_status = SUCCESS;
-	} else {		/* find the command in our active list */
-		for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
-			if (sp == ha->outstanding_cmds[i]) {
-				found++;
-				dprintk(1,
-					"qla1280: RISC aborting command.\n");
-				qla1280_abort_command(ha, sp);
-				return_status = SCSI_ABORT_PENDING;
-				break;
-			}
-		}
-	}
-
-#if STOP_ON_ABORT
-	qla1280_panic("qla1280_abort", ha->host);
-#endif
-	if (found == 0)
-		return_status = SUCCESS;	/* no action - we don't have the command */
-
-	dprintk(1, "qla1280_abort: Aborted status returned = 0x%x.\n",
-		return_status);
-
-	if (ha->done_q_first)
-		qla1280_done(ha, &ha->done_q_first, &ha->done_q_last);
-	if (found)
-		qla1280_restart_queues(ha);
-
- out:
-	spin_unlock_irqrestore(ha->host->host_lock, cpu_flags);
-
-	LEAVE("qla1280_abort");
-	return return_status;
+	complete(sp->wait);
 }
 
 /**************************************************************************
- * qla1200_reset
- *    The reset function will reset the SCSI bus and abort any executing
- *    commands.
+ * qla1200_error_action
+ *    The function will attempt to perform a specified error action and
+ *    wait for the results (or time out).
  *
  * Input:
  *      cmd = Linux SCSI command packet of the command that cause the
  *            bus reset.
- *      flags = SCSI bus reset option flags (see scsi.h)
+ *      action = error action to take (see action_t)
  *
  * Returns:
- *      DID_RESET in cmd.host_byte of aborted command(s)
+ *      SUCCESS or FAIL
  *
  * Note:
  *      Resetting the bus always succeeds - is has to, otherwise the
@@ -1508,36 +1296,34 @@
  *      the SCSI bus reset line.
  **************************************************************************/
 int
-qla1280_reset(Scsi_Cmnd * cmd, unsigned int flags)
+qla1280_error_action(Scsi_Cmnd * cmd, action_t action)
 {
 	struct scsi_qla_host *ha;
 	int bus, target, lun;
 	srb_t *sp;
-	typedef enum {
-		ABORT_DEVICE = 1,
-		DEVICE_RESET = 2,
-		BUS_RESET = 3,
-		ADAPTER_RESET = 4,
-		RESET_DELAYED = 5,
-		FAIL = 6
-	} action_t;
-	action_t action = ADAPTER_RESET;
-	u16 data;
+	uint16_t data;
+	unsigned char *handle;
 	scsi_lu_t *q;
 	int result;
+	DECLARE_COMPLETION(wait);
+	struct timer_list timer;
 
-	ENTER("qla1280_reset");
+	ENTER("qla1280_error_action");
 	if (qla1280_verbose)
 		printk(KERN_INFO "scsi(): Resetting Cmnd=0x%p, Handle=0x%p, "
-		       "flags=0x%x\n", cmd, CMD_HANDLE(cmd), flags);
+		       "action=0x%x\n", cmd, CMD_HANDLE(cmd), action);
+
 	if (cmd == NULL) {
 		printk(KERN_WARNING
 		       "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd "
 		       "pointer, failing.\n");
-		return SCSI_RESET_SNOOZE;
+		LEAVE("qla1280_error_action");
+		return FAIL;
 	}
+
 	ha = (struct scsi_qla_host *)cmd->device->host->hostdata;
 	sp = (srb_t *)CMD_SP(cmd);
+	handle = CMD_HANDLE(cmd);
 
 #if STOP_ON_RESET
 	qla1280_panic("qla1280_reset", ha->host);
@@ -1557,27 +1343,14 @@
 	 * Determine the suggested action that the mid-level driver wants
 	 * us to perform.
 	 */
-	if (CMD_HANDLE(cmd) == NULL) {
-		/*
-		 * if mid-level driver called reset with a orphan SCSI_Cmnd
-		 * (i.e. a command that's not pending), so perform the
-		 * function specified.
-		 */
-		if (flags & SCSI_RESET_SUGGEST_HOST_RESET)
-			action = ADAPTER_RESET;
-		else
-			action = BUS_RESET;
+	if (handle == NULL) {
+		if(action == ABORT_COMMAND) {
+			/* we never got this command */
+			printk(KERN_INFO "qla1280: Aborting a NULL handle\n");
+			return SUCCESS;	/* no action - we don't have command */
+		}
 	} else {
-		/*
-		 * Mid-level driver has called reset with this SCSI_Cmnd and
-		 * its pending.
-		 */
-		if (flags & SCSI_RESET_SUGGEST_HOST_RESET)
-			action = ADAPTER_RESET;
-		else if (flags & SCSI_RESET_SUGGEST_BUS_RESET)
-			action = BUS_RESET;
-		else
-			action = DEVICE_RESET;
+		sp->wait = &wait;
 	}
 
 	bus = SCSI_BUS_32(cmd);
@@ -1585,36 +1358,67 @@
 	lun = SCSI_LUN_32(cmd);
 	q = LU_Q(ha, bus, target, lun);
 
-#if AUTO_ESCALATE_RESET
-	if ((action & DEVICE_RESET) && (q->q_flag & QLA1280_QRESET)) {
-		printk(KERN_INFO
-		       "qla1280(%ld): Bus device reset already sent to "
-		       "device, escalating.\n", ha->host_no);
-		action = BUS_RESET;
-	}
-	if ((action & DEVICE_RESET) && (sp->flags & SRB_ABORT_PENDING)) {
-		printk(KERN_INFO
-		       "qla1280(%ld):Have already attempted to reach "
-		       "device with abort device\n", ha->host_no);
-		printk(KERN_INFO "qla1280(%ld):message, will escalate to BUS "
-		       "RESET.\n", ha->host_no);
-		action = BUS_RESET;
-	}
-#endif
-
-	/*
-	 *  By this point, we want to already know what we are going to do,
-	 *  so we only need to perform the course of action.
-	 */
-	result = SCSI_RESET_ERROR;
+	/* Overloading result.  Here it means the success or fail of the
+	 * *issue* of the action.  When we return from the routine, it must
+	 * mean the actual success or fail of the action */
+	result = FAIL;
 	switch (action) {
 	case FAIL:
 		break;
 
-	case RESET_DELAYED:
-		result = SCSI_RESET_PENDING;
+	case ABORT_COMMAND:
+		if (q == NULL) {
+			/* No lun queue -- command must not be active */
+			printk(KERN_WARNING "qla1280 (%d:%d:%d): No LUN queue for the "
+			       "specified device\n", bus, target, lun);
+			break;
+		}
+		if ((sp->flags & SRB_ABORT_PENDING)) {
+			printk(KERN_WARNING
+			       "scsi(): Command has a pending abort "
+			       "message - ABORT_PENDING.\n");
+			/* This should technically be impossible since we
+			 * now wait for abort completion */
+			break;
+		}
+
+		/*
+		 * Normally, would would need to search our queue for
+		 * the specified command but; since our sp contains
+		 * the cmd ptr, we can just remove it from our LUN
+		 * queue.
+		 */
+		if (!(sp->flags & SRB_SENT)) {
+			if (qla1280_verbose)
+				printk(KERN_WARNING
+				       "scsi(): Command returned from queue "
+				       "aborted.\n");
+			
+			/* Remove srb from SCSI LU queue. */
+			qla1280_removeq(q, sp);
+			sp->flags |= SRB_ABORTED;
+			CMD_RESULT(cmd) = DID_ABORT << 16;
+			qla1280_done_q_put(sp, &ha->done_q_first, &ha->done_q_last);
+			if (ha->done_q_first)
+				qla1280_done(ha, &ha->done_q_first, &ha->done_q_last);
+			
+			qla1280_restart_queues(ha);
+			
+		} else {	/* find the command in our active list */
+			int i;
+
+			for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
+				if (sp == ha->outstanding_cmds[i]) {
+					dprintk(1,
+						"qla1280: RISC aborting command.\n");
+					qla1280_abort_command(ha, sp);
+				}
+			}
+		}
 		break;
 
+
+
 	case ABORT_DEVICE:
 		ha->flags.in_reset = TRUE;
 		if (qla1280_verbose)
@@ -1623,7 +1427,7 @@
 			       "command.\n", ha->host_no, bus, target, lun);
 		qla1280_abort_queue_single(ha, bus, target, lun, DID_ABORT);
 		if (qla1280_abort_device(ha, bus, target, lun) == 0)
-			result = SCSI_RESET_PENDING;
+			result = SUCCESS;
 		break;
 
 	case DEVICE_RESET:
@@ -1636,7 +1440,7 @@
 			qla1280_abort_queue_single(ha, bus, target, lun,
 						   DID_ABORT);
 		if (qla1280_device_reset(ha, bus, target) == 0)
-			result = SCSI_RESET_PENDING;
+			result = SUCCESS;
 		q->q_flag |= QLA1280_QRESET;
 		break;
 
@@ -1651,24 +1455,12 @@
 				qla1280_abort_queue_single(ha, bus, target,
 							   lun, DID_RESET);
 		qla1280_bus_reset(ha, bus);
-		/*
-		 * The bus reset routine returns all the outstanding commands
-		 * back with "DID_RESET" in the status field after a short
-		 * delay by the firmware. If the mid-level time out the SCSI
-		 * reset before our delay we may need to ignore it.
-		 */
-		/* result = SCSI_RESET_PENDING | SCSI_RESET_BUS_RESET; */
-		result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
-		/*
-		 * Wheeeee!!!
-		 */
-		mdelay(4 * 1000);
-		barrier();
-		if (flags & SCSI_RESET_SYNCHRONOUS) {
-			CMD_RESULT(cmd) = DID_BUS_BUSY << 16;
-			(*(cmd)->scsi_done)(cmd);
-		}
-		/* ha->reset_start = jiffies; */
+
+		/* wait 4 seconds */
+		schedule_timeout(4*HZ);
+
+		result = SUCCESS;
+
 		break;
 
 	case ADAPTER_RESET:
@@ -1688,7 +1480,7 @@
 		 * mid-level code can expect completions momentitarily.
 		 */
 		if (qla1280_abort_isp(ha) == 0)
-			result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
+			result = SUCCESS;
 
 		ha->flags.reset_active = FALSE;
 	}
@@ -1698,13 +1490,81 @@
 	qla1280_restart_queues(ha);
 	ha->flags.in_reset = FALSE;
 
+	/* If we didn't manage to issue the action, or we have no
+	 * command to wait for, exit here */
+	if(result == FAIL || handle == NULL)
+		goto leave;
+
+	/* set up a timer just in case we're really jammed */
+	init_timer(&timer);
+	timer.expires = jiffies + 4*HZ;
+	timer.data = (unsigned long)cmd;
+	timer.function = qla1280_error_wait_timeout;
+	add_timer(&timer);
+
+	/* wait for the action to complete (or the timer to expire) */
+	spin_unlock_irq(ha->host->host_lock);
+	wait_for_completion(&wait);
+	del_timer_sync(&timer);
+	spin_lock_irq(ha->host->host_lock);
+	sp->wait = NULL;
+	
+	/* the only action we might get a fail for is abort */
+	if(action == ABORT_COMMAND) {
+		if(sp->flags & SRB_ABORTED)
+			result = SUCCESS;
+		else
+			result = FAILED;
+	}
+
+ leave:
 	dprintk(1, "RESET returning %d\n", result);
 
-	LEAVE("qla1280_reset");
+	LEAVE("qla1280_error_action");
 	return result;
 }
 
 /**************************************************************************
+ *   qla1200_abort
+ *     Abort the specified SCSI command(s).
+ **************************************************************************/
+int
+qla1280_eh_abort(struct scsi_cmnd * cmd)
+{
+	return qla1280_error_action(cmd, ABORT_COMMAND);
+}
+
+/**************************************************************************
+ *   qla1200_device_reset
+ *     Reset the specified SCSI device
+ **************************************************************************/
+int
+qla1280_eh_device_reset(struct scsi_cmnd *cmd)
+{
+	return qla1280_error_action(cmd, DEVICE_RESET);
+}
+
+/**************************************************************************
+ *   qla1200_bus_reset
+ *     Reset the specified bus.
+ **************************************************************************/
+int
+qla1280_eh_bus_reset(struct scsi_cmnd *cmd)
+{
+	return qla1280_error_action(cmd, BUS_RESET);
+}
+
+/**************************************************************************
+ *   qla1200_adapter_reset
+ *     Reset the specified adapter (both channels)
+ **************************************************************************/
+int
+qla1280_eh_adapter_reset(struct scsi_cmnd *cmd)
+{
+	return qla1280_error_action(cmd, ADAPTER_RESET);
+}
+
+/**************************************************************************
  * qla1280_biosparam
  *   Return the disk geometry for the given SCSI device.
  **************************************************************************/
@@ -1934,6 +1794,9 @@
 
 		(*(cmd)->scsi_done)(cmd);
 
+		if(sp->wait != NULL)
+			complete(sp->wait);
+
 		qla1280_next(ha, q, bus);
 	}
 	LEAVE("qla1280_done");
@@ -2537,11 +2400,11 @@
 	dprintk(1, "qla1280_isp_firmware: Completed Reading NVRAM\n");
 
 	dprintk(3, "qla1280_isp_firmware: NVRAM Magic ID= %c %c %c\n",
-		(char *)nv->id[0], nv->id[1], nv->id[2]);
+		nv->id0, nv->id1, nv->id2);
 
 	/* Bad NVRAM data, load RISC code. */
-	if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
-	    nv->id[2] != 'P' || nv->id[3] != ' ' || nv->version < 1) {
+	if (chksum || nv->id0 != 'I' || nv->id1 != 'S' ||
+	    nv->id2 != 'P' || nv->id3 != ' ' || nv->version < 1) {
 		printk(KERN_INFO "qla1280_isp_firmware: Bad checksum or magic "
 		       "number or version in NVRAM.\n");
 		ha->flags.disable_risc_code_load = FALSE;
@@ -2791,7 +2654,7 @@
  * Returns:
  *      0 = success.
  */
-#define DUMP_IT_BACK 0		/* for debug of RISC loading */
+#define DUMP_IT_BACK 1		/* for debug of RISC loading */
 static int
 qla1280_setup_chip(struct scsi_qla_host *ha)
 {
@@ -2806,11 +2669,7 @@
 	int i;
 	uint8_t *sp;
 	uint8_t *tbuf;
-#ifdef QLA_64BIT_PTR
 	dma_addr_t p_tbuf;
-#else
-	uint32_t p_tbuf;
-#endif
 #endif
 
 	ENTER("qla1280_setup_chip");
@@ -2831,6 +2690,8 @@
 
 	num = 0;
 	while (risc_code_size > 0 && !status) {
+		int warn __attribute__((unused)) = 0;
+
 		cnt = 2000 >> 1;
 
 		if (cnt > risc_code_size)
@@ -2839,20 +2700,22 @@
 		dprintk(1, "qla1280_setup_chip:  loading risc @ =(0x%p),"
 			"%d,%d(0x%x)\n",
 			risc_code_address, cnt, num, risc_address);
-		memcpy(ha->request_ring, risc_code_address, (cnt << 1));
+		for(i = 0; i < cnt; i++)
+			((uint16_t *)ha->request_ring)[i] =
+				cpu_to_le16(risc_code_address[i]);
 
 		flush_cache_all();
 
 		mb[0] = MBC_LOAD_RAM;
 		mb[1] = risc_address;
 		mb[4] = cnt;
-		mb[3] = ha->request_dma & 0xffff;
-		mb[2] = (ha->request_dma >> 16) & 0xffff;
-		mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff;
-		mb[6] = pci_dma_hi32(ha->request_dma) >> 16;
+		mb[3] = qla1280_addr0_15(ha->request_dma);
+		mb[2] = qla1280_addr16_31(ha->request_dma);
+		mb[7] = qla1280_addr32_47(ha->request_dma);
+		mb[6] = qla1280_addr48_63(ha->request_dma);
 		dprintk(1, "qla1280_setup_chip: op=%d  0x%p = 0x%4x,0x%4x,"
 			"0x%4x,0x%4x\n",
-			mb[0], ha->request_dma, mb[6], mb[7], mb[2], mb[3]);
+			mb[0], (void *)ha->request_dma, mb[6], mb[7], mb[2], mb[3]);
 		if ((status = qla1280_mailbox_command(ha, BIT_4 | BIT_3 |
 						      BIT_2 | BIT_1 | BIT_0,
 						      &mb[0]))) {
@@ -2860,14 +2723,15 @@
 			       "Failed to load partial segment of f/w\n");
 			break;
 		}
+
 #if DUMP_IT_BACK
-		mb[0] = MBC_READ_RAM_WORD;
+		mb[0] = MBC_DUMP_RAM;
 		mb[1] = risc_address;
 		mb[4] = cnt;
-		mb[3] = p_tbuf & 0xffff;
-		mb[2] = (p_tbuf >> 16) & 0xffff;
-		mb[7] = pci_dma_hi32(p_tbuf) & 0xffff;
-		mb[6] = pci_dma_hi32(p_tbuf) >> 16;
+		mb[3] = qla1280_addr0_15(p_tbuf);
+		mb[2] = qla1280_addr16_31(p_tbuf);
+		mb[7] = qla1280_addr32_47(p_tbuf);
+		mb[6] = qla1280_addr48_63(p_tbuf);
 
 		if ((status = qla1280_mailbox_command(ha,
 						      BIT_4 | BIT_3 | BIT_2 |
@@ -2879,7 +2743,7 @@
 		}
 		sp = (uint8_t *)ha->request_ring;
 		for (i = 0; i < (cnt << 1); i++) {
-			if (tbuf[i] != sp[i]) {
+			if (tbuf[i] != sp[i] &&warn++ < 10) {
 				printk(KERN_ERR "qla1280_setup_chip: FW "
 				       "compare error @ byte(0x%x) loop#=%x\n",
 				       i, num);
@@ -3044,8 +2908,8 @@
 #endif
 
 	/* Bad NVRAM data, set defaults parameters. */
-	if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
-	    nv->id[2] != 'P' || nv->id[3] != ' ' || nv->version < 1) {
+	if (chksum || nv->id0 != 'I' || nv->id1 != 'S' ||
+	    nv->id2 != 'P' || nv->id3 != ' ' || nv->version < 1) {
 #if USE_NVRAM_DEFAULTS
 		dprintk(1, "Using defaults for NVRAM\n");
 #else
@@ -3262,14 +3126,14 @@
 			    ha->device_id == PCI_DEVICE_ID_QLOGIC_ISP10160) {
 				nvram160_t *nv2 = (nvram160_t *) nv;
 				mb[2] |=
-					nv2->bus[bus].target[target].flags.
+					nv2->bus[bus].target[target].flags2.
 					enable_ppr << 5;
 
 				mb[6] =
-					nv2->bus[bus].target[target].flags.
+					nv2->bus[bus].target[target].flags2.
 					ppr_options << 8;
 				mb[6] |=
-					nv2->bus[bus].target[target].flags.
+					nv2->bus[bus].target[target].flags2.
 					ppr_bus_width;
 				mr |= BIT_6;
 			}
@@ -3885,13 +3749,13 @@
 			pkt->entry_type = COMMAND_A64_TYPE;
 			pkt->entry_count = (uint8_t) req_cnt;
 			pkt->sys_define = (uint8_t) ha->req_ring_index;
-			pkt->handle = (uint32_t) cnt;
+			pkt->handle = cpu_to_le32(cnt);
 
 			/* Zero out remaining portion of packet. */
 			memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
 
 			/* Set ISP command timeout. */
-			pkt->timeout = 30;
+			pkt->timeout = cpu_to_le16(30);
 
 			/* Set device target ID and LUN */
 			pkt->lun = SCSI_LUN_32(cmd);
@@ -3900,28 +3764,24 @@
 
 			/* Enable simple tag queuing if device supports it. */
 			if (cmd->device->tagged_queue)
-				pkt->control_flags |= BIT_3;
+				pkt->control_flags |= cpu_to_le16(BIT_3);
 
 			/* Load SCSI command packet. */
-			pkt->cdb_len = (uint16_t)CMD_CDBLEN(cmd);
-			memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), pkt->cdb_len);
+			pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd));
+			memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), CMD_CDBLEN(cmd));
 			/* dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */
 
+			/* Set transfer direction. */
+			sp->dir = qla1280_data_direction(cmd);
+			pkt->control_flags |= cpu_to_le16(sp->dir);
+			
+			/* Set total data segment count. */
+			pkt->dseg_count = cpu_to_le16(seg_cnt);
+
 			/*
 			 * Load data segments.
 			 */
 			if (seg_cnt) {	/* If data transfer. */
-				/* Set transfer direction. */
-				if ((cmd->data_cmnd[0] == WRITE_6))
-					pkt->control_flags |= BIT_6;
-				else
-					pkt->control_flags |= (BIT_5 | BIT_6);
-
-				sp->dir = pkt->control_flags & (BIT_5 | BIT_6);
-
-				/* Set total data segment count. */
-				pkt->dseg_count = seg_cnt;
-
 				/* Setup packet address segment pointer. */
 				dword_ptr = (u32 *)&pkt->dseg_0_address;
 
@@ -4198,13 +4058,13 @@
 			pkt->entry_type = COMMAND_TYPE;
 			pkt->entry_count = (uint8_t) req_cnt;
 			pkt->sys_define = (uint8_t) ha->req_ring_index;
-			pkt->handle = (uint32_t) cnt;
+			pkt->handle = cpu_to_le32(cnt);
 
 			/* Zero out remaining portion of packet. */
 			memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
 
 			/* Set ISP command timeout. */
-			pkt->timeout = 30;
+			pkt->timeout = cpu_to_le16(30);
 
 			/* Set device target ID and LUN */
 			pkt->lun = SCSI_LUN_32(cmd);
@@ -4213,35 +4073,24 @@
 
 			/* Enable simple tag queuing if device supports it. */
 			if (cmd->device->tagged_queue)
-				pkt->control_flags |= BIT_3;
+				pkt->control_flags |= cpu_to_le16(BIT_3);
 
 			/* Load SCSI command packet. */
-			pkt->cdb_len = (uint16_t) CMD_CDBLEN(cmd);
-			memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), pkt->cdb_len);
+			pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd));
+			memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), CMD_CDBLEN(cmd));
 
 			/*dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */
+			/* Set transfer direction. */
+			sp->dir = qla1280_data_direction(cmd);
+			pkt->control_flags |= cpu_to_le16(sp->dir);
+			
+			/* Set total data segment count. */
+			pkt->dseg_count = cpu_to_le16(seg_cnt);
+
 			/*
 			 * Load data segments.
 			 */
 			if (seg_cnt) {
-				/* Set transfer direction (READ and WRITE) */
-				/* Linux doesn't tell us                   */
-				/*
-				 * For block devices, cmd->request->cmd has the operation
-				 * For character devices, this isn't always set properly, so
-				 * we need to check data_cmnd[0].  This catches the conditions
-				 * for st.c, but not sg. Generic commands are pass down to us.
-				 */
-				if ((cmd->data_cmnd[0] == WRITE_6))
-					pkt->control_flags |= BIT_6;
-				else
-					pkt->control_flags |= (BIT_5 | BIT_6);
-
-				sp->dir = pkt->control_flags & (BIT_5 | BIT_6);
-
-				/* Set total data segment count. */
-				pkt->dseg_count = seg_cnt;
-
 				/* Setup packet address segment pointer. */
 				dword_ptr = &pkt->dseg_0_address;
 
@@ -4258,7 +4107,7 @@
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18)
 						*dword_ptr++ =
 							cpu_to_le32(virt_to_bus(sg->address));
-						*dword_ptr++ = sg->length;
+						*dword_ptr++ = cpu_to_le32(sg->length);
 						dprintk(1,
 							"S/G Segment phys_addr=0x%x, len=0x%x\n",
 							cpu_to_le32(virt_to_bus(sg->address)),
@@ -4269,8 +4118,8 @@
 						*dword_ptr++ =
 							cpu_to_le32(sg_dma_len(sg));
 						dprintk(1, "S/G Segment phys_addr=0x%x, len=0x%x\n",
-							cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))),
-							cpu_to_le32(sg_dma_len(sg)));
+							(pci_dma_lo32(sg_dma_address(sg))),
+							(sg_dma_len(sg)));
 #endif
 						sg++;
 					}
@@ -4321,7 +4170,7 @@
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18)
 							*dword_ptr++ =
 								cpu_to_le32(virt_to_bus(sg->address));
-							*dword_ptr++ = sg->length;
+							*dword_ptr++ = cpu_to_le32(sg->length);
 							dprintk(1,
 								"S/G Segment Cont. phys_addr=0x%x, len=0x%x\n",
 								cpu_to_le32(pci_dma_lo32(virt_to_bus(sg->address))), sg->length);
@@ -4366,13 +4215,15 @@
 						cpu_to_le32(pci_dma_lo32(dma_handle));
 #endif
 					*dword_ptr =
-						(uint32_t)cmd->request_bufflen;
+						cpu_to_le32(cmd->request_bufflen);
+					qla1280_dump_buffer(1,(char *)pkt,
+							      REQUEST_ENTRY_SIZE);
 				}
 			} else {	/* No data transfer at all */
 
-				dword_ptr = (uint32_t *)(pkt + 1);
-				*dword_ptr++ = 0;
-				*dword_ptr = 0;
+				//dword_ptr = (uint32_t *)(pkt + 1);
+				//*dword_ptr++ = 0;
+				//*dword_ptr = 0;
 				dprintk(5,
 					"qla1280_32bit_start_scsi: No data, command "
 					"packet data - \n");
@@ -4543,12 +4394,12 @@
 	  if (pkt = (elun_entry_t *)qla1280_req_pkt(ha))
 	  {
 	  pkt->entry_type = ENABLE_LUN_TYPE;
-	  pkt->lun = (uint16_t)(bus ? lun | BIT_15 : lun);
+	  pkt->lun = cpu_to_le16(bus ? lun | BIT_15 : lun);
 	  pkt->command_count = 32;
 	  pkt->immed_notify_count = 1;
 	  pkt->group_6_length = MAX_CMDSZ;
 	  pkt->group_7_length = MAX_CMDSZ;
-	  pkt->timeout = 0x30;
+	  pkt->timeout = cpu_to_le16(0x30);
 
 	  qla1280_isp_cmd(ha);
 	  }
@@ -4593,7 +4444,7 @@
 		if (inotify->seq_id == 0)
 			pkt->event = BIT_7;
 		else
-			pkt->seq_id = inotify->seq_id;
+			pkt->seq_id = cpu_to_le16(inotify->seq_id);
 
 		/* Issue command to ISP */
 		qla1280_isp_cmd(ha);
@@ -4697,17 +4548,17 @@
 		pkt->lun = atio->lun;
 		pkt->initiator_id = atio->initiator_id;
 		pkt->target_id = atio->target_id;
-		pkt->option_flags = atio->option_flags;
+		pkt->option_flags = cpu_to_le32(atio->option_flags);
 		pkt->tag_value = atio->tag_value;
 		pkt->scsi_status = atio->scsi_status;
 
 		if (len) {
-			pkt->dseg_count = 1;
-			pkt->transfer_length = len;
-			pkt->dseg_0_length = len;
+			pkt->dseg_count = cpu_to_le16(1);
+			pkt->transfer_length = cpu_to_le32(len);
+			pkt->dseg_0_length = cpu_to_le32(len);
 			dword_ptr = (uint32_t *) addr;
-			pkt->dseg_0_address[0] = *dword_ptr++;
-			pkt->dseg_0_address[1] = *dword_ptr;
+			pkt->dseg_0_address[0] = cpu_to_le32(*dword_ptr++);
+			pkt->dseg_0_address[1] = cpu_to_le32(*dword_ptr);
 		}
 
 		/* Issue command to ISP */
@@ -4745,16 +4596,16 @@
 		pkt->lun = atio->lun;
 		pkt->initiator_id = atio->initiator_id;
 		pkt->target_id = atio->target_id;
-		pkt->option_flags = atio->option_flags;
+		pkt->option_flags = cpu_to_le32(atio->option_flags);
 		pkt->tag_value = atio->tag_value;
 		pkt->scsi_status = atio->scsi_status;
 
 		if (len) {
-			pkt->dseg_count = 1;
-			pkt->transfer_length = len;
-			pkt->dseg_0_length = len;
-			dword_ptr = (uint32_t *) addr;
-			pkt->dseg_0_address = *dword_ptr;
+			pkt->dseg_count = cpu_to_le16(1);
+			pkt->transfer_length = cpu_to_le32(len);
+			pkt->dseg_0_length = cpu_to_le32(len);
+			dword_ptr = (uint32_t *)addr;
+			pkt->dseg_0_address = cpu_to_le32(*dword_ptr);
 		}
 
 		/* Issue command to ISP */
@@ -4967,7 +4818,7 @@
 						    RESPONSE_ENTRY_SIZE);
 
 				if (pkt->entry_type == STATUS_TYPE) {
-					if ((pkt->scsi_status & 0xff)
+					if ((le16_to_cpu(pkt->scsi_status) & 0xff)
 					    || pkt->comp_status
 					    || pkt->entry_status) {
 						dprintk(2,
@@ -4976,8 +4827,8 @@
 							"scsi_status = 0x%x\n",
 							ha->rsp_ring_index,
 							mailbox[5],
-							pkt->comp_status,
-							pkt->scsi_status);
+							le16_to_cpu(pkt->comp_status),
+							le16_to_cpu(pkt->scsi_status));
 					}
 				} else {
 					dprintk(2,
@@ -5169,7 +5020,7 @@
 			*(sense_ptr + 12) = SC_SELFAIL;
 		}
 		pkt->scsi_status = S_CKCON;
-		pkt->option_flags |= OF_SSTS | OF_NO_DATA;
+		pkt->option_flags |= cpu_to_le32(OF_SSTS | OF_NO_DATA);
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18)
 		if (ha->flags.enable_64bit_addressing)
@@ -5212,7 +5063,7 @@
 				pkt->scsi_status = S_CKCON;
 			}
 
-			pkt->option_flags |= (OF_SSTS | OF_NO_DATA);
+			pkt->option_flags |= cpu_to_le32(OF_SSTS | OF_NO_DATA);
 			break;
 
 		case SS_REQSEN:
@@ -5226,7 +5077,7 @@
 			else
 				len = pkt->cdb[4];
 			pkt->scsi_status = S_GOOD;
-			pkt->option_flags |= (OF_SSTS | OF_DATA_IN);
+			pkt->option_flags |= cpu_to_le32(OF_SSTS | OF_DATA_IN);
 			break;
 
 		case SS_INQUIR:
@@ -5250,7 +5101,7 @@
 			else
 				len = pkt->cdb[4];
 			pkt->scsi_status = S_GOOD;
-			pkt->option_flags |= (OF_SSTS | OF_DATA_IN);
+			pkt->option_flags |= cpu_to_le32(OF_SSTS | OF_DATA_IN);
 			break;
 
 		case SM_WRDB:
@@ -5281,12 +5132,12 @@
 					*(sense_ptr + 12) = SC_ILLCDB;
 					pkt->scsi_status = S_CKCON;
 					pkt->option_flags |=
-						(OF_SSTS | OF_NO_DATA);
+						cpu_to_le32(OF_SSTS | OF_NO_DATA);
 					len = 0;
 				} else if (len) {
 					pkt->scsi_status = S_GOOD;
 					pkt->option_flags |=
-						(OF_SSTS | OF_DATA_OUT);
+						cpu_to_le32(OF_SSTS | OF_DATA_OUT);
 					dprintk(3,
 						"qla1280_atio_entry: Issuing "
 						"SDI_TARMOD_WRCOMP\n");
@@ -5301,7 +5152,7 @@
 
 					pkt->scsi_status = S_GOOD;
 					pkt->option_flags |=
-						(OF_SSTS | OF_NO_DATA);
+						cpu_to_le32(OF_SSTS | OF_NO_DATA);
 				}
 
 				break;
@@ -5327,11 +5178,11 @@
 					len = 0;
 					pkt->scsi_status = S_CKCON;
 					pkt->option_flags |=
-						(OF_SSTS | OF_NO_DATA);
+						cpu_to_le32(OF_SSTS | OF_NO_DATA);
 				} else if (len) {
 					pkt->scsi_status = S_GOOD;
 					pkt->option_flags |=
-						(OF_SSTS | OF_DATA_OUT);
+						cpu_to_le32(OF_SSTS | OF_DATA_OUT);
 					dprintk(3,
 						"qla1280_atio_entry: Issuing "
 						"SDI_TARMOD_WRCOMP\n");
@@ -5346,7 +5197,7 @@
 
 					pkt->scsi_status = S_GOOD;
 					pkt->option_flags |=
-						(OF_SSTS | OF_NO_DATA);
+						cpu_to_le32(OF_SSTS | OF_NO_DATA);
 				}
 				break;
 
@@ -5360,7 +5211,7 @@
 				*(sense_ptr + 12) = SC_ILLCDB;
 				len = 0;
 				pkt->scsi_status = S_CKCON;
-				pkt->option_flags |= (OF_SSTS | OF_NO_DATA);
+				pkt->option_flags |= cpu_to_le32(OF_SSTS | OF_NO_DATA);
 				break;
 			}
 			break;
@@ -5393,7 +5244,7 @@
 						len = TARGET_DATA_SIZE + 4;
 					pkt->scsi_status = S_GOOD;
 					pkt->option_flags |=
-						(OF_SSTS | OF_DATA_IN);
+						cpu_to_le32(OF_SSTS | OF_DATA_IN);
 				} else {
 					dprintk(2,
 						"qla1280_atio_entry: SM_RDDB, "
@@ -5401,7 +5252,7 @@
 
 					pkt->scsi_status = S_GOOD;
 					pkt->option_flags |=
-						(OF_SSTS | OF_NO_DATA);
+						cpu_to_le32(OF_SSTS | OF_NO_DATA);
 				}
 				break;
 			case RW_BUF_DATA:
@@ -5424,7 +5275,7 @@
 					len = 0;
 					pkt->scsi_status = S_CKCON;
 					pkt->option_flags |=
-						(OF_SSTS | OF_NO_DATA);
+						cpu_to_le32(OF_SSTS | OF_NO_DATA);
 				} else {
 					if (*a64 + len > *end_a64)
 						len = *end_a64 - *a64;
@@ -5439,7 +5290,7 @@
 
 						pkt->scsi_status = S_GOOD;
 						pkt->option_flags |=
-							(OF_SSTS | OF_NO_DATA);
+							cpu_to_le32(OF_SSTS | OF_NO_DATA);
 					}
 				}
 				break;
@@ -5468,7 +5319,7 @@
 					}
 					pkt->scsi_status = S_GOOD;
 					pkt->option_flags |=
-						(OF_SSTS | OF_DATA_IN);
+						cpu_to_le32(OF_SSTS | OF_DATA_IN);
 				} else {
 					dprintk(2,
 						"qla1280_atio_entry: SM_RDDB,"
@@ -5476,7 +5327,7 @@
 
 					pkt->scsi_status = S_GOOD;
 					pkt->option_flags |=
-						(OF_SSTS | OF_NO_DATA);
+						cpu_to_le32(OF_SSTS | OF_NO_DATA);
 				}
 				break;
 			default:
@@ -5489,7 +5340,7 @@
 				*(sense_ptr + 12) = SC_ILLCDB;
 				len = 0;
 				pkt->scsi_status = S_CKCON;
-				pkt->option_flags |= (OF_SSTS | OF_NO_DATA);
+				pkt->option_flags |= cpu_to_le32(OF_SSTS | OF_NO_DATA);
 				break;
 			}
 			break;
@@ -5506,7 +5357,7 @@
 			*(sense_ptr + 12) = SC_INVOPCODE;
 			len = 0;
 			pkt->scsi_status = S_CKCON;
-			pkt->option_flags |= (OF_SSTS | OF_NO_DATA);
+			pkt->option_flags |= cpu_to_le32(OF_SSTS | OF_NO_DATA);
 			break;
 		}
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18)
@@ -5568,18 +5419,21 @@
 	srb_t *sp;
 	scsi_lu_t *q;
 	Scsi_Cmnd *cmd;
+	uint32_t handle = le32_to_cpu(pkt->handle);
+	uint16_t scsi_status = le16_to_cpu(pkt->scsi_status);
+	uint16_t comp_status = le16_to_cpu(pkt->comp_status);
 
 	ENTER("qla1280_status_entry");
 
 	/* Validate handle. */
-	if (pkt->handle < MAX_OUTSTANDING_COMMANDS)
-		sp = ha->outstanding_cmds[pkt->handle];
+	if (handle < MAX_OUTSTANDING_COMMANDS)
+		sp = ha->outstanding_cmds[handle];
 	else
 		sp = 0;
 
 	if (sp) {
 		/* Free outstanding command slot. */
-		ha->outstanding_cmds[pkt->handle] = 0;
+		ha->outstanding_cmds[handle] = 0;
 
 		cmd = sp->cmd;
 
@@ -5589,27 +5443,29 @@
 		lun = SCSI_LUN_32(cmd);
 		q = LU_Q(ha, bus, target, lun);
 
-		if (pkt->comp_status || pkt->scsi_status) {
+		if (comp_status || scsi_status) {
 			dprintk(1, "scsi: comp_status = 0x%x, scsi_status = "
-				"0x%x, handle = 0x%x\n", pkt->comp_status,
-				pkt->scsi_status, pkt->handle);
+				"0x%x, handle = 0x%lx\n", comp_status,
+				scsi_status, handle);
 		}
 
 		/* Target busy */
-		if (pkt->scsi_status & SS_BUSY_CONDITION &&
-		    pkt->scsi_status != SS_RESERVE_CONFLICT) {
+		if (scsi_status & SS_BUSY_CONDITION &&
+		    scsi_status != SS_RESERVE_CONFLICT) {
 			CMD_RESULT(cmd) =
-				DID_BUS_BUSY << 16 | (pkt->scsi_status & 0xff);
+				DID_BUS_BUSY << 16 | (scsi_status & 0xff);
 		} else {
 
 			/* Save ISP completion status */
 			CMD_RESULT(cmd) = qla1280_return_status(pkt, cmd);
 
-			if (pkt->scsi_status & SS_CHECK_CONDITION) {
-				if (pkt->comp_status != CS_ARS_FAILED) {
-					if (pkt->req_sense_length <
+			if (scsi_status & SS_CHECK_CONDITION) {
+				if (comp_status != CS_ARS_FAILED) {
+					uint16_t req_sense_length =
+						le16_to_cpu(pkt->req_sense_length);
+					if (req_sense_length <
 					    CMD_SNSLEN(cmd))
-						sense_sz = pkt->req_sense_length;
+						sense_sz = req_sense_length;
 					else
 						/*
 						 * Scsi_Cmnd->sense_buffer is
@@ -5658,6 +5514,7 @@
 		    srb_t ** done_q_first, srb_t ** done_q_last)
 {
 	srb_t *sp;
+	uint32_t handle = le32_to_cpu(pkt->handle);
 
 	ENTER("qla1280_error_entry");
 
@@ -5671,14 +5528,14 @@
 		dprintk(2, "qla1280_error_entry: UNKNOWN flag error\n");
 
 	/* Validate handle. */
-	if (pkt->handle < MAX_OUTSTANDING_COMMANDS)
-		sp = ha->outstanding_cmds[pkt->handle];
+	if (handle < MAX_OUTSTANDING_COMMANDS)
+		sp = ha->outstanding_cmds[handle];
 	else
 		sp = 0;
 
 	if (sp) {
 		/* Free outstanding command slot. */
-		ha->outstanding_cmds[pkt->handle] = 0;
+		ha->outstanding_cmds[handle] = 0;
 
 		/* Bad payload or header */
 		if (pkt->entry_status & (BIT_3 + BIT_2)) {
@@ -5946,8 +5803,10 @@
 	.release		= qla1280_release,
 	.info			= qla1280_info,
 	.queuecommand		= qla1280_queuecommand,
-	.abort			= qla1280_abort,
-	.reset			= qla1280_reset,
+	.eh_abort_handler	= qla1280_eh_abort,
+	.eh_device_reset_handler = qla1280_eh_device_reset,
+	.eh_bus_reset_handler	= qla1280_eh_bus_reset,
+	.eh_host_reset_handler	= qla1280_eh_adapter_reset,
 	.slave_configure	= qla1280_slave_configure,
 	.bios_param		= qla1280_biosparam,
 	.can_queue		= 255,
diff -Nru a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h
--- a/drivers/scsi/qla1280.h	Sun May  4 02:56:45 2003
+++ b/drivers/scsi/qla1280.h	Mon May 26 16:33:44 2003
@@ -158,6 +158,9 @@
 	uint8_t dir;		/* direction of transfer */
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18)
 	dma_addr_t saved_dma_handle;	/* for unmap of single transfers */
+	/* NOTE: the sp->cmd will be NULL when this completion is
+	 * called, so you should know the scsi_cmnd when using this */
+	struct completion *wait;
 #endif
 
 } srb_t;
@@ -317,6 +320,7 @@
 #define MBC_NOP                     0	/* No Operation. */
 #define MBC_LOAD_RAM                1	/* Load RAM. */
 #define MBC_EXECUTE_FIRMWARE        2	/* Execute firmware. */
+#define MBC_DUMP_RAM		     3   /* Dump RAM contents */
 #define MBC_WRITE_RAM_WORD          4	/* Write ram word. */
 #define MBC_READ_RAM_WORD           5	/* Read ram word. */
 #define MBC_MAILBOX_REGISTER_TEST   6	/* Wrap incoming mailboxes */
@@ -371,9 +375,170 @@
 
 /*
  *  QLogic ISP1280 NVRAM structure definition.
+ *
+ * NOTE: the firmware structure is byte reversed on big-endian systems
+ * because it is read a word at a time from the chip, so the in-memory
+ * representation becomes correct
  */
 typedef struct {
-	uint8_t id[4];		/* 0, 1, 2, 3 */
+#if defined(__BIG_ENDIAN)
+	uint8_t id1;		/* 1 */
+	uint8_t id0;		/* 0 */
+
+	uint8_t id3;		/* 3 */
+	uint8_t id2;		/* 2 */
+
+	struct {
+		uint8_t bios_configuration_mode:2;
+		uint8_t bios_disable:1;
+		uint8_t selectable_scsi_boot_enable:1;
+		uint8_t cd_rom_boot_enable:1;
+		uint8_t disable_loading_risc_code:1;
+		uint8_t enable_64bit_addressing:1;
+		uint8_t unused_7:1;
+	} cntr_flags_1;		/* 5 */
+	uint8_t version;	/* 4 */
+
+	struct {
+		uint8_t boot_lun_number:5;
+		uint8_t scsi_bus_number:1;
+		uint8_t unused_6:1;
+		uint8_t unused_7:1;
+		uint8_t boot_target_number:4;
+		uint8_t unused_12:1;
+		uint8_t unused_13:1;
+		uint8_t unused_14:1;
+		uint8_t unused_15:1;
+	} cntr_flags_2;		/* 6, 7 */
+
+	uint16_t unused_8;	/* 8, 9 */
+	uint16_t unused_10;	/* 10, 11 */
+	uint16_t unused_12;	/* 12, 13 */
+	uint16_t unused_14;	/* 14, 15 */
+
+	/* Termination
+	 * 0 = Disable, 1 = high only, 3 = Auto term
+	 */
+	union {
+		uint8_t c;
+		struct {
+			uint8_t scsi_bus_1_control:2;
+			uint8_t scsi_bus_0_control:2;
+			uint8_t unused_0:1;
+			uint8_t unused_1:1;
+			uint8_t unused_2:1;
+			uint8_t auto_term_support:1;
+		} f;
+	} termination;		/* 17 */
+	union {
+		uint8_t c;
+		struct {
+			uint8_t reserved:2;
+			uint8_t burst_enable:1;
+			uint8_t reserved_1:1;
+			uint8_t fifo_threshold:4;
+		} f;
+	} isp_config;		/* 16 */
+
+
+	uint16_t isp_parameter;	/* 18, 19 */
+
+	union {
+		uint16_t w;
+		struct {
+			uint16_t enable_fast_posting:1;
+			uint16_t report_lvd_bus_transition:1;
+			uint16_t unused_2:1;
+			uint16_t unused_3:1;
+			uint16_t unused_4:1;
+			uint16_t unused_5:1;
+			uint16_t unused_6:1;
+			uint16_t unused_7:1;
+			uint16_t unused_8:1;
+			uint16_t unused_9:1;
+			uint16_t unused_10:1;
+			uint16_t unused_11:1;
+			uint16_t unused_12:1;
+			uint16_t unused_13:1;
+			uint16_t unused_14:1;
+			uint16_t unused_15:1;
+		} f;
+	} firmware_feature;	/* 20, 21 */
+
+	uint16_t unused_22;	/* 22, 23 */
+
+	struct {
+		uint8_t bus_reset_delay;	/* 25 */
+		struct {
+			uint8_t initiator_id:4;
+			uint8_t scsi_reset_disable:1;
+			uint8_t scsi_bus_size:1;
+			uint8_t scsi_bus_type:1;
+			uint8_t unused_7:1;
+		} config_1;	/* 24 */
+
+		uint8_t retry_delay;	/* 27 */
+		uint8_t retry_count;	/* 26 */
+
+		uint8_t unused_29;	/* 29 */
+		struct {
+			uint8_t async_data_setup_time:4;
+			uint8_t req_ack_active_negation:1;
+			uint8_t data_line_active_negation:1;
+			uint8_t unused_6:1;
+			uint8_t unused_7:1;
+		} config_2;	/* 28 */
+
+
+		uint16_t selection_timeout;	/* 30, 31 */
+		uint16_t max_queue_depth;	/* 32, 33 */
+
+		uint16_t unused_34;	/* 34, 35 */
+		uint16_t unused_36;	/* 36, 37 */
+		uint16_t unused_38;	/* 38, 39 */
+
+		struct {
+			uint8_t execution_throttle;	/* 41 */
+			union {
+				uint8_t c;
+				struct {
+					uint8_t renegotiate_on_error:1;
+					uint8_t stop_queue_on_check:1;
+					uint8_t auto_request_sense:1;
+					uint8_t tag_queuing:1;
+					uint8_t sync_data_transfers:1;
+					uint8_t wide_data_transfers:1;
+					uint8_t parity_checking:1;
+					uint8_t disconnect_allowed:1;
+				} f;
+			} parameter;	/* 40 */
+
+			struct {
+				uint8_t sync_offset:4;
+				uint8_t device_enable:1;
+				uint8_t lun_disable:1;
+				uint8_t unused_6:1;
+				uint8_t unused_7:1;
+			} flags;	/* 43 */
+			uint8_t sync_period;	/* 42 */
+
+
+			uint16_t unused_44;	/* 44, 45 */
+		} target[MAX_TARGETS];
+	} bus[MAX_BUSES];
+
+	uint16_t unused_248;	/* 248, 249 */
+
+	uint16_t subsystem_id[2];	/* 250, 251, 252, 253 */
+
+	uint8_t chksum;		/* 255 */
+	uint8_t unused_254;	/* 254 */
+
+#elif defined(__LITTLE_ENDIAN)
+	uint8_t id0;		/* 0 */
+	uint8_t id1;		/* 1 */
+	uint8_t id2;		/* 2 */
+	uint8_t id3;		/* 3 */
 	uint8_t version;	/* 4 */
 
 	struct {
@@ -521,14 +686,26 @@
 	uint8_t unused_254;	/* 254 */
 
 	uint8_t chksum;		/* 255 */
+#else
+#error neither __BIG_ENDIAN nor __LITTLE_ENDIAN is defined
+#endif
 } nvram_t;
 
 /*
  *  QLogic ISP12160 NVRAM structure definition.
+ *
+ * NOTE: the firmware structure is byte reversed on big-endian systems
+ * because it is read a word at a time from the chip, so the in-memory
+ * representation becomes correct
  */
 typedef struct {
-	uint8_t id[4];		/* 0, 1, 2, 3 */
-	uint8_t version;	/* 4 */
+#if defined(__BIG_ENDIAN)
+	uint8_t id1;		/* 1 */
+	uint8_t id0;		/* 0 */
+
+	uint8_t id3;		/* 3 */
+	uint8_t id2;		/* 2 */
+
 	/* Host/Bios Flags */
 	struct {
 		uint8_t bios_configuration_mode:2;
@@ -539,17 +716,179 @@
 		uint8_t unused_6:1;
 		uint8_t unused_7:1;
 	} cntr_flags_1;		/* 5 */
+	uint8_t version;	/* 4 */
+
 	/* Selectable Boot Support */
 	struct {
-		uint8_t boot_lun_number:5;
-		uint8_t scsi_bus_number:1;
+		uint16_t boot_lun_number:5;
+		uint16_t scsi_bus_number:1;
+		uint16_t unused_6:1;
+		uint16_t unused_7:1;
+		uint16_t boot_target_number:4;
+		uint16_t unused_12:1;
+		uint16_t unused_13:1;
+		uint16_t unused_14:1;
+		uint16_t unused_15:1;
+	} cntr_flags_2;		/* 6, 7 */
+
+	uint16_t unused_8;	/* 8, 9 */
+	uint16_t unused_10;	/* 10, 11 */
+	uint16_t unused_12;	/* 12, 13 */
+	uint16_t unused_14;	/* 14, 15 */
+
+	/* Termination
+	 * 0 = Disable, 1 = high only, 3 = Auto term
+	 */
+	union {
+		uint8_t c;
+		struct {
+			uint8_t scsi_bus_1_control:2;
+			uint8_t scsi_bus_0_control:2;
+			uint8_t unused_0:1;
+			uint8_t unused_1:1;
+			uint8_t unused_2:1;
+			uint8_t auto_term_support:1;
+		} f;
+	} termination;		/* 17 */
+	/* Auto Term - 3                          */
+	/* High Only - 1 (GPIO2 = 1 & GPIO3 = 0)  */
+	/* Disable - 0 (GPIO2 = 0 & GPIO3 = X)    */
+	/* ISP Config Parameters */
+	union {
+		uint8_t c;
+		struct {
+			uint8_t reserved:2;
+			uint8_t burst_enable:1;
+			uint8_t reserved_1:1;
+			uint8_t fifo_threshold:4;
+		} f;
+	} isp_config;		/* 16 */
+
+	uint16_t isp_parameter;	/* 18, 19 */
+
+	union {
+		uint16_t w;
+		struct {
+			uint16_t enable_fast_posting:1;
+			uint16_t report_lvd_bus_transition:1;
+			uint16_t unused_2:1;
+			uint16_t unused_3:1;
+			uint16_t unused_4:1;
+			uint16_t unused_5:1;
+			uint16_t unused_6:1;
+			uint16_t unused_7:1;
+			uint16_t unused_8:1;
+			uint16_t unused_9:1;
+			uint16_t unused_10:1;
+			uint16_t unused_11:1;
+			uint16_t unused_12:1;
+			uint16_t unused_13:1;
+			uint16_t unused_14:1;
+			uint16_t unused_15:1;
+		} f;
+	} firmware_feature;	/* 20, 21 */
+
+	uint16_t unused_22;	/* 22, 23 */
+
+	struct {
+		uint8_t bus_reset_delay;	/* 25 */
+		struct {
+			uint8_t initiator_id:4;
+			uint8_t scsi_reset_disable:1;
+			uint8_t scsi_bus_size:1;
+			uint8_t scsi_bus_type:1;
+			uint8_t unused_7:1;
+		} config_1;	/* 24 */
+
+		uint8_t retry_delay;	/* 27 */
+		uint8_t retry_count;	/* 26 */
+
+		uint8_t unused_29;	/* 29 */
+		/* Adapter Capabilities bits */
+		struct {
+			uint8_t async_data_setup_time:4;
+			uint8_t req_ack_active_negation:1;
+			uint8_t data_line_active_negation:1;
+			uint8_t unused_6:1;
+			uint8_t unused_7:1;
+		} config_2;	/* 28 */
+
+		uint16_t selection_timeout;	/* 30, 31 */
+		uint16_t max_queue_depth;	/* 32, 33 */
+
+		uint16_t unused_34;	/* 34, 35 */
+		uint16_t unused_36;	/* 36, 37 */
+		uint16_t unused_38;	/* 38, 39 */
+
+		struct {
+			uint8_t execution_throttle;	/* 41 */
+			union {
+				uint8_t c;
+				struct {
+					uint8_t renegotiate_on_error:1;
+					uint8_t stop_queue_on_check:1;
+					uint8_t auto_request_sense:1;
+					uint8_t tag_queuing:1;
+					uint8_t sync_data_transfers:1;
+					uint8_t wide_data_transfers:1;
+					uint8_t parity_checking:1;
+					uint8_t disconnect_allowed:1;
+				} f;
+			} parameter;	/* 40 */
+
+			struct {
+				uint8_t sync_offset:5;
+				uint8_t device_enable:1;
+				uint8_t unused_6:1;
+				uint8_t unused_7:1;
+			} flags1; /* 43 */
+			uint8_t sync_period;	/* 42 */
+
+			uint8_t unused_45;	/* 45 */
+			struct {
+				uint8_t ppr_options:4;
+				uint8_t ppr_bus_width:2;
+				uint8_t unused_8:1;
+				uint8_t enable_ppr:1;
+			} flags2;	/* 44 */
+
+		} target[MAX_TARGETS];
+	} bus[MAX_BUSES];
+
+	uint16_t unused_248;	/* 248, 249 */
+
+	uint16_t subsystem_id[2];	/* 250, 251, 252, 253 */
+
+	uint8_t chksum;		/* 255 */
+	uint8_t System_Id_Pointer;	/* 254 */
+
+#elif defined(__LITTLE_ENDIAN)
+	uint8_t id0;		/* 0 */
+	uint8_t id1;		/* 1 */
+	uint8_t id2;		/* 2 */
+	uint8_t id3;		/* 3 */
+	uint8_t version;	/* 4 */
+	/* Host/Bios Flags */
+	struct {
+		uint8_t bios_configuration_mode:2;
+		uint8_t bios_disable:1;
+		uint8_t selectable_scsi_boot_enable:1;
+		uint8_t cd_rom_boot_enable:1;
+		uint8_t disable_loading_risc_code:1;
 		uint8_t unused_6:1;
 		uint8_t unused_7:1;
-		uint8_t boot_target_number:4;
-		uint8_t unused_12:1;
-		uint8_t unused_13:1;
-		uint8_t unused_14:1;
-		uint8_t unused_15:1;
+	} cntr_flags_1;		/* 5 */
+	/* Selectable Boot Support */
+	struct {
+		uint16_t boot_lun_number:5;
+		uint16_t scsi_bus_number:1;
+		uint16_t unused_6:1;
+		uint16_t unused_7:1;
+		uint16_t boot_target_number:4;
+		uint16_t unused_12:1;
+		uint16_t unused_13:1;
+		uint16_t unused_14:1;
+		uint16_t unused_15:1;
 	} cntr_flags_2;		/* 6, 7 */
 
 	uint16_t unused_8;	/* 8, 9 */
@@ -591,22 +930,22 @@
 	union {
 		uint16_t w;
 		struct {
-			uint8_t enable_fast_posting:1;
-			uint8_t report_lvd_bus_transition:1;
-			uint8_t unused_2:1;
-			uint8_t unused_3:1;
-			uint8_t unused_4:1;
-			uint8_t unused_5:1;
-			uint8_t unused_6:1;
-			uint8_t unused_7:1;
-			uint8_t unused_8:1;
-			uint8_t unused_9:1;
-			uint8_t unused_10:1;
-			uint8_t unused_11:1;
-			uint8_t unused_12:1;
-			uint8_t unused_13:1;
-			uint8_t unused_14:1;
-			uint8_t unused_15:1;
+			uint16_t enable_fast_posting:1;
+			uint16_t report_lvd_bus_transition:1;
+			uint16_t unused_2:1;
+			uint16_t unused_3:1;
+			uint16_t unused_4:1;
+			uint16_t unused_5:1;
+			uint16_t unused_6:1;
+			uint16_t unused_7:1;
+			uint16_t unused_8:1;
+			uint16_t unused_9:1;
+			uint16_t unused_10:1;
+			uint16_t unused_11:1;
+			uint16_t unused_12:1;
+			uint16_t unused_13:1;
+			uint16_t unused_14:1;
+			uint16_t unused_15:1;
 		} f;
 	} firmware_feature;	/* 20, 21 */
 
@@ -665,11 +1004,14 @@
 				uint8_t device_enable:1;
 				uint8_t unused_6:1;
 				uint8_t unused_7:1;
+			} flags1; /* 43 */
+
+			struct {
 				uint8_t ppr_options:4;
 				uint8_t ppr_bus_width:2;
 				uint8_t unused_8:1;
 				uint8_t enable_ppr:1;
-			} flags;	/* 43, 44 */
+			} flags2;	/* 43 */
 
 			uint8_t unused_45;	/* 45 */
 		} target[MAX_TARGETS];
@@ -682,6 +1024,9 @@
 	uint8_t System_Id_Pointer;	/* 254 */
 
 	uint8_t chksum;		/* 255 */
+#else
+#error neither __BIG_ENDIAN nor __LITTLE_ENDIAN is defined
+#endif
 } nvram160_t;
 
 /*
@@ -1306,7 +1651,6 @@
 /*
  *  Linux - SCSI Driver Interface Function Prototypes.
  */
-int qla1280_proc_info(char *, char **, off_t, int, int, int);
 const char *qla1280_info(struct Scsi_Host *host);
 int qla1280_detect(Scsi_Host_Template *);
 int qla1280_release(struct Scsi_Host *);
diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
--- a/drivers/scsi/scsi.h	Wed May  7 07:15:38 2003
+++ b/drivers/scsi/scsi.h	Mon May 26 14:53:23 2003
@@ -383,12 +383,14 @@
 				 * time. */
 	unsigned was_reset:1;	/* There was a bus reset on the bus for 
 				 * this device */
-	unsigned expecting_cc_ua:1;	/* Expecting a CHECK_CONDITION/UNIT_ATTN
-					 * because we did a bus reset. */
-	unsigned ten:1;		/* support ten byte read / write */
+	unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN
+				     * because we did a bus reset. */
+	unsigned use_10_for_rw:1; /* first try 10-byte read / write */
+	unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */
 	unsigned remap:1;	/* support remapping  */
 //	unsigned sync:1;	/* Sync transfer state, managed by host */
 //	unsigned wide:1;	/* WIDE transfer state, managed by host */
+	unsigned no_start_on_add:1;	/* do not issue start on add */
 
 	unsigned int device_blocked;	/* Device returned QUEUE_FULL. */
 
@@ -402,10 +404,6 @@
 	container_of(d, struct scsi_device, sdev_driverfs_dev)
 
 
-/*
- * The Scsi_Cmnd structure is used by scsi.c internally, and for communication
- * with low level drivers that support multiple outstanding commands.
- */
 typedef struct scsi_pointer {
 	char *ptr;		/* data pointer */
 	int this_residual;	/* left in this buffer */
@@ -458,12 +456,13 @@
 };
 
 /*
- * FIXME(eric) - one of the great regrets that I have is that I failed to define
- * these structure elements as something like sc_foo instead of foo.  This would
- * make it so much easier to grep through sources and so forth.  I propose that
- * all new elements that get added to these structures follow this convention.
- * As time goes on and as people have the stomach for it, it should be possible to 
- * go back and retrofit at least some of the elements here with with the prefix.
+ * FIXME(eric) - one of the great regrets that I have is that I failed to
+ * define these structure elements as something like sc_foo instead of foo.
+ * This would make it so much easier to grep through sources and so forth.
+ * I propose that all new elements that get added to these structures follow
+ * this convention.  As time goes on and as people have the stomach for it,
+ * it should be possible to go back and retrofit at least some of the elements
+ * here with with the prefix.
  */
 struct scsi_cmnd {
 	int     sc_magic;
@@ -682,5 +681,10 @@
 }
 
 int scsi_set_medium_removal(Scsi_Device *dev, char state);
+
+extern int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs,
+					    struct device_attribute *attr);
+extern int scsi_sysfs_modify_shost_attribute(struct class_device_attribute ***class_attrs,
+					     struct class_device_attribute *attr);
 
 #endif /* _SCSI_H */
diff -Nru a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
--- a/drivers/scsi/scsi_debug.c	Thu May  8 15:46:47 2003
+++ b/drivers/scsi/scsi_debug.c	Mon May 12 07:26:14 2003
@@ -1259,8 +1259,8 @@
 /* scsi_debug_proc_info
  * Used if the driver currently has no own support for /proc/scsi
  */
-static int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
-				int length, int inode, int inout)
+static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+				int length, int inout)
 {
 	int len, pos, begin;
 	int orig_length;
diff -Nru a/drivers/scsi/scsi_debug.h b/drivers/scsi/scsi_debug.h
--- a/drivers/scsi/scsi_debug.h	Thu May  8 15:46:47 2003
+++ b/drivers/scsi/scsi_debug.h	Mon May 12 07:26:14 2003
@@ -14,7 +14,7 @@
 static int scsi_debug_bus_reset(struct scsi_cmnd *);
 static int scsi_debug_device_reset(struct scsi_cmnd *);
 static int scsi_debug_host_reset(struct scsi_cmnd *);
-static int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
+static int scsi_debug_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
 static const char * scsi_debug_info(struct Scsi_Host *);
 
 /*
diff -Nru a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
--- a/drivers/scsi/scsi_devinfo.c	Thu May  8 15:35:53 2003
+++ b/drivers/scsi/scsi_devinfo.c	Fri May 23 04:01:50 2003
@@ -131,7 +131,7 @@
 	{"EMULEX", "MD21/S2     ESDI", NULL, BLIST_SINGLELUN},
 	{"CANON", "IPUBJD", NULL, BLIST_SPARSELUN},
 	{"nCipher", "Fastness Crypto", NULL, BLIST_FORCELUN},
-	{"DEC", "HSG80", NULL, BLIST_FORCELUN},
+	{"DEC", "HSG80", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
 	{"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN},
 	{"COMPAQ", "CR3500", NULL, BLIST_FORCELUN},
 	{"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
@@ -159,7 +159,10 @@
 	{"HP", "NetRAID-4M", NULL, BLIST_FORCELUN},
 	{"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN},
 	{"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN},
-	{"COMPAQ", "MSA1000", NULL, BLIST_FORCELUN},
+	{"COMPAQ", "MSA1000", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
+	{"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
+	{"COMPAQ", "HSV110", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
+	{"HP", "HSV100", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
 	{"HP", "C1557A", NULL, BLIST_FORCELUN},
 	{"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN},
 	{"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
diff -Nru a/drivers/scsi/scsi_devinfo.h b/drivers/scsi/scsi_devinfo.h
--- a/drivers/scsi/scsi_devinfo.h	Thu May  1 11:29:55 2003
+++ b/drivers/scsi/scsi_devinfo.h	Fri May 23 04:01:50 2003
@@ -14,3 +14,4 @@
 #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 */
+#define BLIST_NOSTARTONADD      0x1000  /* do not do automatic start on add */
diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c	Thu May  8 12:14:09 2003
+++ b/drivers/scsi/scsi_lib.c	Fri May 23 03:02:30 2003
@@ -662,7 +662,6 @@
  *
  *		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)
@@ -796,17 +795,20 @@
 				}
 			}
 		}
-		/* If we had an ILLEGAL REQUEST returned, then we may have
-		 * performed an unsupported command.  The only thing this should be
-		 * would be a ten byte read where only a six byte read was supported.
-		 * Also, on a system where READ CAPACITY failed, we have have read
-		 * past the end of the disk.
+		/*
+		 * If we had an ILLEGAL REQUEST returned, then we may have
+		 * performed an unsupported command.  The only thing this
+		 * should be would be a ten byte read where only a six byte
+		 * read was supported.  Also, on a system where READ CAPACITY
+		 * failed, we may have read past the end of the disk.
 		 */
 
 		switch (cmd->sense_buffer[2]) {
 		case ILLEGAL_REQUEST:
-			if (cmd->device->ten) {
-				cmd->device->ten = 0;
+			if (cmd->device->use_10_for_rw &&
+			    (cmd->cmnd[0] == READ_10 ||
+			     cmd->cmnd[0] == WRITE_10)) {
+				cmd->device->use_10_for_rw = 0;
 				/*
 				 * This will cause a retry with a 6-byte
 				 * command.
diff -Nru a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
--- a/drivers/scsi/scsi_priv.h	Sun May 11 15:12:54 2003
+++ b/drivers/scsi/scsi_priv.h	Thu May 29 22:42:36 2003
@@ -59,6 +59,8 @@
 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 struct Scsi_Host *scsi_host_hn_get(unsigned short);
+extern void scsi_host_put(struct Scsi_Host *);
 extern void scsi_host_init(void);
 
 /* scsi.c */
@@ -108,7 +110,7 @@
 # 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)
+# define scsi_exit_procfs()		do { } while (0)
 #endif /* CONFIG_PROC_FS */
 
 /* scsi_scan.c */
@@ -128,5 +130,10 @@
 extern void scsi_sysfs_remove_host(struct Scsi_Host *);
 extern int scsi_sysfs_register(void);
 extern void scsi_sysfs_unregister(void);
+
+/* definitions for the linker default sections covering the host
+ * class and device attributes */
+extern struct class_device_attribute *scsi_sysfs_shost_attrs[];
+extern struct device_attribute *scsi_sysfs_sdev_attrs[];
 
 #endif /* _SCSI_PRIV_H */
diff -Nru a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
--- a/drivers/scsi/scsi_proc.c	Thu May  8 11:24:15 2003
+++ b/drivers/scsi/scsi_proc.c	Mon May 12 07:26:15 2003
@@ -79,8 +79,8 @@
 		n = generic_proc_info(buffer, start, offset, length,
 				      shost->hostt->info, shost);
 	else
-		n = (shost->hostt->proc_info(buffer, start, offset,
-					   length, shost->host_no, 0));
+		n = shost->hostt->proc_info(shost, buffer, start, offset,
+					   length, 0);
 
 	*eof = (n < length);
 	return n;
@@ -104,8 +104,7 @@
 		ret = -EFAULT;
 		if (copy_from_user(page, buf, count))
 			goto out;
-		ret = shost->hostt->proc_info(page, &start, 0, count,
-					      shost->host_no, 1);
+		ret = shost->hostt->proc_info(shost, page, &start, 0, count, 1);
 	}
 out:
 	free_page((unsigned long)page);
diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
--- a/drivers/scsi/scsi_scan.c	Thu May  8 11:24:15 2003
+++ b/drivers/scsi/scsi_scan.c	Fri May 23 04:01:50 2003
@@ -641,6 +641,13 @@
 		sdev->borken = 0;
 
 	/*
+	 * Some devices may not want to have a start command automatically
+	 * issued when a device is added.
+	 */
+	if (*bflags & BLIST_NOSTARTONADD)
+		sdev->no_start_on_add = 1;
+
+	/*
 	 * If we need to allow I/O to only one of the luns attached to
 	 * this target id at a time set single_lun, and allocate or modify
 	 * sdev_target.
diff -Nru a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c
--- a/drivers/scsi/scsi_syms.c	Thu May  8 11:24:15 2003
+++ b/drivers/scsi/scsi_syms.c	Mon May 12 07:26:15 2003
@@ -89,11 +89,6 @@
  */
 EXPORT_SYMBOL(scsi_reset_provider);
 
-/*
- * These are here only while I debug the rest of the scsi stuff.
- */
-EXPORT_SYMBOL(scsi_host_hn_get);
-EXPORT_SYMBOL(scsi_host_put);
 EXPORT_SYMBOL(scsi_device_types);
 
 /*
diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
--- a/drivers/scsi/scsi_sysfs.c	Sun May 11 15:12:40 2003
+++ b/drivers/scsi/scsi_sysfs.c	Mon May 26 14:47:09 2003
@@ -45,12 +45,13 @@
 shost_rd_attr(sg_tablesize, "%hu\n");
 shost_rd_attr(unchecked_isa_dma, "%d\n");
 
-static struct class_device_attribute *const shost_attrs[] = {
+struct class_device_attribute *scsi_sysfs_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,
+	NULL
 };
 
 static struct class shost_class = {
@@ -243,7 +244,8 @@
 
 static DEVICE_ATTR(rescan, S_IRUGO | S_IWUSR, show_rescan_field, store_rescan_field)
 
-static struct device_attribute * const sdev_attrs[] = {
+/* Default template for device attributes.  May NOT be modified */
+struct device_attribute *scsi_sysfs_sdev_attrs[] = {
 	&dev_attr_device_blocked,
 	&dev_attr_queue_depth,
 	&dev_attr_type,
@@ -254,6 +256,7 @@
 	&dev_attr_rev,
 	&dev_attr_online,
 	&dev_attr_rescan,
+	NULL
 };
 
 static void scsi_device_release(struct device *dev)
@@ -287,9 +290,9 @@
 	if (error)
 		return error;
 
-	for (i = 0; !error && i < ARRAY_SIZE(sdev_attrs); i++)
+	for (i = 0; !error && sdev->host->hostt->sdev_attrs[i] != NULL; i++)
 		error = device_create_file(&sdev->sdev_driverfs_dev,
-					   sdev_attrs[i]);
+					   sdev->host->hostt->sdev_attrs[i]);
 
 	if (error)
 		scsi_device_unregister(sdev);
@@ -305,8 +308,8 @@
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(sdev_attrs); i++)
-		device_remove_file(&sdev->sdev_driverfs_dev, sdev_attrs[i]);
+	for (i = 0; sdev->host->hostt->sdev_attrs[i] != NULL; i++)
+		device_remove_file(&sdev->sdev_driverfs_dev, sdev->host->hostt->sdev_attrs[i]);
 	device_unregister(&sdev->sdev_driverfs_dev);
 }
 
@@ -357,9 +360,9 @@
 	if (error)
 		goto clean_device;
 
-	for (i = 0; !error && i < ARRAY_SIZE(shost_attrs); i++)
+	for (i = 0; !error && shost->hostt->shost_attrs[i] != NULL; i++)
 		error = class_device_create_file(&shost->class_dev,
-					   shost_attrs[i]);
+					   shost->hostt->shost_attrs[i]);
 	if (error)
 		goto clean_class;
 
@@ -383,3 +386,118 @@
 	device_del(&shost->host_gendev);
 }
 
+/** scsi_sysfs_modify_shost_attribute - modify or add a host class attribute
+ *
+ * @class_attrs:host class attribute list to be added to or modified
+ * @attr:	individual attribute to change or added
+ *
+ * returns zero if successful or error if not
+ **/
+int scsi_sysfs_modify_shost_attribute(struct class_device_attribute ***class_attrs,
+				      struct class_device_attribute *attr)
+{
+	int modify = 0;
+	int num_attrs;
+
+	if(*class_attrs == NULL)
+		*class_attrs = scsi_sysfs_shost_attrs;
+
+	for(num_attrs=0; (*class_attrs)[num_attrs] != NULL; num_attrs++)
+		if(strcmp((*class_attrs)[num_attrs]->attr.name, attr->attr.name) == 0)
+			modify = num_attrs;
+
+	if(*class_attrs == scsi_sysfs_shost_attrs || !modify) {
+		/* note: need space for null at the end as well */
+		struct class_device_attribute **tmp_attrs = kmalloc(sizeof(struct class_device_attribute)*(num_attrs + (modify ? 1 : 2)), GFP_KERNEL);
+		if(tmp_attrs == NULL)
+			return -ENOMEM;
+		memcpy(tmp_attrs, *class_attrs, sizeof(struct class_device_attribute)*num_attrs);
+		if(*class_attrs != scsi_sysfs_shost_attrs)
+			kfree(*class_attrs);
+		*class_attrs = tmp_attrs;
+	}
+	if(modify) {
+		/* spare the caller from having to copy things it's
+		 * not interested in */
+		struct class_device_attribute *old_attr =
+			(*class_attrs)[modify];
+		/* extend permissions */
+		attr->attr.mode |= old_attr->attr.mode;
+
+		/* override null show/store with default */
+		if(attr->show == NULL)
+			attr->show = old_attr->show;
+		if(attr->store == NULL)
+			attr->store = old_attr->store;
+		(*class_attrs)[modify] = attr;
+	} else {
+		(*class_attrs)[num_attrs++] = attr;
+		(*class_attrs)[num_attrs] = NULL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(scsi_sysfs_modify_shost_attribute);
+
+/** scsi_sysfs_modify_sdev_attribute - modify or add a host device attribute
+ *
+ * @dev_attrs:	pointer to the attribute list to be added to or modified
+ * @attr:	individual attribute to change or added
+ *
+ * returns zero if successful or error if not
+ **/
+int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs,
+				     struct device_attribute *attr)
+{
+	int modify = 0;
+	int num_attrs;
+
+	if(*dev_attrs == NULL)
+		*dev_attrs = scsi_sysfs_sdev_attrs;
+
+	for(num_attrs=0; (*dev_attrs)[num_attrs] != NULL; num_attrs++)
+		if(strcmp((*dev_attrs)[num_attrs]->attr.name, attr->attr.name) == 0)
+			modify = num_attrs;
+
+	if(*dev_attrs == scsi_sysfs_sdev_attrs || !modify) {
+		/* note: need space for null at the end as well */
+		struct device_attribute **tmp_attrs = kmalloc(sizeof(struct device_attribute)*(num_attrs + (modify ? 1 : 2)), GFP_KERNEL);
+		if(tmp_attrs == NULL)
+			return -ENOMEM;
+		memcpy(tmp_attrs, *dev_attrs, sizeof(struct device_attribute)*num_attrs);
+		if(*dev_attrs != scsi_sysfs_sdev_attrs)
+			kfree(*dev_attrs);
+		*dev_attrs = tmp_attrs;
+	}
+	if(modify) {
+		/* spare the caller from having to copy things it's
+		 * not interested in */
+		struct device_attribute *old_attr =
+			(*dev_attrs)[modify];
+		/* extend permissions */
+		attr->attr.mode |= old_attr->attr.mode;
+
+		/* override null show/store with default */
+		if(attr->show == NULL)
+			attr->show = old_attr->show;
+		if(attr->store == NULL)
+			attr->store = old_attr->store;
+		(*dev_attrs)[modify] = attr;
+	} else {
+		(*dev_attrs)[num_attrs++] = attr;
+		(*dev_attrs)[num_attrs] = NULL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(scsi_sysfs_modify_sdev_attribute);
+
+void scsi_sysfs_release_attributes(struct SHT *hostt)
+{
+	if(hostt->sdev_attrs != scsi_sysfs_sdev_attrs)
+		kfree(hostt->sdev_attrs);
+
+	if(hostt->shost_attrs != scsi_sysfs_shost_attrs)
+		kfree(hostt->shost_attrs);
+}
+EXPORT_SYMBOL(scsi_sysfs_release_attributes);
diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c
--- a/drivers/scsi/sd.c	Mon May 12 20:52:56 2003
+++ b/drivers/scsi/sd.c	Fri May 23 04:01:50 2003
@@ -320,7 +320,8 @@
 		SCpnt->cmnd[12] = (unsigned char) (this_count >> 8) & 0xff;
 		SCpnt->cmnd[13] = (unsigned char) this_count & 0xff;
 		SCpnt->cmnd[14] = SCpnt->cmnd[15] = 0;
-	} else if (((this_count > 0xff) || (block > 0x1fffff)) || SCpnt->device->ten) {
+	} else if ((this_count > 0xff) || (block > 0x1fffff) ||
+		   SCpnt->device->use_10_for_rw) {
 		if (this_count > 0xffff)
 			this_count = 0xffff;
 
@@ -768,11 +769,14 @@
 			break;
 
 		case ILLEGAL_REQUEST:
-			if (SCpnt->device->ten == 1) {
-				if (SCpnt->cmnd[0] == READ_10 ||
-				    SCpnt->cmnd[0] == WRITE_10)
-					SCpnt->device->ten = 0;
-			}
+			if (SCpnt->device->use_10_for_rw &&
+			    (SCpnt->cmnd[0] == READ_10 ||
+			     SCpnt->cmnd[0] == WRITE_10))
+				SCpnt->device->use_10_for_rw = 0;
+			if (SCpnt->device->use_10_for_ms &&
+			    (SCpnt->cmnd[0] == MODE_SENSE_10 ||
+			     SCpnt->cmnd[0] == MODE_SELECT_10))
+				SCpnt->device->use_10_for_ms = 0;
 			break;
 
 		default:
@@ -835,9 +839,10 @@
 
 			the_result = SRpnt->sr_result;
 			retries++;
-		} while (retries < 3 && !scsi_status_is_good(the_result)
-			 && ((driver_byte(the_result) & DRIVER_SENSE)
-			     && SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION));
+		} 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
@@ -855,7 +860,12 @@
 			break;
 		}
 					
-					
+		/*
+		 * The device does not want the automatic start to be issued.
+		 */
+		if (sdkp->device->no_start_on_add) {
+			break;
+		}
 
 		/*
 		 * If manual intervention is required, or this is an
@@ -1093,16 +1103,29 @@
 	sdkp->device->sector_size = sector_size;
 }
 
+/* called with buffer of length 512 */
 static int
-sd_do_mode_sense6(struct scsi_device *sdp, struct scsi_request *SRpnt,
-		  int dbd, int modepage, unsigned char *buffer, int len) {
-	unsigned char cmd[8];
+sd_do_mode_sense(struct scsi_request *SRpnt, int dbd, int modepage,
+		 unsigned char *buffer, int len) {
+	unsigned char cmd[12];
 
-	memset((void *) &cmd[0], 0, 8);
-	cmd[0] = MODE_SENSE;
+	memset((void *) &cmd[0], 0, 12);
 	cmd[1] = dbd;
 	cmd[2] = modepage;
-	cmd[4] = len;
+
+	if (SRpnt->sr_device->use_10_for_ms) {
+		if (len < 8)
+			len = 8;
+
+		cmd[0] = MODE_SENSE_10;
+		cmd[8] = len;
+	} else {
+		if (len < 4)
+			len = 4;
+
+		cmd[0] = MODE_SENSE;
+		cmd[4] = len;
+	}
 
 	SRpnt->sr_cmd_len = 0;
 	SRpnt->sr_sense_buffer[0] = 0;
@@ -1119,11 +1142,11 @@
 
 /*
  * read write protect setting, if possible - called only in sd_init_onedisk()
+ * called with buffer of length 512
  */
 static void
 sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
 		   struct scsi_request *SRpnt, unsigned char *buffer) {
-	struct scsi_device *sdp = sdkp->device;
 	int res;
 
 	/*
@@ -1131,7 +1154,7 @@
 	 * We have to start carefully: some devices hang if we ask
 	 * for more than is available.
 	 */
-	res = sd_do_mode_sense6(sdp, SRpnt, 0, 0x3F, buffer, 4);
+	res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 4);
 
 	/*
 	 * Second attempt: ask for page 0
@@ -1139,13 +1162,13 @@
 	 * Sense Key 5: Illegal Request, Sense Code 24: Invalid field in CDB.
 	 */
 	if (res)
-		res = sd_do_mode_sense6(sdp, SRpnt, 0, 0, buffer, 4);
+		res = sd_do_mode_sense(SRpnt, 0, 0, buffer, 4);
 
 	/*
 	 * Third attempt: ask 255 bytes, as we did earlier.
 	 */
 	if (res)
-		res = sd_do_mode_sense6(sdp, SRpnt, 0, 0x3F, buffer, 255);
+		res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 255);
 
 	if (res) {
 		printk(KERN_WARNING
@@ -1161,25 +1184,25 @@
 
 /*
  * sd_read_cache_type - called only from sd_init_onedisk()
+ * called with buffer of length 512
  */
 static void
 sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
 		   struct scsi_request *SRpnt, unsigned char *buffer) {
-	struct scsi_device *sdp = sdkp->device;
 	int len = 0, res;
 
 	const int dbd = 0x08;	   /* DBD */
 	const int modepage = 0x08; /* current values, cache page */
 
 	/* cautiously ask */
-	res = sd_do_mode_sense6(sdp, SRpnt, dbd, modepage, buffer, 4);
+	res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, 4);
 
 	if (res == 0) {
 		/* that went OK, now ask for the proper length */
 		len = buffer[0] + 1;
 		if (len > 128)
 			len = 128;
-		res = sd_do_mode_sense6(sdp, SRpnt, dbd, modepage, buffer, len);
+		res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, len);
 	}
 
 	if (res == 0 && buffer[3] + 6 < len) {
@@ -1278,7 +1301,8 @@
 	if (sdkp->media_present)
 		sd_read_cache_type(sdkp, disk->disk_name, SRpnt, buffer);
 		
-	SRpnt->sr_device->ten = 1;
+	SRpnt->sr_device->use_10_for_rw = 1;
+	SRpnt->sr_device->use_10_for_ms = 0;
 	SRpnt->sr_device->remap = 1;
 
  leave:
diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c
--- a/drivers/scsi/sr.c	Wed May  7 07:15:41 2003
+++ b/drivers/scsi/sr.c	Fri May 23 03:02:30 2003
@@ -559,7 +559,8 @@
 	sprintf(cd->cdi.name, "sr%d", minor);
 
 	sdev->sector_size = 2048;	/* A guess, just in case */
-	sdev->ten = 1;
+	sdev->use_10_for_rw = 1;
+	sdev->use_10_for_ms = 0;
 	sdev->remap = 1;
 
 	/* FIXME: need to handle a get_capabilities failure properly ?? */
diff -Nru a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
--- a/drivers/scsi/sun3_NCR5380.c	Fri May  9 03:21:35 2003
+++ b/drivers/scsi/sun3_NCR5380.c	Mon May 26 18:54:39 2003
@@ -726,7 +726,7 @@
 	printk("NCR5380_print_status: no memory for print buffer\n");
 	return;
     }
-    len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0);
+    len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0);
     pr_bfr[len] = 0;
     printk("\n%s\n", pr_bfr);
     free_page((unsigned long) pr_bfr);
@@ -754,11 +754,10 @@
 static
 char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
 
-static int NCR5380_proc_info (char *buffer, char **start, off_t offset,
-			      int length, int hostno, int inout)
+static int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, off_t offset,
+			      int length, int inout)
 {
     char *pos = buffer;
-    struct Scsi_Host *instance;
     struct NCR5380_hostdata *hostdata;
     Scsi_Cmnd *ptr;
     unsigned long flags;
@@ -771,9 +770,6 @@
 	}					\
     } while (0)
 
-    instance = scsi_host_hn_get(hostno);
-    if (!instance)
-	return(-ESRCH);
     hostdata = (struct NCR5380_hostdata *)instance->hostdata;
 
     if (inout) { /* Has data been written to the file ? */
diff -Nru a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h
--- a/drivers/scsi/sun3_scsi.h	Fri Feb  7 14:02:17 2003
+++ b/drivers/scsi/sun3_scsi.h	Mon May 12 07:26:15 2003
@@ -57,8 +57,6 @@
 static const char *sun3scsi_info (struct Scsi_Host *);
 static int sun3scsi_bus_reset(Scsi_Cmnd *);
 static int sun3scsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-static int sun3scsi_proc_info (char *buffer, char **start, off_t offset,
-			int length, int hostno, int inout);
 #ifdef MODULE
 static int sun3scsi_release (struct Scsi_Host *);
 #else
diff -Nru a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c
--- a/drivers/scsi/sym53c8xx.c	Sun May 25 17:00:00 2003
+++ b/drivers/scsi/sym53c8xx.c	Mon May 26 18:54:40 2003
@@ -1288,8 +1288,8 @@
 };
 #endif
 #ifdef SCSI_NCR_PROC_INFO_SUPPORT
-static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset,
-			int length, int hostno, int func);
+static int sym53c8xx_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+			int length, int func);
 #endif
 
 /*
@@ -14226,22 +14226,17 @@
 **	- func = 1 means write (parse user control command)
 */
 
-static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset,
-			int length, int hostno, int func)
+static int sym53c8xx_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+			int length, int func)
 {
-	struct Scsi_Host *host;
 	struct host_data *host_data;
 	ncb_p ncb = 0;
 	int retv;
 
 #ifdef DEBUG_PROC_INFO
-printk("sym53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func);
+printk("sym53c8xx_proc_info: hostno=%d, func=%d\n", host->host_no, func);
 #endif
 
-	host = scsi_host_hn_get(hostno);
-	if (!host)
-		return -EINVAL;
-
 	host_data = (struct host_data *) host->hostdata;
 	ncb = host_data->ncb;
 	retv = -EINVAL;
@@ -14261,7 +14256,6 @@
 	}
 
 out:
-	scsi_host_put(host);
 	return retv;
 }
 
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	Sun May 25 17:00:00 2003
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c	Mon May 26 18:54:41 2003
@@ -1787,18 +1787,13 @@
  *  - func = 0 means read  (returns adapter infos)
  *  - func = 1 means write (not yet merget from sym53c8xx)
  */
-static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset,
-			int length, int hostno, int func)
+static int sym53c8xx_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+			int length, int func)
 {
-	struct Scsi_Host *host;
 	struct host_data *host_data;
 	hcb_p np = 0;
 	int retv;
 
-	host = scsi_host_hn_get(hostno);
-	if (!host)
-		return -EINVAL;
-
 	host_data = (struct host_data *) host->hostdata;
 	np = host_data->ncb;
 	if (!np)
@@ -1821,7 +1816,6 @@
 #endif
 	}
 
-	scsi_host_put(host);
 	return retv;
 }
 #endif /* SYM_LINUX_PROC_INFO_SUPPORT */
diff -Nru a/drivers/scsi/t128.h b/drivers/scsi/t128.h
--- a/drivers/scsi/t128.h	Sun May  4 02:56:46 2003
+++ b/drivers/scsi/t128.h	Mon May 12 07:26:16 2003
@@ -99,8 +99,6 @@
 static int t128_host_reset(Scsi_Cmnd *);
 static int t128_bus_reset(Scsi_Cmnd *);
 static int t128_device_reset(Scsi_Cmnd *);
-static int t128_proc_info (char *buffer, char **start, off_t offset,
-		   int length, int hostno, int inout);
 
 #ifndef NULL
 #define NULL 0
diff -Nru a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
--- a/drivers/scsi/tmscsim.c	Sun May  4 02:56:46 2003
+++ b/drivers/scsi/tmscsim.c	Mon May 12 07:26:16 2003
@@ -2855,12 +2855,11 @@
  else SPRINTF(" No  ")
 
 
-int DC390_proc_info (char *buffer, char **start,
-		     off_t offset, int length, int hostno, int inout)
+int DC390_proc_info (struct Scsi_Host *shpnt, char *buffer, char **start,
+		     off_t offset, int length, int inout)
 {
   int dev, spd, spd1;
   char *pos = buffer;
-  PSH shpnt = 0;
   PACB pACB;
   PDCB pDCB;
   PSCSICMD pcmd;
@@ -2870,13 +2869,12 @@
 
   while(pACB != (PACB)-1)
      {
-	shpnt = pACB->pScsiHost;
-	if (shpnt->host_no == hostno) break;
+	if (shpnt == pACB->pScsiHost)
+		break;
 	pACB = pACB->pNextACB;
      }
 
   if (pACB == (PACB)-1) return(-ESRCH);
-  if(!shpnt) return(-ESRCH);
 
   if(inout) /* Has data been written to the file ? */
       return dc390_set_info(buffer, length, pACB);
diff -Nru a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
--- a/drivers/scsi/wd33c93.c	Sat Mar 22 18:30:53 2003
+++ b/drivers/scsi/wd33c93.c	Mon May 12 07:26:16 2003
@@ -1913,7 +1913,7 @@
 }
 
 int
-wd33c93_proc_info(char *buf, char **start, off_t off, int len, int hn, int in)
+wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off, int len, int in)
 {
 
 #ifdef PROC_INTERFACE
@@ -1921,16 +1921,10 @@
 	char *bp;
 	char tbuf[128];
 	struct Scsi_Host *instance;
-	struct WD33C93_hostdata *hd;
 	Scsi_Cmnd *cmd;
 	int x, i;
 	static int stop = 0;
 
-	instance = scsi_host_hn_get(hn);
-	if (!instance) {
-		printk("*** Hmm... Can't find host #%d!\n", hn);
-		return (-ESRCH);
-	}
 	hd = (struct WD33C93_hostdata *) instance->hostdata;
 
 /* If 'in' is TRUE we need to _read_ the proc file. We accept the following
diff -Nru a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h
--- a/drivers/scsi/wd33c93.h	Wed Mar 12 21:38:15 2003
+++ b/drivers/scsi/wd33c93.h	Mon May 12 07:26:16 2003
@@ -338,7 +338,7 @@
 int wd33c93_abort (Scsi_Cmnd *cmd);
 int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
 void wd33c93_intr (struct Scsi_Host *instance);
-int wd33c93_proc_info(char *, char **, off_t, int, int, int);
+int wd33c93_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
 int wd33c93_host_reset (Scsi_Cmnd *);
 void wd33c93_release(void);
 
diff -Nru a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
--- a/drivers/scsi/wd7000.c	Thu May  8 11:24:15 2003
+++ b/drivers/scsi/wd7000.c	Mon May 12 08:12:55 2003
@@ -1372,45 +1372,24 @@
 }
 
 
-static int wd7000_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+static int wd7000_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length,  int inout)
 {
-	struct Scsi_Host *host = NULL;
-	Adapter *adapter;
+	Adapter *adapter = (Adapter *)host->hostdata;
 	unsigned long flags;
 	char *pos = buffer;
-	short i;
-
 #ifdef WD7000_DEBUG
 	Mailbox *ogmbs, *icmbs;
 	short count;
 #endif
 
 	/*
-	 * Find the specified host board.
-	 */
-	for (i = 0; i < UNITS; i++)
-		if (wd7000_host[i] && (wd7000_host[i]->host_no == hostno)) {
-			host = wd7000_host[i];
-
-			break;
-		}
-
-	/*
-	 * Host not found!
-	 */
-	if (!host)
-		return (-ESRCH);
-
-	/*
 	 * Has data been written to the file ?
 	 */
 	if (inout)
 		return (wd7000_set_info(buffer, length, host));
 
-	adapter = (Adapter *) host->hostdata;
-
 	spin_lock_irqsave(host->host_lock, flags);
-	SPRINTF("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", hostno, adapter->rev1, adapter->rev2);
+	SPRINTF("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", host->host_no, adapter->rev1, adapter->rev2);
 	SPRINTF("  IO base:      0x%x\n", adapter->iobase);
 	SPRINTF("  IRQ:          %d\n", adapter->irq);
 	SPRINTF("  DMA channel:  %d\n", adapter->dma);
diff -Nru a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
--- a/drivers/serial/68328serial.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/serial/68328serial.c	Mon May 26 15:29:13 2003
@@ -83,13 +83,12 @@
 extern wait_queue_head_t keypress_wait; 
 #endif
 
-struct tty_driver serial_driver, callout_driver;
+struct tty_driver serial_driver;
 static int serial_refcount;
 
 /* serial subtype definitions */
 #define SERIAL_TYPE_NORMAL	1
-#define SERIAL_TYPE_CALLOUT	2
-  
+ 
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
@@ -1178,8 +1177,6 @@
 	 */
 	if (info->flags & S_NORMAL_ACTIVE)
 		info->normal_termios = *tty->termios;
-	if (info->flags & S_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -1220,8 +1217,7 @@
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(S_NORMAL_ACTIVE|S_CALLOUT_ACTIVE|
-			 S_CLOSING);
+	info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	restore_flags(flags);
 }
@@ -1240,7 +1236,7 @@
 	shutdown(info);
 	info->event = 0;
 	info->count = 0;
-	info->flags &= ~(S_NORMAL_ACTIVE|S_CALLOUT_ACTIVE);
+	info->flags &= ~S_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -1272,25 +1268,6 @@
 		return -EAGAIN;
 #endif
 	}
-
-	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & S_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & S_CALLOUT_ACTIVE) &&
-		    (info->flags & S_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & S_CALLOUT_ACTIVE) &&
-		    (info->flags & S_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= S_CALLOUT_ACTIVE;
-		return 0;
-	}
 	
 	/*
 	 * If non-blocking mode is set, or the port is not enabled,
@@ -1298,20 +1275,13 @@
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & S_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= S_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & S_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -1326,8 +1296,7 @@
 	info->blocked_open++;
 	while (1) {
 		cli();
-		if (!(info->flags & S_CALLOUT_ACTIVE))
-			m68k_rtsdtr(info, 1);
+		m68k_rtsdtr(info, 1);
 		sti();
 		current->state = TASK_INTERRUPTIBLE;
 		if (tty_hung_up_p(filp) ||
@@ -1342,8 +1311,7 @@
 #endif
 			break;
 		}
-		if (!(info->flags & S_CALLOUT_ACTIVE) &&
-		    !(info->flags & S_CLOSING) && do_clocal)
+		if (!(info->flags & S_CLOSING) && do_clocal)
 			break;
                 if (signal_pending(current)) {
 			retval = -ERESTARTSYS;
@@ -1401,16 +1369,10 @@
 	}
 
 	if ((info->count == 1) && (info->flags & S_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->normal_termios;
-		else 
-			*tty->termios = info->callout_termios;
+		*tty->termios = info->normal_termios;
 		change_speed(info);
 	}
 
-	info->session = current->session;
-	info->pgrp = current->pgrp;
-
 	return 0;
 }
 
@@ -1519,20 +1481,9 @@
 	serial_driver.hangup = rs_hangup;
 	serial_driver.set_ldisc = rs_set_ldisc;
 
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	callout_driver = serial_driver;
-	callout_driver.name = "cua";
-	callout_driver.major = TTYAUX_MAJOR;
-	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-
 	if (tty_register_driver(&serial_driver))
 		panic("Couldn't register serial driver\n");
-	if (tty_register_driver(&callout_driver))
-		panic("Couldn't register callout driver\n");
-	
+
 	save_flags(flags); cli();
 
 	for(i=0;i<NR_PORTS;i++) {
@@ -1551,7 +1502,6 @@
 	    info->blocked_open = 0;
 	    INIT_WORK(&info->tqueue, do_softint, info);
 	    INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
-	    info->callout_termios =callout_driver.init_termios;
 	    info->normal_termios = serial_driver.init_termios;
 	    init_waitqueue_head(&info->open_wait);
 	    init_waitqueue_head(&info->close_wait);
diff -Nru a/drivers/serial/68328serial.h b/drivers/serial/68328serial.h
--- a/drivers/serial/68328serial.h	Mon Mar 10 16:26:26 2003
+++ b/drivers/serial/68328serial.h	Mon May 26 15:29:13 2003
@@ -155,8 +155,6 @@
 	int			line;
 	int			count;	    /* # of fd on device */
 	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
 	unsigned char 		*xmit_buf;
 	int			xmit_head;
 	int			xmit_tail;
@@ -164,7 +162,6 @@
 	struct work_struct	tqueue;
 	struct work_struct	tqueue_hangup;
 	struct termios		normal_termios;
-	struct termios		callout_termios;
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
 };
diff -Nru a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
--- a/drivers/serial/68360serial.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/serial/68360serial.c	Mon May 26 15:29:08 2003
@@ -73,7 +73,7 @@
 static char *serial_name = "CPM UART driver";
 static char *serial_version = "0.03";
 
-static struct tty_driver serial_driver, callout_driver;
+static struct tty_driver serial_driver;
 static int serial_refcount;
 int serial_console_setup(struct console *co, char *options);
 
@@ -164,7 +164,6 @@
         unsigned short  closing_wait; /* time to wait before closing */
         struct async_icount_24     icount; 
         struct termios          normal_termios;
-        struct termios          callout_termios;
         int     io_type;
         struct async_struct *info;
 };
@@ -256,8 +255,6 @@
 	unsigned long		event;
 	unsigned long		last_active;
 	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
 	struct work_struct	tqueue;
 	struct work_struct	tqueue_hangup;
  	wait_queue_head_t	open_wait; 
@@ -610,8 +607,7 @@
 #endif		
 		if (status & UART_MSR_DCD)
 			wake_up_interruptible(&info->open_wait);
-		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-			   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+		else {
 #ifdef SERIAL_DEBUG_OPEN
 			printk("scheduling hangup...");
 #endif
@@ -1718,8 +1714,6 @@
 	 */
 	if (info->flags & ASYNC_NORMAL_ACTIVE)
 		info->state->normal_termios = *tty->termios;
-	if (info->flags & ASYNC_CALLOUT_ACTIVE)
-		info->state->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -1768,8 +1762,7 @@
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	MOD_DEC_USE_COUNT;
 	local_irq_restore(flags);
@@ -1861,7 +1854,7 @@
 	shutdown(info);
 	info->event = 0;
 	state->count = 0;
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -1899,28 +1892,6 @@
 #endif
 	}
 
-
-#if 0 /* FIXME */
-	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-#endif	
-
 	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
@@ -1930,19 +1901,12 @@
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR)) ||
 	    !(info->state->smc_scc_num & NUM_IS_SCC)) {
-		if (info->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (state->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
 	
 	/*
 	 * Block waiting for the carrier detect and the line to become
@@ -1965,8 +1929,7 @@
 	info->blocked_open++;
 	while (1) {
 		local_irq_disable();
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (tty->termios->c_cflag & CBAUD))
+		if (tty->termios->c_cflag & CBAUD)
 			serial_out(info, UART_MCR,
 				   serial_inp(info, UART_MCR) |
 				   (UART_MCR_DTR | UART_MCR_RTS));
@@ -1984,8 +1947,7 @@
 #endif
 			break;
 		}
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(info->flags & ASYNC_CLOSING) &&
+		if (!(info->flags & ASYNC_CLOSING) &&
 		    (do_clocal || (serial_in(info, UART_MSR) &
 				   UART_MSR_DCD)))
 			break;
@@ -2076,16 +2038,10 @@
 
 	if ((info->state->count == 1) &&
 	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->state->normal_termios;
-		else 
-			*tty->termios = info->state->callout_termios;
+		*tty->termios = info->state->normal_termios;
 		change_speed(info);
 	}
 
-	info->session = current->session;
-	info->pgrp = current->pgrp;
-
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_open %s successful...", tty->name);
 #endif
@@ -2617,22 +2573,9 @@
 	/* serial_driver.wait_until_sent = rs_360_wait_until_sent; */
 	/* serial_driver.read_proc = rs_360_read_proc; */
 	
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	callout_driver = serial_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(&serial_driver))
 		panic("Couldn't register serial driver\n");
-	if (tty_register_driver(&callout_driver))
-		panic("Couldn't register callout driver\n");
-	
+
 	cp = pquicc;	/* Get pointer to Communication Processor */
 	/* immap = (immap_t *)IMAP_ADDR; */	/* and to internal registers */
 
@@ -2690,7 +2633,6 @@
 		state->custom_divisor = 0;
 		state->close_delay = 5*HZ/10;
 		state->closing_wait = 30*HZ;
-		state->callout_termios = callout_driver.init_termios;
 		state->normal_termios = serial_driver.init_termios;
 		state->icount.cts = state->icount.dsr = 
 			state->icount.rng = state->icount.dcd = 0;
diff -Nru a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
--- a/drivers/serial/mcfserial.c	Thu May  8 15:48:31 2003
+++ b/drivers/serial/mcfserial.c	Mon May 26 15:29:08 2003
@@ -76,12 +76,11 @@
 /*
  *	Driver data structures.
  */
-struct tty_driver	mcfrs_serial_driver, mcfrs_callout_driver;
+struct tty_driver	mcfrs_serial_driver;
 static int		mcfrs_serial_refcount;
 
 /* serial subtype definitions */
 #define SERIAL_TYPE_NORMAL	1
-#define SERIAL_TYPE_CALLOUT	2
   
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
@@ -450,12 +449,10 @@
 		return;
 
 	if (info->flags & ASYNC_CHECK_CD) {
-		if (dcd) {
+		if (dcd)
 			wake_up_interruptible(&info->open_wait);
-		} else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_CALLOUT_NOHUP))) {
+		else 
 			schedule_work(&info->tqueue_hangup);
-		}
 	}
 }
 
@@ -1198,8 +1195,6 @@
 	 */
 	if (info->flags & ASYNC_NORMAL_ACTIVE)
 		info->normal_termios = *tty->termios;
-	if (info->flags & ASYNC_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
 
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
@@ -1248,8 +1243,7 @@
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	local_irq_restore(flags);
 }
@@ -1268,7 +1262,7 @@
 	shutdown(info);
 	info->event = 0;
 	info->count = 0;
-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->flags &= ~ASYNC_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -1300,25 +1294,6 @@
 		return -EAGAIN;
 #endif
 	}
-
-	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
 	
 	/*
 	 * If non-blocking mode is set, or the port is not enabled,
@@ -1326,20 +1301,13 @@
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ASYNC_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -1357,8 +1325,7 @@
 	info->blocked_open++;
 	while (1) {
 		local_irq_disable();
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE))
-			mcfrs_setsignals(info, 1, 1);
+		mcfrs_setsignals(info, 1, 1);
 		local_irq_enable();
 		current->state = TASK_INTERRUPTIBLE;
 		if (tty_hung_up_p(filp) ||
@@ -1373,8 +1340,7 @@
 #endif
 			break;
 		}
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    !(info->flags & ASYNC_CLOSING) &&
+		if (!(info->flags & ASYNC_CLOSING) &&
 		    (do_clocal || (mcfrs_getsignals(info) & TIOCM_CD)))
 			break;
 		if (signal_pending(current)) {
@@ -1443,16 +1409,10 @@
 	}
 
 	if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->normal_termios;
-		else 
-			*tty->termios = info->callout_termios;
+		*tty->termios = info->normal_termios;
 		mcfrs_change_speed(info);
 	}
 
-	info->session = current->session;
-	info->pgrp = current->pgrp;
-
 #ifdef SERIAL_DEBUG_OPEN
 	printk("mcfrs_open %s successful...\n", tty->name);
 #endif
@@ -1658,26 +1618,11 @@
 	mcfrs_serial_driver.read_proc = mcfrs_readproc;
 	mcfrs_serial_driver.driver_name = "serial";
 
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	mcfrs_callout_driver = mcfrs_serial_driver;
-	mcfrs_callout_driver.name = "cua";
-	mcfrs_callout_driver.major = TTYAUX_MAJOR;
-	mcfrs_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-	mcfrs_callout_driver.read_proc = 0;
-	mcfrs_callout_driver.proc_entry = 0;
-
 	if (tty_register_driver(&mcfrs_serial_driver)) {
 		printk("MCFRS: Couldn't register serial driver\n");
 		return(-EBUSY);
 	}
-	if (tty_register_driver(&mcfrs_callout_driver)) {
-		printk("MCFRS: Couldn't register callout driver\n");
-		return(-EBUSY);
-	}
-	
+
 	local_irq_save(flags);
 
 	/*
@@ -1696,7 +1641,6 @@
 		info->blocked_open = 0;
 		INIT_WORK(&info->tqueue, mcfrs_offintr, info);
 		INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
-		info->callout_termios = mcfrs_callout_driver.init_termios;
 		info->normal_termios = mcfrs_serial_driver.init_termios;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
diff -Nru a/drivers/serial/mcfserial.h b/drivers/serial/mcfserial.h
--- a/drivers/serial/mcfserial.h	Tue Jan 14 03:33:49 2003
+++ b/drivers/serial/mcfserial.h	Mon May 26 15:29:08 2003
@@ -58,8 +58,6 @@
 	int			line;
 	int			count;	    /* # of fd on device */
 	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
 	unsigned char 		*xmit_buf;
 	int			xmit_head;
 	int			xmit_tail;
@@ -68,7 +66,6 @@
 	struct work_struct	tqueue;
 	struct work_struct	tqueue_hangup;
 	struct termios		normal_termios;
-	struct termios		callout_termios;
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
 
diff -Nru a/drivers/sgi/char/sgiserial.c b/drivers/sgi/char/sgiserial.c
--- a/drivers/sgi/char/sgiserial.c	Thu May  8 06:26:46 2003
+++ b/drivers/sgi/char/sgiserial.c	Mon May 26 15:29:09 2003
@@ -97,14 +97,13 @@
 
 DECLARE_TASK_QUEUE(tq_serial);
 
-struct tty_driver serial_driver, callout_driver;
+struct tty_driver serial_driver;
 struct console *sgisercon;
 static int serial_refcount;
 
 /* serial subtype definitions */
 #define SERIAL_TYPE_NORMAL	1
-#define SERIAL_TYPE_CALLOUT	2
-  
+
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
@@ -1514,8 +1513,6 @@
 	 */
 	if (info->flags & ZILOG_NORMAL_ACTIVE)
 		info->normal_termios = *tty->termios;
-	if (info->flags & ZILOG_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -1561,8 +1558,7 @@
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
-			 ZILOG_CLOSING);
+	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	restore_flags(flags);
 }
@@ -1581,7 +1577,7 @@
 	shutdown(info);
 	info->event = 0;
 	info->count = 0;
-	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE);
+	info->flags &= ~ZILOG_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -1615,44 +1611,18 @@
 	}
 
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ZILOG_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
-		    (info->flags & ZILOG_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
-		    (info->flags & ZILOG_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ZILOG_CALLOUT_ACTIVE;
-		return 0;
-	}
-	
-	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & ZILOG_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ZILOG_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & ZILOG_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -1670,8 +1640,7 @@
 	info->blocked_open++;
 	while (1) {
 		cli();
-		if (!(info->flags & ZILOG_CALLOUT_ACTIVE))
-			zs_rtsdtr(info, 1);
+		zs_rtsdtr(info, 1);
 		sti();
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) ||
@@ -1686,8 +1655,7 @@
 #endif
 			break;
 		}
-		if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
-		    !(info->flags & ZILOG_CLOSING) && do_clocal)
+		if (!(info->flags & ZILOG_CLOSING) && do_clocal)
 			break;
 		if (signal_pending(current)) {
 			retval = -ERESTARTSYS;
@@ -1761,10 +1729,7 @@
 	}
 
 	if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->normal_termios;
-		else 
-			*tty->termios = info->callout_termios;
+		*tty->termios = info->normal_termios;
 		change_speed(info);
 	}
 
@@ -1776,9 +1741,6 @@
 		change_speed(info);		
 	}
 
-	info->session = current->session;
-	info->pgrp = current->pgrp;
-
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_open %s successful...\n", tty->name);
 #endif
@@ -1899,20 +1861,9 @@
 	serial_driver.start = rs_start;
 	serial_driver.hangup = rs_hangup;
 
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	callout_driver = serial_driver;
-	callout_driver.name = "cua";
-	callout_driver.major = TTYAUX_MAJOR;
-	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-
 	if (tty_register_driver(&serial_driver))
 		panic("Couldn't register serial driver\n");
-	if (tty_register_driver(&callout_driver))
-		panic("Couldn't register callout driver\n");
-	
+
 	save_flags(flags); cli();
 
 	/* Set up our interrupt linked list */
@@ -1999,7 +1950,6 @@
 		info->tqueue.data = info;
 		info->tqueue_hangup.routine = do_serial_hangup;
 		info->tqueue_hangup.data = info;
-		info->callout_termios =callout_driver.init_termios;
 		info->normal_termios = serial_driver.init_termios;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
diff -Nru a/drivers/sgi/char/sgiserial.h b/drivers/sgi/char/sgiserial.h
--- a/drivers/sgi/char/sgiserial.h	Mon Feb  4 23:44:52 2002
+++ b/drivers/sgi/char/sgiserial.h	Mon May 26 15:29:09 2003
@@ -148,8 +148,6 @@
 	int			line;
 	int			count;	    /* # of fd on device */
 	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
 	unsigned char 		*xmit_buf;
 	int			xmit_head;
 	int			xmit_tail;
@@ -157,7 +155,6 @@
 	struct tq_struct	tqueue;
 	struct tq_struct	tqueue_hangup;
 	struct termios		normal_termios;
-	struct termios		callout_termios;
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
 };
diff -Nru a/drivers/tc/zs.c b/drivers/tc/zs.c
--- a/drivers/tc/zs.c	Wed May  7 15:51:55 2003
+++ b/drivers/tc/zs.c	Mon May 26 15:29:09 2003
@@ -180,12 +180,11 @@
 
 DECLARE_TASK_QUEUE(tq_zs_serial);
 
-struct tty_driver serial_driver, callout_driver;
+struct tty_driver serial_driver;
 static int serial_refcount;
 
 /* serial subtype definitions */
 #define SERIAL_TYPE_NORMAL	1
-#define SERIAL_TYPE_CALLOUT	2
 
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
@@ -526,7 +525,7 @@
 		    && info->tty && !C_CLOCAL(info->tty)) {
 			if (stat & DCD) {
 				wake_up_interruptible(&info->open_wait);
-			} else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
+			} else {
 				tty_hangup(info->tty);
 			}
 		}
@@ -1397,8 +1396,6 @@
 	 */
 	if (info->flags & ZILOG_NORMAL_ACTIVE)
 		info->normal_termios = *tty->termios;
-	if (info->flags & ZILOG_CALLOUT_ACTIVE)
-		info->callout_termios = *tty->termios;
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -1438,8 +1435,7 @@
 		}
 		wake_up_interruptible(&info->open_wait);
 	}
-	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
-			 ZILOG_CLOSING);
+	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	restore_flags(flags);
 }
@@ -1492,7 +1488,7 @@
 	shutdown(info);
 	info->event = 0;
 	info->count = 0;
-	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE);
+	info->flags &= ~ZILOG_NORMAL_ACTIVE;
 	info->tty = 0;
 	wake_up_interruptible(&info->open_wait);
 }
@@ -1527,20 +1523,6 @@
 	 * If this is a callout device, then just make sure the normal
 	 * device isn't being used.
 	 */
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		if (info->flags & ZILOG_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
-		    (info->flags & ZILOG_SESSION_LOCKOUT) &&
-		    (info->session != current->session))
-		    return -EBUSY;
-		if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
-		    (info->flags & ZILOG_PGRP_LOCKOUT) &&
-		    (info->pgrp != current->pgrp))
-		    return -EBUSY;
-		info->flags |= ZILOG_CALLOUT_ACTIVE;
-		return 0;
-	}
 	
 	/*
 	 * If non-blocking mode is set, or the port is not enabled,
@@ -1548,20 +1530,13 @@
 	 */
 	if ((filp->f_flags & O_NONBLOCK) ||
 	    (tty->flags & (1 << TTY_IO_ERROR))) {
-		if (info->flags & ZILOG_CALLOUT_ACTIVE)
-			return -EBUSY;
 		info->flags |= ZILOG_NORMAL_ACTIVE;
 		return 0;
 	}
 
-	if (info->flags & ZILOG_CALLOUT_ACTIVE) {
-		if (info->normal_termios.c_cflag & CLOCAL)
-			do_clocal = 1;
-	} else {
-		if (tty->termios->c_cflag & CLOCAL)
-			do_clocal = 1;
-	}
-	
+	if (tty->termios->c_cflag & CLOCAL)
+		do_clocal = 1;
+
 	/*
 	 * Block waiting for the carrier detect and the line to become
 	 * free (i.e., not in use by the callout).  While we are in
@@ -1582,8 +1557,7 @@
 	info->blocked_open++;
 	while (1) {
 		cli();
-		if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
-		    (tty->termios->c_cflag & CBAUD))
+		if (tty->termios->c_cflag & CBAUD)
 			zs_rtsdtr(info, RTS | DTR, 1);
 		sti();
 		set_current_state(TASK_INTERRUPTIBLE);
@@ -1599,8 +1573,7 @@
 #endif
 			break;
 		}
-		if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
-		    !(info->flags & ZILOG_CLOSING) &&
+		if (!(info->flags & ZILOG_CLOSING) &&
 		    (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD)))
 			break;
 		if (signal_pending(current)) {
@@ -1689,10 +1662,7 @@
 	}
 
 	if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) {
-		if (tty->driver->subtype == SERIAL_TYPE_NORMAL)
-			*tty->termios = info->normal_termios;
-		else 
-			*tty->termios = info->callout_termios;
+		*tty->termios = info->normal_termios;
 		change_speed(info);
 	}
 #ifdef CONFIG_SERIAL_CONSOLE
@@ -1703,9 +1673,6 @@
 	}
 #endif
 
-	info->session = current->session;
-	info->pgrp = current->pgrp;
-
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_open %s successful...", tty->name);
 #endif
@@ -1910,23 +1877,8 @@
 	serial_driver.break_ctl = rs_break;
 	serial_driver.wait_until_sent = rs_wait_until_sent;
 
-	/*
-	 * The callout device is just like normal device except for
-	 * major number and the subtype code.
-	 */
-	callout_driver = serial_driver;
-#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
-	callout_driver.name = "cua/";
-#else
-	callout_driver.name = "cua";
-#endif
-	callout_driver.major = TTYAUX_MAJOR;
-	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-
 	if (tty_register_driver(&serial_driver))
 		panic("Couldn't register serial driver\n");
-	if (tty_register_driver(&callout_driver))
-		panic("Couldn't register callout driver\n");
 
 	save_flags(flags); cli();
 
@@ -1964,7 +1916,6 @@
 		info->blocked_open = 0;
 		info->tqueue.routine = do_softint;
 		info->tqueue.data = info;
-		info->callout_termios = callout_driver.init_termios;
 		info->normal_termios = serial_driver.init_termios;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
@@ -1972,8 +1923,6 @@
 		       info->port, info->irq);
 		printk(" is a Z85C30 SCC\n");
 		tty_register_device(&serial_driver, info->line, NULL);
-		tty_register_device(&callout_driver, info->line, NULL);
-
 	}
 
 	restore_flags(flags);
diff -Nru a/drivers/tc/zs.h b/drivers/tc/zs.h
--- a/drivers/tc/zs.h	Sun Sep 29 15:28:06 2002
+++ b/drivers/tc/zs.h	Mon May 26 15:29:09 2003
@@ -144,8 +144,6 @@
 	int			line;
 	int			count;	    /* # of fd on device */
 	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
 	unsigned char 		*xmit_buf;
 	int			xmit_head;
 	int			xmit_tail;
@@ -153,7 +151,6 @@
 	struct tq_struct	tqueue;
 	struct tq_struct	tqueue_hangup;
 	struct termios		normal_termios;
-	struct termios		callout_termios;
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
 };
diff -Nru a/drivers/usb/media/pwc-if.c b/drivers/usb/media/pwc-if.c
--- a/drivers/usb/media/pwc-if.c	Thu Apr 24 03:35:40 2003
+++ b/drivers/usb/media/pwc-if.c	Mon May 26 16:23:35 2003
@@ -1804,7 +1804,7 @@
 	}
 	memcpy(vdev, &pwc_template, sizeof(pwc_template));
 	strcpy(vdev->name, name);
-	SET_MODULE_OWNER(vdev);
+	vdev->owner = THIS_MODULE;
 	pdev->vdev = vdev;
 	vdev->priv = pdev;
 
diff -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
--- a/drivers/usb/storage/scsiglue.c	Sun Apr  6 04:58:42 2003
+++ b/drivers/usb/storage/scsiglue.c	Mon May 12 08:21:06 2003
@@ -264,33 +264,21 @@
 #define SPRINTF(args...) \
 	do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
 
-static int usb_storage_proc_info (char *buffer, char **start, off_t offset,
-		int length, int hostno, int inout)
+static int usb_storage_proc_info (struct Scsi_Host *hostptr, char *buffer, char **start, off_t offset,
+		int length, int inout)
 {
 	struct us_data *us;
 	char *pos = buffer;
-	struct Scsi_Host *hostptr;
 	unsigned long f;
 
 	/* if someone is sending us data, just throw it away */
 	if (inout)
 		return length;
 
-	/* find our data from the given hostno */
-	hostptr = scsi_host_hn_get(hostno);
-	if (!hostptr) {	 /* if we couldn't find it, we return an error */
-		return -ESRCH;
-	}
 	us = (struct us_data*)hostptr->hostdata[0];
 
-	/* if we couldn't find it, we return an error */
-	if (!us) {
-		scsi_host_put(hostptr);
-		return -ESRCH;
-	}
-
 	/* print the controller name */
-	SPRINTF("   Host scsi%d: usb-storage\n", hostno);
+	SPRINTF("   Host scsi%d: usb-storage\n", hostptr->host_no);
 
 	/* print product, vendor, and serial number strings */
 	SPRINTF("       Vendor: %s\n", us->vendor);
@@ -318,9 +306,6 @@
 
 		*(pos++) = '\n';
 		}
-
-	/* release the reference count on this host */
-	scsi_host_put(hostptr);
 
 	/*
 	 * Calculate start of next buffer, and return value.
diff -Nru a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h
--- a/drivers/video/i810/i810.h	Thu Apr 10 08:47:57 2003
+++ b/drivers/video/i810/i810.h	Mon May 26 17:59:07 2003
@@ -203,8 +203,8 @@
 #define LOCKUP                      8
 
 struct gtt_data {
-	agp_memory *i810_fb_memory;
-	agp_memory *i810_cursor_memory;
+	struct agp_memory *i810_fb_memory;
+	struct agp_memory *i810_cursor_memory;
 };
 
 struct mode_registers {
diff -Nru a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
--- a/drivers/video/i810/i810_main.c	Thu Apr 24 03:30:41 2003
+++ b/drivers/video/i810/i810_main.c	Mon May 26 18:03:39 2003
@@ -1926,11 +1926,6 @@
 #ifndef MODULE
 int __init i810fb_init(void)
 {
-	if (agp_init()) {
-		printk("i810fb_init: cannot initialize agpgart\n");
-		return -ENODEV;
-	}
-
 	if (agp_intel_init()) {
 		printk("i810fb_init: cannot initialize intel agpgart\n");
 		return -ENODEV;
diff -Nru a/drivers/video/i810/i810_main.h b/drivers/video/i810/i810_main.h
--- a/drivers/video/i810/i810_main.h	Wed Mar 26 10:59:20 2003
+++ b/drivers/video/i810/i810_main.h	Mon May 26 18:03:39 2003
@@ -111,7 +111,6 @@
 /* Initialization */
 static void i810fb_release_resource       (struct fb_info *info, struct i810fb_par *par);
 extern int __init agp_intel_init(void);
-extern int __init agp_init(void);
 
 
 /* Video Timings */
diff -Nru a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
--- a/drivers/video/sis/sis_main.c	Thu Apr 24 03:30:41 2003
+++ b/drivers/video/sis/sis_main.c	Tue May 27 03:59:57 2003
@@ -2868,8 +2868,8 @@
 	unsigned long *write_port = 0;
 	SIS_CMDTYPE    cmd_type;
 #ifndef AGPOFF
-	agp_kern_info  *agp_info;
-	agp_memory     *agp;
+	struct agp_kern_info  *agp_info;
+	struct agp_memory     *agp;
 	u32            agp_phys;
 #endif
 #endif
@@ -2946,8 +2946,8 @@
 
 #ifndef AGPOFF
 	if (sisfb_queuemode == AGP_CMD_QUEUE) {
-		agp_info = vmalloc(sizeof(agp_kern_info));
-		memset((void*)agp_info, 0x00, sizeof(agp_kern_info));
+		agp_info = vmalloc(sizeof(*agp_info));
+		memset((void*)agp_info, 0x00, sizeof(*agp_info));
 		agp_copy_info(agp_info);
 
 		agp_backend_acquire();
diff -Nru a/fs/attr.c b/fs/attr.c
--- a/fs/attr.c	Sun Mar 16 00:39:53 2003
+++ b/fs/attr.c	Thu May 29 22:42:39 2003
@@ -68,13 +68,19 @@
 	int error = 0;
 
 	if (ia_valid & ATTR_SIZE) {
-		if (attr->ia_size != inode->i_size)
+		if (attr->ia_size != inode->i_size) {
 			error = vmtruncate(inode, attr->ia_size);
-		if (error || (ia_valid == ATTR_SIZE))
-			goto out;
+			if (error || (ia_valid == ATTR_SIZE))
+				goto out;
+		} else {
+			/*
+			 * We skipped the truncate but must still update
+			 * timestamps
+			 */
+			ia_valid |= ATTR_MTIME|ATTR_CTIME;
+		}
 	}
 
-	lock_kernel();
 	if (ia_valid & ATTR_UID)
 		inode->i_uid = attr->ia_uid;
 	if (ia_valid & ATTR_GID)
@@ -86,12 +92,13 @@
 	if (ia_valid & ATTR_CTIME)
 		inode->i_ctime = attr->ia_ctime;
 	if (ia_valid & ATTR_MODE) {
-		inode->i_mode = attr->ia_mode;
+		umode_t mode = attr->ia_mode;
+
 		if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
-			inode->i_mode &= ~S_ISGID;
+			mode &= ~S_ISGID;
+		inode->i_mode = mode;
 	}
 	mark_inode_dirty(inode);
-	unlock_kernel();
 out:
 	return error;
 }
diff -Nru a/fs/bio.c b/fs/bio.c
--- a/fs/bio.c	Sun May 25 09:19:53 2003
+++ b/fs/bio.c	Mon May 26 18:53:39 2003
@@ -38,7 +38,7 @@
  * basically we just need to survive
  */
 #define BIO_SPLIT_ENTRIES 8	
-static mempool_t *bio_split_pool;
+mempool_t *bio_split_pool;
 
 struct biovec_pool {
 	int nr_vecs;
@@ -916,3 +916,4 @@
 EXPORT_SYMBOL(bio_unmap_user);
 EXPORT_SYMBOL(bio_pair_release);
 EXPORT_SYMBOL(bio_split);
+EXPORT_SYMBOL(bio_split_pool);
diff -Nru a/fs/char_dev.c b/fs/char_dev.c
--- a/fs/char_dev.c	Sun May 25 14:52:51 2003
+++ b/fs/char_dev.c	Tue May 27 07:48:53 2003
@@ -89,6 +89,8 @@
 	if (cd == NULL)
 		return ERR_PTR(-ENOMEM);
 
+	memset(cd, 0, sizeof(struct char_device_struct));
+
 	write_lock_irq(&chrdevs_lock);
 
 	/* temporary */
diff -Nru a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
--- a/fs/cifs/cifsfs.c	Sun May 25 19:29:11 2003
+++ b/fs/cifs/cifsfs.c	Tue May 27 07:50:56 2003
@@ -94,13 +94,17 @@
 	sb->s_blocksize_bits = 14;	/* default 2**14 = CIFS_MAX_MSGSIZE */
 	inode = iget(sb, ROOT_I);
 
-	if (!inode)
+	if (!inode) {
+		rc = -ENOMEM;
 		goto out_no_root;
+	}
 
 	sb->s_root = d_alloc_root(inode);
 
-	if (!sb->s_root)
+	if (!sb->s_root) {
+		rc = -ENOMEM;
 		goto out_no_root;
+	}
 
 	return 0;
 
@@ -114,7 +118,7 @@
 		unload_nls(cifs_sb->local_nls);	
 	if(cifs_sb)
 		kfree(cifs_sb);
-	return -EINVAL;
+	return rc;
 }
 
 void
@@ -332,7 +336,7 @@
 	.release = cifs_close,
 	.lock = cifs_lock,
 	.fsync = cifs_fsync,
-    .flush = cifs_flush,
+	.flush = cifs_flush,
 	.mmap  = cifs_file_mmap,
 	.sendfile = generic_file_sendfile,
 };
diff -Nru a/fs/cifs/connect.c b/fs/cifs/connect.c
--- a/fs/cifs/connect.c	Sun May 25 19:30:34 2003
+++ b/fs/cifs/connect.c	Tue May 27 11:28:27 2003
@@ -346,6 +346,7 @@
 {
 	char *value;
 	char *data;
+	int  temp_len;
 
 	memset(vol,0,sizeof(struct smb_vol));
 	vol->linux_uid = current->uid;	/* current->euid instead? */
@@ -398,8 +399,9 @@
 				       "CIFS: invalid path to network resource\n");
 				return 1;	/* needs_arg; */
 			}
-			if (strnlen(value, 300) < 300) {
-				vol->UNC = value;
+			if ((temp_len = strnlen(value, 300)) < 300) {
+				vol->UNC = kmalloc(GFP_KERNEL, temp_len);
+				strcpy(vol->UNC,value);
 				if (strncmp(vol->UNC, "//", 2) == 0) {
 					vol->UNC[0] = '\\';
 					vol->UNC[1] = '\\';
@@ -472,8 +474,9 @@
 			printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
 			return 1;
 		}
-		if (strnlen(devname, 300) < 300) {
-			vol->UNC = devname;
+		if ((temp_len = strnlen(devname, 300)) < 300) {
+			vol->UNC = kmalloc(GFP_KERNEL, temp_len);
+			strcpy(vol->UNC,devname);
 			if (strncmp(vol->UNC, "//", 2) == 0) {
 				vol->UNC[0] = '\\';
 				vol->UNC[1] = '\\';
@@ -812,6 +815,8 @@
 	cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data));
 
 	if (parse_mount_options(mount_data, devname, &volume_info)) {
+		if(volume_info.UNC)
+			kfree(volume_info.UNC);
 		FreeXid(xid);
 		return -EINVAL;
 	}
@@ -852,6 +857,8 @@
 			       ("Error connecting to IPv4 socket. Aborting operation"));
 			if(csocket != NULL)
 				sock_release(csocket);
+			if(volume_info.UNC)
+				kfree(volume_info.UNC);
 			FreeXid(xid);
 			return rc;
 		}
@@ -860,6 +867,8 @@
 		if (srvTcp == NULL) {
 			rc = -ENOMEM;
 			sock_release(csocket);
+			if(volume_info.UNC)
+				kfree(volume_info.UNC);
 			FreeXid(xid);
 			return rc;
 		} else {
@@ -943,6 +952,8 @@
 								 "",
 								 cifs_sb->
 								 local_nls);
+					if(volume_info.UNC)
+						kfree(volume_info.UNC);
 					FreeXid(xid);
 					return -ENODEV;
 				} else {
@@ -995,7 +1006,8 @@
 		if (tcon->ses->capabilities & CAP_UNIX)
 			CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls);
 	}
-
+	if(volume_info.UNC)
+		kfree(volume_info.UNC);
 	FreeXid(xid);
 	return rc;
 }
@@ -2293,7 +2305,7 @@
 		length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
         /* skip service field (NB: this field is always ASCII) */
 		bcc_ptr += length + 1;	
-        strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
+		strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
 		if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
 			length = UniStrnlen((wchar_t *) bcc_ptr, 512);
 			if (((long) bcc_ptr + (2 * length)) -
diff -Nru a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
--- a/fs/cifs/netmisc.c	Sat Feb 15 14:10:24 2003
+++ b/fs/cifs/netmisc.c	Tue May 20 07:48:11 2003
@@ -46,7 +46,7 @@
 const struct smb_to_posix_error mapping_table_ERRDOS[] = {
 	{ERRbadfunc, -EINVAL},
 	{ERRbadfile, -ENOENT},
-	{ERRbadpath, -ENOENT},
+	{ERRbadpath, -ENOTDIR},
 	{ERRnofids, -EMFILE},
 	{ERRnoaccess, -EACCES},
 	{ERRbadfid, -EBADF},
@@ -63,26 +63,29 @@
 	{ERRnofiles, -ENOENT},
 	{ERRbadshare, -ETXTBSY},
 	{ERRlock, -EACCES},
-	{ERRfilexists, -EINVAL},
+	{ERRunsup, -EINVAL},
+	{ERRnosuchshare,-ENXIO},
+	{ERRfilexists, -EEXIST},
 	{ERRinvparm, -EINVAL},
 	{ERRdiskfull, -ENOSPC},
-	{ERRinvnum, -EINVAL},
+	{ERRinvname, -ENOENT},
 	{ERRdirnotempty, -ENOTEMPTY},
 	{ERRnotlocked, -ENOLCK},
 	{ERRalreadyexists, -EEXIST},
 	{ERRmoredata, -EOVERFLOW},
 	{ErrQuota, -EDQUOT},
 	{ErrNotALink, -ENOLINK},
+	{ERRnetlogonNotStarted,-ENOPROTOOPT},
 	{0, 0}
 };
 
 const struct smb_to_posix_error mapping_table_ERRSRV[] = {
 	{ERRerror, -EIO},
-	{ERRbadpw, -EACCES},
+	{ERRbadpw, -EPERM},
 	{ERRbadtype, -EREMOTE},
 	{ERRaccess, -EACCES},
 	{ERRinvtid, -ENXIO},
-	{ERRinvnetname, -ENOENT},
+	{ERRinvnetname, -ENODEV},
 	{ERRinvdevice, -ENXIO},
 	{ERRqfull, -ENOSPC},
 	{ERRqtoobig, -ENOSPC},
@@ -617,7 +620,7 @@
 	ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_CANT_START}, {
 	ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, {
 	ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, {
-	ERRDOS, 2455, NT_STATUS_NETLOGON_NOT_STARTED}, {
+	ERRDOS, ERRnetlogonNotStarted, NT_STATUS_NETLOGON_NOT_STARTED}, {
 	ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED}, {
 	ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK}, {
 	ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, {
diff -Nru a/fs/cifs/smberr.h b/fs/cifs/smberr.h
--- a/fs/cifs/smberr.h	Thu Oct 10 12:16:14 2002
+++ b/fs/cifs/smberr.h	Tue May 20 07:48:11 2003
@@ -59,7 +59,7 @@
 #define ERRfilexists 80		/* The file named in the request already exists. */
 #define ERRinvparm   87
 #define ERRdiskfull  112
-#define ERRinvnum    123
+#define ERRinvname   123
 #define ERRdirnotempty 145
 #define ERRnotlocked   158
 #define ERRalreadyexists 183
@@ -109,4 +109,5 @@
 #define ERRbadclient      2240
 #define ERRbadLogonTime   2241
 #define ERRpasswordExpired 2242
+#define ERRnetlogonNotStarted 2455
 #define ERRnosupport       0xFFFF
diff -Nru a/fs/coda/inode.c b/fs/coda/inode.c
--- a/fs/coda/inode.c	Sun May 25 18:38:56 2003
+++ b/fs/coda/inode.c	Thu May 29 22:42:28 2003
@@ -69,9 +69,9 @@
 int coda_init_inodecache(void)
 {
 	coda_inode_cachep = kmem_cache_create("coda_inode_cache",
-					     sizeof(struct coda_inode_info),
-					     0, SLAB_HWCACHE_ALIGN||SLAB_RECLAIM_ACCOUNT,
-					     init_once, NULL);
+				sizeof(struct coda_inode_info),
+				0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
+				init_once, NULL);
 	if (coda_inode_cachep == NULL)
 		return -ENOMEM;
 	return 0;
diff -Nru a/fs/fat/cache.c b/fs/fat/cache.c
--- a/fs/fat/cache.c	Wed Oct 23 08:14:05 2002
+++ b/fs/fat/cache.c	Tue May 27 07:32:56 2003
@@ -12,9 +12,6 @@
 #include <linux/msdos_fs.h>
 #include <linux/buffer_head.h>
 
-static struct fat_cache *fat_cache,cache[FAT_CACHE];
-static spinlock_t fat_cache_lock = SPIN_LOCK_UNLOCKED;
-
 int __fat_access(struct super_block *sb, int nr, int new_value)
 {
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
@@ -133,148 +130,163 @@
 	return next;
 }
 
-void fat_cache_init(void)
+void fat_cache_init(struct super_block *sb)
 {
-	static int initialized;
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	int count;
 
-	spin_lock(&fat_cache_lock);
-	if (initialized) {
-		spin_unlock(&fat_cache_lock);
-		return;
-	}
-	fat_cache = &cache[0];
-	for (count = 0; count < FAT_CACHE; count++) {
-		cache[count].sb = NULL;
-		cache[count].next = count == FAT_CACHE-1 ? NULL :
-		    &cache[count+1];
-	}
-	initialized = 1;
-	spin_unlock(&fat_cache_lock);
-}
+	spin_lock_init(&sbi->cache_lock);
 
+	for (count = 0; count < FAT_CACHE_NR - 1; count++) {
+		sbi->cache_array[count].start_cluster = 0;
+		sbi->cache_array[count].next = &sbi->cache_array[count + 1];
+	}
+	sbi->cache_array[count].start_cluster = 0;
+	sbi->cache_array[count].next = NULL;
+	sbi->cache = sbi->cache_array;
+}
 
-void fat_cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu)
+void fat_cache_lookup(struct inode *inode, int cluster, int *f_clu, int *d_clu)
 {
+	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
 	struct fat_cache *walk;
-	int first = MSDOS_I(inode)->i_start;
+	int first;
 
+	BUG_ON(cluster == 0);
+	
+	first = MSDOS_I(inode)->i_start;
 	if (!first)
 		return;
-	spin_lock(&fat_cache_lock);
-	for (walk = fat_cache; walk; walk = walk->next)
-		if (inode->i_sb == walk->sb
-		    && walk->start_cluster == first
+
+	spin_lock(&sbi->cache_lock);
+
+	if (MSDOS_I(inode)->disk_cluster &&
+	    MSDOS_I(inode)->file_cluster <= cluster) {
+		*d_clu = MSDOS_I(inode)->disk_cluster;
+		*f_clu = MSDOS_I(inode)->file_cluster;
+	}
+
+	for (walk = sbi->cache; walk; walk = walk->next) {
+		if (walk->start_cluster == first
 		    && walk->file_cluster <= cluster
 		    && walk->file_cluster > *f_clu) {
 			*d_clu = walk->disk_cluster;
+			*f_clu = walk->file_cluster;
 #ifdef DEBUG
-printk("cache hit: %d (%d)\n",walk->file_cluster,*d_clu);
+			printk("cache hit: %d (%d)\n", *f_clu, *d_clu);
 #endif
-			if ((*f_clu = walk->file_cluster) == cluster) { 
-				spin_unlock(&fat_cache_lock);
-				return;
-			}
+			if (*f_clu == cluster)
+				goto out;
 		}
-	spin_unlock(&fat_cache_lock);
+	}
 #ifdef DEBUG
-printk("cache miss\n");
+	printk("cache miss\n");
 #endif
+out:
+	spin_unlock(&sbi->cache_lock);
 }
 
-
 #ifdef DEBUG
-static void list_cache(void)
+static void list_cache(struct super_block *sb)
 {
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	struct fat_cache *walk;
 
-	for (walk = fat_cache; walk; walk = walk->next) {
-		if (walk->sb)
-			printk("<%s,%d>(%d,%d) ", walk->sb->s_id,
+	for (walk = sbi->cache; walk; walk = walk->next) {
+		if (walk->start_cluster)
+			printk("<%s,%d>(%d,%d) ", sb->s_id,
 			       walk->start_cluster, walk->file_cluster,
 			       walk->disk_cluster);
-		else printk("-- ");
+		else
+			printk("-- ");
 	}
 	printk("\n");
 }
 #endif
 
-
-void fat_cache_add(struct inode *inode,int f_clu,int d_clu)
+/*
+ * Cache invalidation occurs rarely, thus the LRU chain is not updated. It
+ * fixes itself after a while.
+ */
+static void __fat_cache_inval_inode(struct inode *inode)
 {
-	struct fat_cache *walk,*last;
+	struct fat_cache *walk;
 	int first = MSDOS_I(inode)->i_start;
+	MSDOS_I(inode)->file_cluster = MSDOS_I(inode)->disk_cluster = 0;
+	for (walk = MSDOS_SB(inode->i_sb)->cache; walk; walk = walk->next)
+		if (walk->start_cluster == first)
+			walk->start_cluster = 0;
+}
+
+void fat_cache_inval_inode(struct inode *inode)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+	spin_lock(&sbi->cache_lock);
+	__fat_cache_inval_inode(inode);
+	spin_unlock(&sbi->cache_lock);
+}
+
+void fat_cache_add(struct inode *inode, int f_clu, int d_clu)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
+	struct fat_cache *walk, *last;
+	int first, prev_f_clu, prev_d_clu;
+
+	first = MSDOS_I(inode)->i_start;
+	if (!first)
+		return;
 
 	last = NULL;
-	spin_lock(&fat_cache_lock);
-	for (walk = fat_cache; walk->next; walk = (last = walk)->next)
-		if (inode->i_sb == walk->sb
-		    && walk->start_cluster == first
-		    && walk->file_cluster == f_clu) {
+	spin_lock(&sbi->cache_lock);
+
+	if (MSDOS_I(inode)->file_cluster == f_clu)
+		goto out;
+	else {
+		prev_f_clu = MSDOS_I(inode)->file_cluster;
+		prev_d_clu = MSDOS_I(inode)->disk_cluster;
+		MSDOS_I(inode)->file_cluster = f_clu;
+		MSDOS_I(inode)->disk_cluster = d_clu;
+		if (prev_f_clu == 0)
+			goto out;
+		f_clu = prev_f_clu;
+		d_clu = prev_d_clu;
+	}
+	
+	for (walk = sbi->cache; walk->next; walk = (last = walk)->next) {
+		if (walk->start_cluster == first &&
+		    walk->file_cluster == f_clu) {
 			if (walk->disk_cluster != d_clu) {
 				printk(KERN_ERR "FAT: cache corruption"
 				       " (ino %lu)\n", inode->i_ino);
-				spin_unlock(&fat_cache_lock);
-				fat_cache_inval_inode(inode);
-				return;
+				__fat_cache_inval_inode(inode);
+				goto out;
 			}
+			if (last == NULL)
+				goto out;
+
 			/* update LRU */
-			if (last == NULL) {
-				spin_unlock(&fat_cache_lock);
-				return;
-			}
 			last->next = walk->next;
-			walk->next = fat_cache;
-			fat_cache = walk;
+			walk->next = sbi->cache;
+			sbi->cache = walk;
 #ifdef DEBUG
-list_cache();
+			list_cache();
 #endif
-			spin_unlock(&fat_cache_lock);
-			return;
+			goto out;
 		}
-	walk->sb = inode->i_sb;
+	}
 	walk->start_cluster = first;
 	walk->file_cluster = f_clu;
 	walk->disk_cluster = d_clu;
 	last->next = NULL;
-	walk->next = fat_cache;
-	fat_cache = walk;
-	spin_unlock(&fat_cache_lock);
+	walk->next = sbi->cache;
+	sbi->cache = walk;
 #ifdef DEBUG
-list_cache();
+	list_cache();
 #endif
+out:
+	spin_unlock(&sbi->cache_lock);
 }
 
-
-/* Cache invalidation occurs rarely, thus the LRU chain is not updated. It
-   fixes itself after a while. */
-
-void fat_cache_inval_inode(struct inode *inode)
-{
-	struct fat_cache *walk;
-	int first = MSDOS_I(inode)->i_start;
-
-	spin_lock(&fat_cache_lock);
-	for (walk = fat_cache; walk; walk = walk->next)
-		if (walk->sb == inode->i_sb
-		    && walk->start_cluster == first)
-			walk->sb = NULL;
-	spin_unlock(&fat_cache_lock);
-}
-
-
-void fat_cache_inval_dev(struct super_block *sb)
-{
-	struct fat_cache *walk;
-
-	spin_lock(&fat_cache_lock);
-	for (walk = fat_cache; walk; walk = walk->next)
-		if (walk->sb == sb)
-			walk->sb = 0;
-	spin_unlock(&fat_cache_lock);
-}
-
-
 static int fat_get_cluster(struct inode *inode, int cluster)
 {
 	struct super_block *sb = inode->i_sb;
@@ -302,32 +314,36 @@
 	return nr;
 }
 
-int fat_bmap(struct inode *inode, int sector)
+int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys)
 {
 	struct super_block *sb = inode->i_sb;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	int cluster, offset, last_block;
+	sector_t last_block;
+	int cluster, offset;
 
+	*phys = 0;
 	if ((sbi->fat_bits != 32) &&
 	    (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
 	     !MSDOS_I(inode)->i_start))) {
-		if (sector >= sbi->dir_entries >> sbi->dir_per_block_bits)
-			return 0;
-		return sector + sbi->dir_start;
+		if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits))
+			*phys = sector + sbi->dir_start;
+		return 0;
 	}
 	last_block = (MSDOS_I(inode)->mmu_private + (sb->s_blocksize - 1))
 		>> sb->s_blocksize_bits;
 	if (sector >= last_block)
 		return 0;
 
-	cluster = sector / sbi->cluster_size;
-	offset  = sector % sbi->cluster_size;
+	cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits);
+	offset  = sector & (sbi->cluster_size - 1);
 	cluster = fat_get_cluster(inode, cluster);
 	if (cluster < 0)
 		return cluster;
-	else if (!cluster)
-		return 0;
-	return (cluster - 2) * sbi->cluster_size + sbi->data_start + offset;
+	else if (cluster) {
+		*phys = ((sector_t)cluster - 2) * sbi->cluster_size
+			+ sbi->data_start + offset;
+	}
+	return 0;
 }
 
 
diff -Nru a/fs/fat/dir.c b/fs/fat/dir.c
--- a/fs/fat/dir.c	Sun Nov 17 11:53:57 2002
+++ b/fs/fat/dir.c	Tue May 27 07:32:48 2003
@@ -191,11 +191,11 @@
 	int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
 	int utf8 = MSDOS_SB(sb)->options.utf8;
 	unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
-	int ino, chl, i, j, last_u, res = 0;
-	loff_t cpos = 0;
+	int chl, i, j, last_u, res = 0;
+	loff_t i_pos, cpos = 0;
 
 	while(1) {
-		if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
+		if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1)
 			goto EODir;
 parse_record:
 		long_slots = 0;
@@ -246,7 +246,7 @@
 				if (ds->id & 0x40) {
 					unicode[offset + 13] = 0;
 				}
-				if (fat_get_entry(inode,&cpos,&bh,&de,&ino)<0)
+				if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos)<0)
 					goto EODir;
 				if (slot == 0)
 					break;
@@ -358,14 +358,15 @@
 	int utf8 = MSDOS_SB(sb)->options.utf8;
 	int nocase = MSDOS_SB(sb)->options.nocase;
 	unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname;
-	int ino, inum, chi, chl, i, i2, j, last, last_u, dotoffset = 0;
-	loff_t cpos;
+	unsigned long inum;
+	int chi, chl, i, i2, j, last, last_u, dotoffset = 0;
+	loff_t i_pos, cpos;
 	int ret = 0;
 	
 	lock_kernel();
 
 	cpos = filp->f_pos;
-/* Fake . and .. for the root directory. */
+	/* Fake . and .. for the root directory. */
 	if (inode->i_ino == MSDOS_ROOT_INO) {
 		while (cpos < 2) {
 			if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO, DT_DIR) < 0)
@@ -387,7 +388,7 @@
  	bh = NULL;
 GetNew:
 	long_slots = 0;
-	if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
+	if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1)
 		goto EODir;
 	/* Check for long filename entry */
 	if (isvfat) {
@@ -445,7 +446,7 @@
 			if (ds->id & 0x40) {
 				unicode[offset + 13] = 0;
 			}
-			if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
+			if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1)
 				goto EODir;
 			if (slot == 0)
 				break;
@@ -533,7 +534,7 @@
 	else if (!memcmp(de->name,MSDOS_DOTDOT,11)) {
 		inum = parent_ino(filp->f_dentry);
 	} else {
-		struct inode *tmp = fat_iget(sb, ino);
+		struct inode *tmp = fat_iget(sb, i_pos);
 		if (tmp) {
 			inum = tmp->i_ino;
 			iput(tmp);
@@ -591,23 +592,23 @@
 	return fat_readdirx(inode, filp, dirent, filldir, 0, 0);
 }
 
-static int vfat_ioctl_fill(
-	void * buf,
-	const char * name,
-	int name_len,
-	loff_t offset,
-	ino_t ino,
-	unsigned int d_type)
+struct fat_ioctl_filldir_callback {
+	struct dirent __user *dirent;
+	int result;
+};
+
+static int fat_ioctl_filldir(void *__buf, const char * name, int name_len,
+			     loff_t offset, ino_t ino, unsigned int d_type)
 {
-	struct dirent *d1 = (struct dirent *)buf;
-	struct dirent *d2 = d1 + 1;
+	struct fat_ioctl_filldir_callback *buf = __buf;
+	struct dirent __user *d1 = buf->dirent;
+	struct dirent __user *d2 = d1 + 1;
 	int len, slen;
 	int dotdir;
 
-	get_user(len, &d1->d_reclen);
-	if (len != 0) {
-		return -1;
-	}
+	if (buf->result)
+		return -EINVAL;
+	buf->result++;
 
 	if ((name_len == 1 && name[0] == '.') ||
 	    (name_len == 2 && name[0] == '.' && name[1] == '.')) {
@@ -618,73 +619,79 @@
 		len = strlen(name);
 	}
 	if (len != name_len) {
-		copy_to_user(d2->d_name, name, len);
-		put_user(0, d2->d_name + len);
-		put_user(len, &d2->d_reclen);
-		put_user(ino, &d2->d_ino);
-		put_user(offset, &d2->d_off);
 		slen = name_len - len;
-		copy_to_user(d1->d_name, name+len+1, slen);
-		put_user(0, d1->d_name+slen);
-		put_user(slen, &d1->d_reclen);
+		if (copy_to_user(d2->d_name, name, len)		||
+		    put_user(0, d2->d_name + len)		||
+		    put_user(len, &d2->d_reclen)		||
+		    put_user(ino, &d2->d_ino)			||
+		    put_user(offset, &d2->d_off)		||
+		    copy_to_user(d1->d_name, name+len+1, slen)	||
+		    put_user(0, d1->d_name+slen)		||
+		    put_user(slen, &d1->d_reclen))
+			goto efault;
 	} else {
-		put_user(0, d2->d_name);
-		put_user(0, &d2->d_reclen);
-		copy_to_user(d1->d_name, name, len);
-		put_user(0, d1->d_name+len);
-		put_user(len, &d1->d_reclen);
+		if (put_user(0, d2->d_name)			||
+		    put_user(0, &d2->d_reclen)			||
+		    copy_to_user(d1->d_name, name, len)		||
+		    put_user(0, d1->d_name+len)			||
+		    put_user(len, &d1->d_reclen))
+			goto efault;
 	}
-
 	return 0;
+efault:
+	buf->result = -EFAULT;
+	return -EFAULT;
 }
 
 int fat_dir_ioctl(struct inode * inode, struct file * filp,
 		  unsigned int cmd, unsigned long arg)
 {
-	int err;
+	struct fat_ioctl_filldir_callback buf;
+	struct dirent __user *d1 = (struct dirent *)arg;
+	int ret, shortname, both;
+
+	if (!access_ok(VERIFY_WRITE, d1, sizeof(struct dirent[2])))
+		return -EFAULT;
 	/*
-	 * We want to provide an interface for Samba to be able
-	 * to get the short filename for a given long filename.
-	 * Samba should use this ioctl instead of readdir() to
-	 * get the information it needs.
+	 * Yes, we don't need this put_user() absolutely. However old
+	 * code didn't return the right value. So, app use this value,
+	 * in order to check whether it is EOF.
 	 */
+	if (put_user(0, &d1->d_reclen))
+		return -EFAULT;
+
+	buf.dirent = d1;
+	buf.result = 0;
 	switch (cmd) {
-	case VFAT_IOCTL_READDIR_BOTH: {
-		struct dirent *d1 = (struct dirent *)arg;
-		err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
-		if (err)
-			return err;
-		put_user(0, &d1->d_reclen);
-		return fat_readdirx(inode,filp,(void *)arg,
-				    vfat_ioctl_fill, 0, 1);
-	}
-	case VFAT_IOCTL_READDIR_SHORT: {
-		struct dirent *d1 = (struct dirent *)arg;
-		put_user(0, &d1->d_reclen);
-		err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
-		if (err)
-			return err;
-		return fat_readdirx(inode,filp,(void *)arg,
-				    vfat_ioctl_fill, 1, 1);
-	}
+	case VFAT_IOCTL_READDIR_SHORT:
+		shortname = 1;
+		both = 1;
+		break;
+	case VFAT_IOCTL_READDIR_BOTH:
+		shortname = 0;
+		both = 1;
+		break;
 	default:
 		return -EINVAL;
 	}
-
-	return 0;
+	ret = fat_readdirx(inode, filp, &buf, fat_ioctl_filldir,
+			   shortname, both);
+	if (ret >= 0)
+		ret = buf.result;
+	return ret;
 }
 
 /***** See if directory is empty */
 int fat_dir_empty(struct inode *dir)
 {
-	loff_t pos;
+	loff_t pos, i_pos;
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
-	int ino,result = 0;
+	int result = 0;
 
 	pos = 0;
 	bh = NULL;
-	while (fat_get_entry(dir,&pos,&bh,&de,&ino) > -1) {
+	while (fat_get_entry(dir,&pos,&bh,&de,&i_pos) > -1) {
 		/* Ignore vfat longname entries */
 		if (de->attr == ATTR_EXT)
 			continue;
@@ -703,7 +710,7 @@
 /* This assumes that size of cluster is above the 32*slots */
 
 int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
-		  struct msdos_dir_entry **de, int *ino)
+		  struct msdos_dir_entry **de, loff_t *i_pos)
 {
 	struct super_block *sb = dir->i_sb;
 	loff_t offset, curr;
@@ -713,7 +720,7 @@
 	offset = curr = 0;
 	*bh = NULL;
 	row = 0;
-	while (fat_get_entry(dir, &curr, bh, de, ino) > -1) {
+	while (fat_get_entry(dir, &curr, bh, de, i_pos) > -1) {
 		/* check the maximum size of directory */
 		if (curr >= FAT_MAX_DIR_SIZE) {
 			brelse(*bh);
@@ -735,7 +742,7 @@
 		return PTR_ERR(new_bh);
 	brelse(new_bh);
 	do {
-		fat_get_entry(dir, &curr, bh, de, ino);
+		fat_get_entry(dir, &curr, bh, de, i_pos);
 	} while (++row < slots);
 
 	return offset;
diff -Nru a/fs/fat/file.c b/fs/fat/file.c
--- a/fs/fat/file.c	Tue Nov  5 07:36:01 2002
+++ b/fs/fat/file.c	Tue May 27 07:32:40 2003
@@ -32,11 +32,12 @@
 		  struct buffer_head *bh_result, int create)
 {
 	struct super_block *sb = inode->i_sb;
-	unsigned long phys;
+	sector_t phys;
+	int err;
 
-	phys = fat_bmap(inode, iblock);
-	if (phys < 0)
-		return phys;
+	err = fat_bmap(inode, iblock, &phys);
+	if (err)
+		return err;
 	if (phys) {
 		map_bh(bh_result, sb, phys);
 		return 0;
@@ -55,9 +56,9 @@
 			return error;
 	}
 	MSDOS_I(inode)->mmu_private += sb->s_blocksize;
-	phys = fat_bmap(inode, iblock);
-	if (phys < 0)
-		return phys;
+	err = fat_bmap(inode, iblock, &phys);
+	if (err)
+		return err;
 	if (!phys)
 		BUG();
 	set_buffer_new(bh_result);
diff -Nru a/fs/fat/inode.c b/fs/fat/inode.c
--- a/fs/fat/inode.c	Sun May 25 14:07:56 2003
+++ b/fs/fat/inode.c	Tue May 27 07:32:57 2003
@@ -60,17 +60,17 @@
 	}
 }
 
-static inline unsigned long fat_hash(struct super_block *sb, int i_pos)
+static inline unsigned long fat_hash(struct super_block *sb, loff_t i_pos)
 {
 	unsigned long tmp = (unsigned long)i_pos | (unsigned long) sb;
 	tmp = tmp + (tmp >> FAT_HASH_BITS) + (tmp >> FAT_HASH_BITS * 2);
 	return tmp & FAT_HASH_MASK;
 }
 
-void fat_attach(struct inode *inode, int i_pos)
+void fat_attach(struct inode *inode, loff_t i_pos)
 {
 	spin_lock(&fat_inode_lock);
-	MSDOS_I(inode)->i_location = i_pos;
+	MSDOS_I(inode)->i_pos = i_pos;
 	list_add(&MSDOS_I(inode)->i_fat_hash,
 		fat_inode_hashtable + fat_hash(inode->i_sb, i_pos));
 	spin_unlock(&fat_inode_lock);
@@ -79,12 +79,12 @@
 void fat_detach(struct inode *inode)
 {
 	spin_lock(&fat_inode_lock);
-	MSDOS_I(inode)->i_location = 0;
+	MSDOS_I(inode)->i_pos = 0;
 	list_del_init(&MSDOS_I(inode)->i_fat_hash);
 	spin_unlock(&fat_inode_lock);
 }
 
-struct inode *fat_iget(struct super_block *sb, int i_pos)
+struct inode *fat_iget(struct super_block *sb, loff_t i_pos)
 {
 	struct list_head *p = fat_inode_hashtable + fat_hash(sb, i_pos);
 	struct list_head *walk;
@@ -96,7 +96,7 @@
 		i = list_entry(walk, struct msdos_inode_info, i_fat_hash);
 		if (i->vfs_inode.i_sb != sb)
 			continue;
-		if (i->i_location != i_pos)
+		if (i->i_pos != i_pos)
 			continue;
 		inode = igrab(&i->vfs_inode);
 		if (inode)
@@ -109,11 +109,11 @@
 static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de);
 
 struct inode *fat_build_inode(struct super_block *sb,
-				struct msdos_dir_entry *de, int ino, int *res)
+			struct msdos_dir_entry *de, loff_t i_pos, int *res)
 {
 	struct inode *inode;
 	*res = 0;
-	inode = fat_iget(sb, ino);
+	inode = fat_iget(sb, i_pos);
 	if (inode)
 		goto out;
 	inode = new_inode(sb);
@@ -128,7 +128,7 @@
 		inode = NULL;
 		goto out;
 	}
-	fat_attach(inode, ino);
+	fat_attach(inode, i_pos);
 	insert_inode_hash(inode);
 out:
 	return inode;
@@ -160,7 +160,6 @@
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 
 	fat_clusters_flush(sb);
-	fat_cache_inval_dev(sb);
 	if (sbi->nls_disk) {
 		unload_nls(sbi->nls_disk);
 		sbi->nls_disk = NULL;
@@ -500,7 +499,7 @@
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	int error;
 
-	MSDOS_I(inode)->i_location = 0;
+	MSDOS_I(inode)->i_pos = 0;
 	inode->i_uid = sbi->options.fs_uid;
 	inode->i_gid = sbi->options.fs_gid;
 	inode->i_version++;
@@ -537,9 +536,10 @@
  *  0/  i_ino - for fast, reliable lookup if still in the cache
  *  1/  i_generation - to see if i_ino is still valid
  *          bit 0 == 0 iff directory
- *  2/  i_location - if ino has changed, but still in cache
- *  3/  i_logstart - to semi-verify inode found at i_location
- *  4/  parent->i_logstart - maybe used to hunt for the file on disc
+ *  2/  i_pos - if ino has changed, but still in cache (hi)
+ *  3/  i_pos - if ino has changed, but still in cache (low)
+ *  4/  i_logstart - to semi-verify inode found at i_location
+ *  5/  parent->i_logstart - maybe used to hunt for the file on disc
  *
  */
 
@@ -551,7 +551,7 @@
 
 	if (fhtype != 3)
 		return ERR_PTR(-ESTALE);
-	if (len < 5)
+	if (len < 6)
 		return ERR_PTR(-ESTALE);
 
 	return sb->s_export_op->find_exported_dentry(sb, fh, NULL, acceptable, context);
@@ -570,13 +570,15 @@
 		inode = NULL;
 	}
 	if (!inode) {
-		/* try 2 - see if i_location is in F-d-c
+		loff_t i_pos = ((loff_t)fh[2] << 32) | fh[3];
+
+		/* try 2 - see if i_pos is in F-d-c
 		 * require i_logstart to be the same
 		 * Will fail if you truncate and then re-write
 		 */
 
-		inode = fat_iget(sb, fh[2]);
-		if (inode && MSDOS_I(inode)->i_logstart != fh[3]) {
+		inode = fat_iget(sb, i_pos);
+		if (inode && MSDOS_I(inode)->i_logstart != fh[4]) {
 			iput(inode);
 			inode = NULL;
 		}
@@ -616,15 +618,16 @@
 	int len = *lenp;
 	struct inode *inode =  de->d_inode;
 	
-	if (len < 5)
+	if (len < 6)
 		return 255; /* no room */
-	*lenp = 5;
+	*lenp = 6;
 	fh[0] = inode->i_ino;
 	fh[1] = inode->i_generation;
-	fh[2] = MSDOS_I(inode)->i_location;
-	fh[3] = MSDOS_I(inode)->i_logstart;
+	fh[2] = (__u32)(MSDOS_I(inode)->i_pos >> 32);
+	fh[3] = (__u32)MSDOS_I(inode)->i_pos;
+	fh[4] = MSDOS_I(inode)->i_logstart;
 	spin_lock(&de->d_lock);
-	fh[4] = MSDOS_I(de->d_parent->d_inode)->i_logstart;
+	fh[5] = MSDOS_I(de->d_parent->d_inode)->i_logstart;
 	spin_unlock(&de->d_lock);
 	return 3;
 }
@@ -635,15 +638,15 @@
 	struct msdos_dir_entry *de = NULL;
 	struct dentry *parent = NULL;
 	int res;
-	int ino = 0;
+	loff_t i_pos = 0;
 	struct inode *inode;
 
 	lock_kernel();
-	res = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &ino);
+	res = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &i_pos);
 
 	if (res < 0)
 		goto out;
-	inode = fat_build_inode(child->d_sb, de, ino, &res);
+	inode = fat_build_inode(child->d_sb, de, i_pos, &res);
 	if (res)
 		goto out;
 	if (!inode)
@@ -762,7 +765,7 @@
 	if (!parse_options(data, isvfat, &debug, &sbi->options))
 		goto out_fail;
 
-	fat_cache_init();
+	fat_cache_init(sb);
 	/* set up enough so that it can read an inode */
 	init_MUTEX(&sbi->fat_lock);
 
@@ -1098,7 +1101,8 @@
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	int error;
 
-	MSDOS_I(inode)->i_location = 0;
+	MSDOS_I(inode)->file_cluster = MSDOS_I(inode)->disk_cluster = 0;
+	MSDOS_I(inode)->i_pos = 0;
 	inode->i_uid = sbi->options.fs_uid;
 	inode->i_gid = sbi->options.fs_gid;
 	inode->i_version++;
@@ -1112,10 +1116,9 @@
 		inode->i_fop = &fat_dir_operations;
 
 		MSDOS_I(inode)->i_start = CF_LE_W(de->start);
-		if (sbi->fat_bits == 32) {
-			MSDOS_I(inode)->i_start |=
-				(CF_LE_W(de->starthi) << 16);
-		}
+		if (sbi->fat_bits == 32)
+			MSDOS_I(inode)->i_start |= (CF_LE_W(de->starthi) << 16);
+
 		MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
 		error = fat_calc_dir_size(inode);
 		if (error < 0)
@@ -1131,10 +1134,9 @@
 		    	? S_IRUGO|S_IWUGO : S_IRWXUGO)
 		    & ~sbi->options.fs_fmask) | S_IFREG;
 		MSDOS_I(inode)->i_start = CF_LE_W(de->start);
-		if (sbi->fat_bits == 32) {
-			MSDOS_I(inode)->i_start |=
-				(CF_LE_W(de->starthi) << 16);
-		}
+		if (sbi->fat_bits == 32)
+			MSDOS_I(inode)->i_start |= (CF_LE_W(de->starthi) << 16);
+
 		MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
 		inode->i_size = CF_LE_L(de->size);
 	        inode->i_op = &fat_file_inode_operations;
@@ -1168,22 +1170,22 @@
 	struct super_block *sb = inode->i_sb;
 	struct buffer_head *bh;
 	struct msdos_dir_entry *raw_entry;
-	unsigned int i_pos;
+	loff_t i_pos;
 
 retry:
-	i_pos = MSDOS_I(inode)->i_location;
+	i_pos = MSDOS_I(inode)->i_pos;
 	if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) {
 		return;
 	}
 	lock_kernel();
 	if (!(bh = sb_bread(sb, i_pos >> MSDOS_SB(sb)->dir_per_block_bits))) {
-		fat_fs_panic(sb, "unable to read i-node block (ino %lu)",
+		fat_fs_panic(sb, "unable to read i-node block (i_pos %llu)",
 			     i_pos);
 		unlock_kernel();
 		return;
 	}
 	spin_lock(&fat_inode_lock);
-	if (i_pos != MSDOS_I(inode)->i_location) {
+	if (i_pos != MSDOS_I(inode)->i_pos) {
 		spin_unlock(&fat_inode_lock);
 		brelse(bh);
 		unlock_kernel();
diff -Nru a/fs/fat/misc.c b/fs/fat/misc.c
--- a/fs/fat/misc.c	Mon May 12 21:23:11 2003
+++ b/fs/fat/misc.c	Tue May 27 07:32:40 2003
@@ -178,9 +178,9 @@
 struct buffer_head *fat_extend_dir(struct inode *inode)
 {
 	struct super_block *sb = inode->i_sb;
-	int nr, sector, last_sector;
 	struct buffer_head *bh, *res = NULL;
-	int cluster_size = MSDOS_SB(sb)->cluster_size;
+	int nr, cluster_size = MSDOS_SB(sb)->cluster_size;
+	sector_t sector, last_sector;
 
 	if (MSDOS_SB(sb)->fat_bits != 32) {
 		if (inode->i_ino == MSDOS_ROOT_INO)
@@ -191,7 +191,7 @@
 	if (nr < 0)
 		return ERR_PTR(nr);
 	
-	sector = MSDOS_SB(sb)->data_start + (nr - 2) * cluster_size;
+	sector = ((sector_t)nr - 2) * cluster_size + MSDOS_SB(sb)->data_start;
 	last_sector = sector + cluster_size;
 	for ( ; sector < last_sector; sector++) {
 		if ((bh = sb_getblk(sb, sector))) {
@@ -289,11 +289,13 @@
  */
 
 int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
-    struct msdos_dir_entry **de, int *ino)
+		   struct msdos_dir_entry **de, loff_t *i_pos)
 {
 	struct super_block *sb = dir->i_sb;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	int sector, offset, iblock;
+	sector_t phys, iblock;
+	loff_t offset;
+	int err;
 
 next:
 	offset = *pos;
@@ -302,14 +304,14 @@
 
 	*bh = NULL;
 	iblock = *pos >> sb->s_blocksize_bits;
-	sector = fat_bmap(dir, iblock);
-	if (sector <= 0)
+	err = fat_bmap(dir, iblock, &phys);
+	if (err || !phys)
 		return -1;	/* beyond EOF or error */
 
-	*bh = sb_bread(sb, sector);
+	*bh = sb_bread(sb, phys);
 	if (*bh == NULL) {
-		printk(KERN_ERR "FAT: Directory bread(block %d) failed\n",
-		       sector);
+		printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n",
+		       phys);
 		/* skip this block */
 		*pos = (iblock + 1) << sb->s_blocksize_bits;
 		goto next;
@@ -318,7 +320,7 @@
 	offset &= sb->s_blocksize - 1;
 	*pos += sizeof(struct msdos_dir_entry);
 	*de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
-	*ino = (sector << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
+	*i_pos = ((loff_t)phys << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS);
 
 	return 0;
 }
@@ -357,7 +359,7 @@
     done = !IS_FREE(data[entry].name) \
       && ( \
            ( \
-             (MSDOS_SB(sb)->fat_bits != 32) ? 0 : (CF_LE_W(data[entry].starthi) << 16) \
+             (sbi->fat_bits != 32) ? 0 : (CF_LE_W(data[entry].starthi) << 16) \
            ) \
            | CF_LE_W(data[entry].start) \
          ) == *number;
@@ -374,35 +376,38 @@
 	    (*number)++; \
     }
 
-static int raw_scan_sector(struct super_block *sb,int sector,const char *name,
-    int *number,int *ino,struct buffer_head **res_bh,
-    struct msdos_dir_entry **res_de)
+static int raw_scan_sector(struct super_block *sb, sector_t sector,
+			   const char *name, int *number, loff_t *i_pos,
+			   struct buffer_head **res_bh,
+			   struct msdos_dir_entry **res_de)
 {
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	struct buffer_head *bh;
 	struct msdos_dir_entry *data;
 	int entry,start,done;
 
-	if (!(bh = sb_bread(sb,sector)))
+	if (!(bh = sb_bread(sb, sector)))
 		return -EIO;
 	data = (struct msdos_dir_entry *) bh->b_data;
-	for (entry = 0; entry < MSDOS_SB(sb)->dir_per_block; entry++) {
+	for (entry = 0; entry < sbi->dir_per_block; entry++) {
 /* RSS_COUNT:  if (data[entry].name == name) done=true else done=false. */
 		if (name) {
 			RSS_NAME
 		} else {
-			if (!ino) RSS_COUNT
+			if (!i_pos) RSS_COUNT
 			else {
 				if (number) RSS_START
 				else RSS_FREE
 			}
 		}
 		if (done) {
-			if (ino)
-				*ino = sector * MSDOS_SB(sb)->dir_per_block + entry;
+			if (i_pos) {
+				*i_pos = ((loff_t)sector << sbi->dir_per_block_bits) + entry;
+			}
 			start = CF_LE_W(data[entry].start);
-			if (MSDOS_SB(sb)->fat_bits == 32) {
+			if (sbi->fat_bits == 32)
 				start |= (CF_LE_W(data[entry].starthi) << 16);
-			}
+
 			if (!res_bh)
 				brelse(bh);
 			else {
@@ -422,16 +427,19 @@
  * requested entry is found or the end of the directory is reached.
  */
 
-static int raw_scan_root(struct super_block *sb,const char *name,int *number,int *ino,
-    struct buffer_head **res_bh,struct msdos_dir_entry **res_de)
+static int raw_scan_root(struct super_block *sb, const char *name,
+			 int *number, loff_t *i_pos,
+			 struct buffer_head **res_bh,
+			 struct msdos_dir_entry **res_de)
 {
 	int count,cluster;
 
 	for (count = 0;
 	     count < MSDOS_SB(sb)->dir_entries / MSDOS_SB(sb)->dir_per_block;
 	     count++) {
-		if ((cluster = raw_scan_sector(sb,MSDOS_SB(sb)->dir_start+count,
-					       name,number,ino,res_bh,res_de)) >= 0)
+		cluster = raw_scan_sector(sb, MSDOS_SB(sb)->dir_start + count,
+					  name, number, i_pos, res_bh, res_de);
+		if (cluster >= 0)
 			return cluster;
 	}
 	return -ENOENT;
@@ -443,24 +451,29 @@
  * requested entry is found or the end of the directory is reached.
  */
 
-static int raw_scan_nonroot(struct super_block *sb,int start,const char *name,
-    int *number,int *ino,struct buffer_head **res_bh,struct msdos_dir_entry
-    **res_de)
+static int raw_scan_nonroot(struct super_block *sb, int start, const char *name,
+			    int *number, loff_t *i_pos,
+			    struct buffer_head **res_bh,
+			    struct msdos_dir_entry **res_de)
 {
+	struct msdos_sb_info *sbi = MSDOS_SB(sb);
 	int count, cluster;
 	unsigned long dir_size = 0;
+	sector_t sector;
 
 #ifdef DEBUG
 	printk("raw_scan_nonroot: start=%d\n",start);
 #endif
 	do {
-		for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
-			if ((cluster = raw_scan_sector(sb,(start-2)*
-			    MSDOS_SB(sb)->cluster_size+MSDOS_SB(sb)->data_start+
-			    count,name,number,ino,res_bh,res_de)) >= 0)
+		for (count = 0; count < sbi->cluster_size; count++) {
+			sector = ((sector_t)start - 2) * sbi->cluster_size
+				+ count + sbi->data_start;
+			cluster = raw_scan_sector(sb, sector, name, number,
+						  i_pos, res_bh, res_de);
+			if (cluster >= 0)
 				return cluster;
 		}
-		dir_size += 1 << MSDOS_SB(sb)->cluster_bits;
+		dir_size += 1 << sbi->cluster_bits;
 		if (dir_size > FAT_MAX_DIR_SIZE) {
 			fat_fs_panic(sb, "Directory %d: "
 				     "exceeded the maximum size of directory",
@@ -492,13 +505,13 @@
  */
 
 static int raw_scan(struct super_block *sb, int start, const char *name,
-    int *number, int *ino, struct buffer_head **res_bh,
-    struct msdos_dir_entry **res_de)
+		    loff_t *i_pos, struct buffer_head **res_bh,
+		    struct msdos_dir_entry **res_de)
 {
 	if (start)
-		return raw_scan_nonroot(sb,start,name,number,ino,res_bh,res_de);
+		return raw_scan_nonroot(sb,start,name,NULL,i_pos,res_bh,res_de);
 	else
-		return raw_scan_root(sb,name,number,ino,res_bh,res_de);
+		return raw_scan_root(sb,name,NULL,i_pos,res_bh,res_de);
 }
 
 /*
@@ -507,19 +520,21 @@
  */
 int fat_subdirs(struct inode *dir)
 {
-	int count;
+	struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
+	int number;
 
-	count = 0;
-	if ((dir->i_ino == MSDOS_ROOT_INO) &&
-	    (MSDOS_SB(dir->i_sb)->fat_bits != 32)) {
-		(void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL);
-	} else {
-		if ((dir->i_ino != MSDOS_ROOT_INO) &&
-		    !MSDOS_I(dir)->i_start) return 0; /* in mkdir */
-		else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start,
-		    NULL,&count,NULL,NULL,NULL);
+	number = 0;
+	if ((dir->i_ino == MSDOS_ROOT_INO) && (sbi->fat_bits != 32))
+		raw_scan_root(dir->i_sb, NULL, &number, NULL, NULL, NULL);
+	else {
+		if ((dir->i_ino != MSDOS_ROOT_INO) && !MSDOS_I(dir)->i_start)
+			return 0; /* in mkdir */
+		else {
+			raw_scan_nonroot(dir->i_sb, MSDOS_I(dir)->i_start,
+					 NULL, &number, NULL, NULL, NULL);
+		}
 	}
-	return count;
+	return number;
 }
 
 
@@ -528,12 +543,12 @@
  * for an empty directory slot (name is NULL). Returns an error code or zero.
  */
 
-int fat_scan(struct inode *dir,const char *name,struct buffer_head **res_bh,
-    struct msdos_dir_entry **res_de,int *ino)
+int fat_scan(struct inode *dir, const char *name, struct buffer_head **res_bh,
+	     struct msdos_dir_entry **res_de, loff_t *i_pos)
 {
 	int res;
 
-	res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,
-		       name, NULL, ino, res_bh, res_de);
-	return res<0 ? res : 0;
+	res = raw_scan(dir->i_sb, MSDOS_I(dir)->i_start, name, i_pos,
+		       res_bh, res_de);
+	return (res < 0) ? res : 0;
 }
diff -Nru a/fs/fcntl.c b/fs/fcntl.c
--- a/fs/fcntl.c	Tue May 13 13:42:27 2003
+++ b/fs/fcntl.c	Thu May 29 22:42:42 2003
@@ -80,11 +80,11 @@
  */
 
 static int locate_fd(struct files_struct *files, 
-			    struct file *file, int orig_start)
+			    struct file *file, unsigned int orig_start)
 {
 	unsigned int newfd;
+	unsigned int start;
 	int error;
-	int start;
 
 	error = -EINVAL;
 	if (orig_start >= current->rlim[RLIMIT_NOFILE].rlim_cur)
@@ -129,7 +129,7 @@
 	return error;
 }
 
-static int dupfd(struct file *file, int start)
+static int dupfd(struct file *file, unsigned int start)
 {
 	struct files_struct * files = current->files;
 	int fd;
@@ -286,10 +286,8 @@
 
 	switch (cmd) {
 		case F_DUPFD:
-			if (arg < NR_OPEN) {
-				get_file(filp);
-				err = dupfd(filp, arg);
-			}
+			get_file(filp);
+			err = dupfd(filp, arg);
 			break;
 		case F_GETFD:
 			err = get_close_on_exec(fd);
diff -Nru a/fs/jffs2/background.c b/fs/jffs2/background.c
--- a/fs/jffs2/background.c	Thu Feb 13 09:34:46 2003
+++ b/fs/jffs2/background.c	Wed May 28 08:01:05 2003
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: background.c,v 1.33 2002/11/12 09:44:30 dwmw2 Exp $
+ * $Id: background.c,v 1.38 2003/05/26 09:50:38 dwmw2 Exp $
  *
  */
 
@@ -16,9 +16,8 @@
 #include <linux/kernel.h>
 #include <linux/jffs2.h>
 #include <linux/mtd/mtd.h>
-#include <linux/interrupt.h>
 #include <linux/completion.h>
-#include <linux/mtd/compatmac.h> /* recalc_sigpending() */
+#include <linux/sched.h>
 #include <linux/unistd.h>
 #include "nodelist.h"
 
@@ -28,10 +27,10 @@
 
 void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
 {
-	spin_lock_bh(&c->erase_completion_lock);
+	spin_lock(&c->erase_completion_lock);
         if (c->gc_task && thread_should_wake(c))
                 send_sig(SIGHUP, c->gc_task, 1);
-	spin_unlock_bh(&c->erase_completion_lock);
+	spin_unlock(&c->erase_completion_lock);
 }
 
 /* This must only ever be called when no GC thread is currently running */
@@ -69,12 +68,12 @@
 		flush_scheduled_work();
 	}
 
-	spin_lock_bh(&c->erase_completion_lock);
+	spin_lock(&c->erase_completion_lock);
 	if (c->gc_task) {
 		D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid));
 		send_sig(SIGKILL, c->gc_task, 1);
 	}
-	spin_unlock_bh(&c->erase_completion_lock);
+	spin_unlock(&c->erase_completion_lock);
 	wait_for_completion(&c->gc_thread_exit);
 }
 
@@ -126,9 +125,9 @@
 
 			case SIGKILL:
 				D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGKILL received.\n"));
-				spin_lock_bh(&c->erase_completion_lock);
+				spin_lock(&c->erase_completion_lock);
 				c->gc_task = NULL;
-				spin_unlock_bh(&c->erase_completion_lock);
+				spin_unlock(&c->erase_completion_lock);
 				complete_and_exit(&c->gc_thread_exit, 0);
 
 			case SIGHUP:
@@ -152,6 +151,7 @@
 static int thread_should_wake(struct jffs2_sb_info *c)
 {
 	int ret = 0;
+	uint32_t dirty;
 
 	if (c->unchecked_size) {
 		D1(printk(KERN_DEBUG "thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
@@ -159,8 +159,18 @@
 		return 1;
 	}
 
+	/* dirty_size contains blocks on erase_pending_list
+	 * those blocks are counted in c->nr_erasing_blocks.
+	 * If one block is actually erased, it is not longer counted as dirty_space
+	 * but it is counted in c->nr_erasing_blocks, so we add it and subtract it
+	 * with c->nr_erasing_blocks * c->sector_size again.
+	 * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks
+	 * This helps us to force gc and pick eventually a clean block to spread the load.
+	 */
+	dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size;
+
 	if (c->nr_free_blocks + c->nr_erasing_blocks < JFFS2_RESERVED_BLOCKS_GCTRIGGER && 
-			(c->dirty_size > c->sector_size)) 
+			(dirty > c->sector_size)) 
 		ret = 1;
 
 	D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", 
diff -Nru a/fs/jffs2/build.c b/fs/jffs2/build.c
--- a/fs/jffs2/build.c	Tue Nov 12 08:11:53 2002
+++ b/fs/jffs2/build.c	Wed May 28 08:01:05 2003
@@ -7,19 +7,42 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: build.c,v 1.42 2002/09/09 16:29:08 dwmw2 Exp $
+ * $Id: build.c,v 1.46 2003/04/29 17:12:26 gleixner Exp $
  *
  */
 
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include "nodelist.h"
 
 int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *);
 int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *);
 
+static inline struct jffs2_inode_cache *
+first_inode_chain(int *i, struct jffs2_sb_info *c)
+{
+	for (; *i < INOCACHE_HASHSIZE; (*i)++) {
+		if (c->inocache_list[*i])
+			return c->inocache_list[*i];
+	}
+	return NULL;
+}
+
+static inline struct jffs2_inode_cache *
+next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c)
+{
+	/* More in this chain? */
+	if (ic->next)
+		return ic->next;
+	(*i)++;
+	return first_inode_chain(i, c);
+}
 
-#define for_each_inode(i, c, ic) for (i=0; i<INOCACHE_HASHSIZE; i++) for (ic=c->inocache_list[i]; ic; ic=ic->next) 
+#define for_each_inode(i, c, ic)			\
+	for (i = 0, ic = first_inode_chain(&i, (c));	\
+	     ic;					\
+	     ic = next_inode(&i, ic, (c)))
 
 /* Scan plan:
  - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go
@@ -229,6 +252,7 @@
 	init_MUTEX(&c->alloc_sem);
 	init_MUTEX(&c->erase_free_sem);
 	init_waitqueue_head(&c->erase_wait);
+	init_waitqueue_head(&c->inocache_wq);
 	spin_lock_init(&c->erase_completion_lock);
 	spin_lock_init(&c->inocache_lock);
 
diff -Nru a/fs/jffs2/compr.c b/fs/jffs2/compr.c
--- a/fs/jffs2/compr.c	Tue Jul 23 03:13:13 2002
+++ b/fs/jffs2/compr.c	Wed May 28 08:01:06 2003
@@ -7,14 +7,15 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr.c,v 1.24 2002/05/20 14:56:37 dwmw2 Exp $
+ * $Id: compr.c,v 1.26 2003/01/12 13:21:28 dwmw2 Exp $
  *
  */
 
-#ifdef __KERNEL__
+#if defined(__KERNEL__) || defined (__ECOS)
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/types.h>
 #else 
 #define KERN_DEBUG
 #define KERN_NOTICE
diff -Nru a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c
--- a/fs/jffs2/compr_rtime.c	Mon Feb 24 12:31:17 2003
+++ b/fs/jffs2/compr_rtime.c	Wed May 28 08:01:06 2003
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_rtime.c,v 1.9 2002/05/20 14:56:37 dwmw2 Exp $
+ * $Id: compr_rtime.c,v 1.10 2003/05/11 10:47:13 dwmw2 Exp $
  *
  *
  * Very simple lz77-ish encoder.
@@ -30,7 +30,7 @@
 int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, 
 		   uint32_t *sourcelen, uint32_t *dstlen)
 {
-	int positions[256];
+	short positions[256];
 	int outpos = 0;
 	int pos=0;
 
@@ -70,7 +70,7 @@
 void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
 		      uint32_t srclen, uint32_t destlen)
 {
-	int positions[256];
+	short positions[256];
 	int outpos = 0;
 	int pos=0;
 	
diff -Nru a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c
--- a/fs/jffs2/compr_zlib.c	Tue Jul 23 06:08:22 2002
+++ b/fs/jffs2/compr_zlib.c	Wed May 28 08:01:06 2003
@@ -7,20 +7,22 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_zlib.c,v 1.18 2002/05/20 14:56:37 dwmw2 Exp $
+ * $Id: compr_zlib.c,v 1.23 2003/05/26 09:15:19 dwmw2 Exp $
  *
  */
 
-#ifndef __KERNEL__
+#if !defined(__KERNEL__) && !defined(__ECOS)
 #error "The userspace support got too messy and was removed. Update your mkfs.jffs2"
 #endif
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/mtd/compatmac.h> /* for min() */
+#include <linux/vmalloc.h>
+#include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/jffs2.h>
 #include <linux/zlib.h>
+#include <linux/zutil.h>
+#include <asm/semaphore.h>
 #include "nodelist.h"
 
 	/* Plan: call deflate() with avail_in == *sourcelen, 
@@ -34,21 +36,21 @@
 
 static DECLARE_MUTEX(deflate_sem);
 static DECLARE_MUTEX(inflate_sem);
-static void *deflate_workspace;
-static void *inflate_workspace;
+static z_stream inf_strm, def_strm;
 
+#ifdef __KERNEL__ /* Linux-only */
 int __init jffs2_zlib_init(void)
 {
-	deflate_workspace = vmalloc(zlib_deflate_workspacesize());
-	if (!deflate_workspace) {
+	def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
+	if (!def_strm.workspace) {
 		printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize());
 		return -ENOMEM;
 	}
 	D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize()));
-	inflate_workspace = vmalloc(zlib_inflate_workspacesize());
-	if (!inflate_workspace) {
+	inf_strm.workspace = vmalloc(zlib_inflate_workspacesize());
+	if (!inf_strm.workspace) {
 		printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize());
-		vfree(deflate_workspace);
+		vfree(def_strm.workspace);
 		return -ENOMEM;
 	}
 	D1(printk(KERN_DEBUG "Allocated %d bytes for inflate workspace\n", zlib_inflate_workspacesize()));
@@ -57,97 +59,120 @@
 
 void jffs2_zlib_exit(void)
 {
-	vfree(deflate_workspace);
-	vfree(inflate_workspace);
+	vfree(def_strm.workspace);
+	vfree(inf_strm.workspace);
 }
+#endif /* __KERNEL__ */
 
 int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, 
 		   uint32_t *sourcelen, uint32_t *dstlen)
 {
-	z_stream strm;
 	int ret;
 
 	if (*dstlen <= STREAM_END_SPACE)
 		return -1;
 
 	down(&deflate_sem);
-	strm.workspace = deflate_workspace;
 
-	if (Z_OK != zlib_deflateInit(&strm, 3)) {
+	if (Z_OK != zlib_deflateInit(&def_strm, 3)) {
 		printk(KERN_WARNING "deflateInit failed\n");
 		up(&deflate_sem);
 		return -1;
 	}
 
-	strm.next_in = data_in;
-	strm.total_in = 0;
+	def_strm.next_in = data_in;
+	def_strm.total_in = 0;
 	
-	strm.next_out = cpage_out;
-	strm.total_out = 0;
+	def_strm.next_out = cpage_out;
+	def_strm.total_out = 0;
 
-	while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) {
-		strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE);
-		strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out);
+	while (def_strm.total_out < *dstlen - STREAM_END_SPACE && def_strm.total_in < *sourcelen) {
+		def_strm.avail_out = *dstlen - (def_strm.total_out + STREAM_END_SPACE);
+		def_strm.avail_in = min((unsigned)(*sourcelen-def_strm.total_in), def_strm.avail_out);
 		D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n",
-			  strm.avail_in, strm.avail_out));
-		ret = zlib_deflate(&strm, Z_PARTIAL_FLUSH);
+			  def_strm.avail_in, def_strm.avail_out));
+		ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH);
 		D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", 
-			  strm.avail_in, strm.avail_out, strm.total_in, strm.total_out));
+			  def_strm.avail_in, def_strm.avail_out, def_strm.total_in, def_strm.total_out));
 		if (ret != Z_OK) {
 			D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret));
-			zlib_deflateEnd(&strm);
+			zlib_deflateEnd(&def_strm);
 			up(&deflate_sem);
 			return -1;
 		}
 	}
-	strm.avail_out += STREAM_END_SPACE;
-	strm.avail_in = 0;
-	ret = zlib_deflate(&strm, Z_FINISH);
-	zlib_deflateEnd(&strm);
-	up(&deflate_sem);
+	def_strm.avail_out += STREAM_END_SPACE;
+	def_strm.avail_in = 0;
+	ret = zlib_deflate(&def_strm, Z_FINISH);
+	zlib_deflateEnd(&def_strm);
+
 	if (ret != Z_STREAM_END) {
 		D1(printk(KERN_DEBUG "final deflate returned %d\n", ret));
-		return -1;
+		ret = -1;
+		goto out;
 	}
 
-	D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n",
-		  strm.total_in, strm.total_out));
+	if (def_strm.total_out >= def_strm.total_in) {
+		D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld; failing\n",
+			  def_strm.total_in, def_strm.total_out));
+		ret = -1;
+		goto out;
+	}
 
-	if (strm.total_out >= strm.total_in)
-		return -1;
+	D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n",
+		  def_strm.total_in, def_strm.total_out));
 
-	*dstlen = strm.total_out;
-	*sourcelen = strm.total_in;
-	return 0;
+	*dstlen = def_strm.total_out;
+	*sourcelen = def_strm.total_in;
+	ret = 0;
+ out:
+	up(&deflate_sem);
+	return ret;
 }
 
 void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
 		      uint32_t srclen, uint32_t destlen)
 {
-	z_stream strm;
 	int ret;
+	int wbits = MAX_WBITS;
 
 	down(&inflate_sem);
-	strm.workspace = inflate_workspace;
 
-	if (Z_OK != zlib_inflateInit(&strm)) {
+	inf_strm.next_in = data_in;
+	inf_strm.avail_in = srclen;
+	inf_strm.total_in = 0;
+	
+	inf_strm.next_out = cpage_out;
+	inf_strm.avail_out = destlen;
+	inf_strm.total_out = 0;
+
+	/* If it's deflate, and it's got no preset dictionary, then
+	   we can tell zlib to skip the adler32 check. */
+	if (srclen > 2 && !(data_in[1] & PRESET_DICT) &&
+	    ((data_in[0] & 0x0f) == Z_DEFLATED) &&
+	    !(((data_in[0]<<8) + data_in[1]) % 31)) {
+
+		D2(printk(KERN_DEBUG "inflate skipping adler32\n"));
+		wbits = -((data_in[0] >> 4) + 8);
+		inf_strm.next_in += 2;
+		inf_strm.avail_in -= 2;
+	} else {
+		/* Let this remain D1 for now -- it should never happen */
+		D1(printk(KERN_DEBUG "inflate not skipping adler32\n"));
+	}
+
+
+	if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) {
 		printk(KERN_WARNING "inflateInit failed\n");
 		up(&inflate_sem);
 		return;
 	}
-	strm.next_in = data_in;
-	strm.avail_in = srclen;
-	strm.total_in = 0;
-	
-	strm.next_out = cpage_out;
-	strm.avail_out = destlen;
-	strm.total_out = 0;
 
-	while((ret = zlib_inflate(&strm, Z_FINISH)) == Z_OK)
+	while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK)
 		;
 	if (ret != Z_STREAM_END) {
 		printk(KERN_NOTICE "inflate returned %d\n", ret);
 	}
-	zlib_inflateEnd(&strm);
+	zlib_inflateEnd(&inf_strm);
 	up(&inflate_sem);
 }
diff -Nru a/fs/jffs2/dir.c b/fs/jffs2/dir.c
--- a/fs/jffs2/dir.c	Wed Nov 20 03:19:02 2002
+++ b/fs/jffs2/dir.c	Wed May 28 08:01:06 2003
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: dir.c,v 1.73 2002/08/26 15:00:51 dwmw2 Exp $
+ * $Id: dir.c,v 1.76 2003/05/26 09:50:38 dwmw2 Exp $
  *
  */
 
@@ -16,13 +16,20 @@
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/crc32.h>
-#include <linux/mtd/compatmac.h> /* For completion */
 #include <linux/jffs2.h>
 #include <linux/jffs2_fs_i.h>
 #include <linux/jffs2_fs_sb.h>
 #include <linux/time.h>
 #include "nodelist.h"
 
+/* Urgh. Please tell me there's a nicer way of doing this. */
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
+typedef int mknod_arg_t;
+#else
+typedef dev_t mknod_arg_t;
+#endif
+
 static int jffs2_readdir (struct file *, void *, filldir_t);
 
 static int jffs2_create (struct inode *,struct dentry *,int);
@@ -32,7 +39,7 @@
 static int jffs2_symlink (struct inode *,struct dentry *,const char *);
 static int jffs2_mkdir (struct inode *,struct dentry *,int);
 static int jffs2_rmdir (struct inode *,struct dentry *);
-static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t);
+static int jffs2_mknod (struct inode *,struct dentry *,int,mknod_arg_t);
 static int jffs2_rename (struct inode *, struct dentry *,
                         struct inode *, struct dentry *);
 
@@ -211,8 +218,7 @@
 		return ret;
 	}
 
-	dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(ri->ctime);
-	dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0;
+	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime));
 
 	jffs2_free_raw_inode(ri);
 	d_instantiate(dentry, inode);
@@ -402,8 +408,7 @@
 		return PTR_ERR(fd);
 	}
 
-	dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(rd->mctime);
-	dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0;
+	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
 
 	jffs2_free_raw_dirent(rd);
 
@@ -540,8 +545,7 @@
 		return PTR_ERR(fd);
 	}
 
-	dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(rd->mctime);
-	dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0;
+	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
 	dir_i->i_nlink++;
 
 	jffs2_free_raw_dirent(rd);
@@ -573,7 +577,7 @@
 	return ret;
 }
 
-static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, dev_t rdev)
+static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, mknod_arg_t rdev)
 {
 	struct jffs2_inode_info *f, *dir_f;
 	struct jffs2_sb_info *c;
@@ -583,7 +587,7 @@
 	struct jffs2_full_dnode *fn;
 	struct jffs2_full_dirent *fd;
 	int namelen;
-	unsigned short dev;
+	jint16_t dev;
 	int devlen = 0;
 	uint32_t alloclen, phys_ofs;
 	uint32_t writtenlen;
@@ -596,7 +600,7 @@
 	c = JFFS2_SB_INFO(dir_i->i_sb);
 	
 	if (S_ISBLK(mode) || S_ISCHR(mode)) {
-		dev = (MAJOR(rdev) << 8) | MINOR(rdev);
+		dev = cpu_to_je16((MAJOR(rdev) << 8) | MINOR(rdev));
 		devlen = sizeof(dev);
 	}
 	
@@ -704,8 +708,7 @@
 		return PTR_ERR(fd);
 	}
 
-	dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(rd->mctime);
-	dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0;
+	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
 
 	jffs2_free_raw_dirent(rd);
 
diff -Nru a/fs/jffs2/erase.c b/fs/jffs2/erase.c
--- a/fs/jffs2/erase.c	Tue Nov 12 08:11:54 2002
+++ b/fs/jffs2/erase.c	Wed May 28 08:01:06 2003
@@ -7,16 +7,17 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: erase.c,v 1.45 2002/10/09 08:27:08 dwmw2 Exp $
+ * $Id: erase.c,v 1.51 2003/05/11 22:47:36 dwmw2 Exp $
  *
  */
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
-#include <linux/interrupt.h>
 #include <linux/compiler.h>
 #include <linux/crc32.h>
+#include <linux/sched.h>
+#include <linux/pagemap.h>
 #include "nodelist.h"
 
 struct erase_priv_struct {
@@ -24,7 +25,10 @@
 	struct jffs2_sb_info *c;
 };
       
+#ifndef __ECOS
 static void jffs2_erase_callback(struct erase_info *);
+#endif
+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
@@ -32,16 +36,25 @@
 void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
 	int ret;
+#ifdef __ECOS
+       ret = jffs2_flash_erase(c, jeb);
+       if (!ret) {
+               jffs2_erase_succeeded(c, jeb);
+               return;
+       }
+#else /* Linux */
 	struct erase_info *instr;
 
 	instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL);
 	if (!instr) {
 		printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
-		spin_lock_bh(&c->erase_completion_lock);
+		spin_lock(&c->erase_completion_lock);
 		list_del(&jeb->list);
 		list_add(&jeb->list, &c->erase_pending_list);
 		c->erasing_size -= c->sector_size;
-		spin_unlock_bh(&c->erase_completion_lock);
+		c->dirty_size += c->sector_size;
+		jeb->dirty_size = c->sector_size;
+		spin_unlock(&c->erase_completion_lock);
 		return;
 	}
 
@@ -65,15 +78,18 @@
 		return;
 
 	kfree(instr);
+#endif /* __ECOS */
 
 	if (ret == -ENOMEM || ret == -EAGAIN) {
 		/* Erase failed immediately. Refile it on the list */
 		D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret));
-		spin_lock_bh(&c->erase_completion_lock);
+		spin_lock(&c->erase_completion_lock);
 		list_del(&jeb->list);
 		list_add(&jeb->list, &c->erase_pending_list);
 		c->erasing_size -= c->sector_size;
-		spin_unlock_bh(&c->erase_completion_lock);
+		c->dirty_size += c->sector_size;
+		jeb->dirty_size = c->sector_size;
+		spin_unlock(&c->erase_completion_lock);
 		return;
 	}
 
@@ -82,20 +98,7 @@
 	else
 		printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret);
 
-	/* Note: This is almost identical to jffs2_erase_failed() except
-	   for the fact that we used spin_lock_bh() not spin_lock(). If
-	   we could use spin_lock_bh() from a BH, we could merge them.
-	   Or if we abandon the idea that MTD drivers may call the erase
-	   callback from a BH, I suppose :)
-	*/
-	spin_lock_bh(&c->erase_completion_lock);
-	c->erasing_size -= c->sector_size;
-	c->bad_size += c->sector_size;
-	list_del(&jeb->list);
-	list_add(&jeb->list, &c->bad_list);
-	c->nr_erasing_blocks--;
-	spin_unlock_bh(&c->erase_completion_lock);
-	wake_up(&c->erase_wait);
+	jffs2_erase_failed(c, jeb);
 }
 
 void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
@@ -104,7 +107,7 @@
 
 	down(&c->erase_free_sem);
 
-	spin_lock_bh(&c->erase_completion_lock);
+	spin_lock(&c->erase_completion_lock);
 
 	while (!list_empty(&c->erase_complete_list) ||
 	       !list_empty(&c->erase_pending_list)) {
@@ -112,7 +115,7 @@
 		if (!list_empty(&c->erase_complete_list)) {
 			jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list);
 			list_del(&jeb->list);
-			spin_unlock_bh(&c->erase_completion_lock);
+			spin_unlock(&c->erase_completion_lock);
 			jffs2_mark_erased_block(c, jeb);
 
 		} else if (!list_empty(&c->erase_pending_list)) {
@@ -126,7 +129,7 @@
 			jeb->used_size = jeb->dirty_size = jeb->free_size = 0;
 			jffs2_free_all_node_refs(c, jeb);
 			list_add(&jeb->list, &c->erasing_list);
-			spin_unlock_bh(&c->erase_completion_lock);
+			spin_unlock(&c->erase_completion_lock);
 
 			jffs2_erase_block(c, jeb);
 
@@ -136,10 +139,10 @@
 
 		/* Be nice */
 		cond_resched();
-		spin_lock_bh(&c->erase_completion_lock);
+		spin_lock(&c->erase_completion_lock);
 	}
 
-	spin_unlock_bh(&c->erase_completion_lock);
+	spin_unlock(&c->erase_completion_lock);
 	D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n"));
 
 	up(&c->erase_free_sem);
@@ -156,8 +159,7 @@
 	jffs2_erase_pending_trigger(c);
 }
 
-
-static inline void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
 	 spin_lock(&c->erase_completion_lock);
 	 c->erasing_size -= c->sector_size;
@@ -169,6 +171,7 @@
 	 wake_up(&c->erase_wait);
 }	 
 
+#ifndef __ECOS
 static void jffs2_erase_callback(struct erase_info *instr)
 {
 	struct erase_priv_struct *priv = (void *)instr->priv;
@@ -181,6 +184,7 @@
 	}	
 	kfree(instr);
 }
+#endif /* !__ECOS */
 
 /* Hmmm. Maybe we should accept the extra space it takes and make
    this a standard doubly-linked list? */
@@ -290,9 +294,9 @@
 			printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n");
 			/* Stick it back on the list from whence it came and come back later */
 			jffs2_erase_pending_trigger(c);
-			spin_lock_bh(&c->erase_completion_lock);
+			spin_lock(&c->erase_completion_lock);
 			list_add(&jeb->list, &c->erase_complete_list);
-			spin_unlock_bh(&c->erase_completion_lock);
+			spin_unlock(&c->erase_completion_lock);
 			return;
 		}
 	}
@@ -313,7 +317,7 @@
 				goto bad;
 			}
 			if (retlen != readlen) {
-				printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %d\n", ofs, readlen, retlen);
+				printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen);
 				goto bad;
 			}
 			for (i=0; i<readlen; i += sizeof(unsigned long)) {
@@ -328,13 +332,13 @@
 						jffs2_write_nand_badblock( c ,jeb );
 					kfree(ebuf);
 				bad2:
-					spin_lock_bh(&c->erase_completion_lock);
+					spin_lock(&c->erase_completion_lock);
 					c->erasing_size -= c->sector_size;
 					c->bad_size += c->sector_size;
 
 					list_add_tail(&jeb->list, &c->bad_list);
 					c->nr_erasing_blocks--;
-					spin_unlock_bh(&c->erase_completion_lock);
+					spin_unlock(&c->erase_completion_lock);
 					wake_up(&c->erase_wait);
 					return;
 				}
@@ -374,7 +378,7 @@
 			goto bad2;
 		}
 		if (retlen != je32_to_cpu(marker.totlen)) {
-			printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %d\n",
+			printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %zd\n",
 			       jeb->offset, je32_to_cpu(marker.totlen), retlen);
 			goto bad2;
 		}
@@ -392,7 +396,7 @@
 		jeb->wasted_size = 0;
 	}
 
-	spin_lock_bh(&c->erase_completion_lock);
+	spin_lock(&c->erase_completion_lock);
 	c->erasing_size -= c->sector_size;
 	c->free_size += jeb->free_size;
 	c->used_size += jeb->used_size;
@@ -403,7 +407,7 @@
 	list_add_tail(&jeb->list, &c->free_list);
 	c->nr_erasing_blocks--;
 	c->nr_free_blocks++;
-	spin_unlock_bh(&c->erase_completion_lock);
+	spin_unlock(&c->erase_completion_lock);
 	wake_up(&c->erase_wait);
 }
 
diff -Nru a/fs/jffs2/file.c b/fs/jffs2/file.c
--- a/fs/jffs2/file.c	Sat Dec 14 15:14:32 2002
+++ b/fs/jffs2/file.c	Wed May 28 08:01:06 2003
@@ -7,12 +7,11 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: file.c,v 1.81 2002/11/12 09:46:22 dwmw2 Exp $
+ * $Id: file.c,v 1.85 2003/05/26 09:50:38 dwmw2 Exp $
  *
  */
 
 #include <linux/kernel.h>
-#include <linux/mtd/compatmac.h> /* for min() */
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/time.h>
@@ -153,17 +152,20 @@
 	if (ivalid & ATTR_MODE)
 		if (iattr->ia_mode & S_ISGID &&
 		    !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID))
-			ri->mode = cpu_to_je32(iattr->ia_mode & ~S_ISGID);
+			ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID);
 		else 
-			ri->mode = cpu_to_je32(iattr->ia_mode);
+			ri->mode = cpu_to_jemode(iattr->ia_mode);
 	else
-		ri->mode = cpu_to_je32(inode->i_mode);
+		ri->mode = cpu_to_jemode(inode->i_mode);
 
 
 	ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size);
-	ri->atime = cpu_to_je32((ivalid & ATTR_ATIME)?iattr->ia_atime.tv_sec:inode->i_atime.tv_sec);
-	ri->mtime = cpu_to_je32((ivalid & ATTR_MTIME)?iattr->ia_mtime.tv_sec:inode->i_mtime.tv_sec);
-	ri->ctime = cpu_to_je32((ivalid & ATTR_CTIME)?iattr->ia_ctime.tv_sec:inode->i_ctime.tv_sec);
+	ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime));
+	ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime));
+	ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime));
+
+	ri->offset = cpu_to_je32(0);
+	ri->csize = ri->dsize = cpu_to_je32(mdatalen);
 	ri->compr = JFFS2_COMPR_NONE;
 	if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
 		/* It's an extension. Make it a hole node */
@@ -188,13 +190,10 @@
 		return PTR_ERR(new_metadata);
 	}
 	/* It worked. Update the inode */
-	inode->i_atime.tv_sec = je32_to_cpu(ri->atime);
-	inode->i_ctime.tv_sec = je32_to_cpu(ri->ctime);
-	inode->i_mtime.tv_sec = je32_to_cpu(ri->mtime);
-	inode->i_atime.tv_nsec =
-	inode->i_ctime.tv_nsec =
-	inode->i_mtime.tv_nsec = 0;
-	inode->i_mode = je32_to_cpu(ri->mode);
+	inode->i_atime = ITIME(je32_to_cpu(ri->atime));
+	inode->i_ctime = ITIME(je32_to_cpu(ri->ctime));
+	inode->i_mtime = ITIME(je32_to_cpu(ri->mtime));
+	inode->i_mode = jemode_to_cpu(ri->mode);
 	inode->i_uid = je16_to_cpu(ri->uid);
 	inode->i_gid = je16_to_cpu(ri->gid);
 
@@ -309,7 +308,7 @@
 
 		ri.ino = cpu_to_je32(f->inocache->ino);
 		ri.version = cpu_to_je32(++f->highest_version);
-		ri.mode = cpu_to_je32(inode->i_mode);
+		ri.mode = cpu_to_jemode(inode->i_mode);
 		ri.uid = cpu_to_je16(inode->i_uid);
 		ri.gid = cpu_to_je16(inode->i_gid);
 		ri.isize = cpu_to_je32(max((uint32_t)inode->i_size, pageofs));
@@ -390,7 +389,7 @@
 
 	/* Set the fields that the generic jffs2_write_inode_range() code can't find */
 	ri->ino = cpu_to_je32(inode->i_ino);
-	ri->mode = cpu_to_je32(inode->i_mode);
+	ri->mode = cpu_to_jemode(inode->i_mode);
 	ri->uid = cpu_to_je16(inode->i_uid);
 	ri->gid = cpu_to_je16(inode->i_gid);
 	ri->isize = cpu_to_je32((uint32_t)inode->i_size);
@@ -416,8 +415,7 @@
 			inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen;
 			inode->i_blocks = (inode->i_size + 511) >> 9;
 			
-			inode->i_ctime.tv_sec = inode->i_mtime.tv_sec = je32_to_cpu(ri->ctime);
-			inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0;
+			inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime));
 		}
 	}
 
diff -Nru a/fs/jffs2/fs.c b/fs/jffs2/fs.c
--- a/fs/jffs2/fs.c	Tue Dec 31 17:25:18 2002
+++ b/fs/jffs2/fs.c	Wed May 28 08:01:06 2003
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: fs.c,v 1.19 2002/11/12 09:53:40 dwmw2 Exp $
+ * $Id: fs.c,v 1.24 2003/04/29 09:52:58 dwmw2 Exp $
  *
  */
 
@@ -16,7 +16,6 @@
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/mtd/mtd.h>
 #include <linux/pagemap.h>
 #include <linux/slab.h>
@@ -35,7 +34,7 @@
 	buf->f_ffree = 0;
 	buf->f_namelen = JFFS2_MAX_NAME_LEN;
 
-	spin_lock_bh(&c->erase_completion_lock);
+	spin_lock(&c->erase_completion_lock);
 
 	avail = c->dirty_size + c->free_size;
 	if (avail > c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE)
@@ -47,7 +46,7 @@
 
 	D1(jffs2_dump_block_lists(c));
 
-	spin_unlock_bh(&c->erase_completion_lock);
+	spin_unlock(&c->erase_completion_lock);
 
 	return 0;
 }
@@ -87,16 +86,13 @@
 		up(&f->sem);
 		return;
 	}
-	inode->i_mode = je32_to_cpu(latest_node.mode);
+	inode->i_mode = jemode_to_cpu(latest_node.mode);
 	inode->i_uid = je16_to_cpu(latest_node.uid);
 	inode->i_gid = je16_to_cpu(latest_node.gid);
 	inode->i_size = je32_to_cpu(latest_node.isize);
-	inode->i_atime.tv_sec = je32_to_cpu(latest_node.atime);
-	inode->i_mtime.tv_sec = je32_to_cpu(latest_node.mtime);
-	inode->i_ctime.tv_sec = je32_to_cpu(latest_node.ctime);
-	inode->i_atime.tv_nsec =
-	inode->i_mtime.tv_nsec =
-	inode->i_ctime.tv_nsec = 0;
+	inode->i_atime = ITIME(je32_to_cpu(latest_node.atime));
+	inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime));
+	inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime));
 
 	inode->i_nlink = f->inocache->nlink;
 
@@ -104,7 +100,7 @@
 	inode->i_blocks = (inode->i_size + 511) >> 9;
 	
 	switch (inode->i_mode & S_IFMT) {
-		unsigned short rdev;
+		jint16_t rdev;
 
 	case S_IFLNK:
 		inode->i_op = &jffs2_symlink_inode_operations;
@@ -151,7 +147,7 @@
 	case S_IFSOCK:
 	case S_IFIFO:
 		inode->i_op = &jffs2_file_inode_operations;
-		init_special_inode(inode, inode->i_mode, kdev_t_to_nr(mk_kdev(rdev>>8, rdev&0xff)));
+		init_special_inode(inode, inode->i_mode, kdev_t_to_nr(mk_kdev(je16_to_cpu(rdev)>>8, je16_to_cpu(rdev)&0xff)));
 		break;
 
 	default:
@@ -232,7 +228,7 @@
 	} else {
 		ri->gid = cpu_to_je16(current->fsgid);
 	}
-	ri->mode =  cpu_to_je32(mode);
+	ri->mode =  cpu_to_jemode(mode);
 	ret = jffs2_do_new_inode (c, f, mode, ri);
 	if (ret) {
 		make_bad_inode(inode);
@@ -241,12 +237,11 @@
 	}
 	inode->i_nlink = 1;
 	inode->i_ino = je32_to_cpu(ri->ino);
-	inode->i_mode = je32_to_cpu(ri->mode);
+	inode->i_mode = jemode_to_cpu(ri->mode);
 	inode->i_gid = je16_to_cpu(ri->gid);
 	inode->i_uid = je16_to_cpu(ri->uid);
-	inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0;
-	inode->i_atime.tv_sec = inode->i_ctime.tv_sec = inode->i_mtime.tv_sec = get_seconds();
-	ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime.tv_sec);
+	inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+	ri->atime = ri->mtime = ri->ctime = cpu_to_je32(I_SEC(inode->i_mtime));
 
 	inode->i_blksize = PAGE_SIZE;
 	inode->i_blocks = 0;
@@ -263,27 +258,32 @@
 	struct jffs2_sb_info *c;
 	struct inode *root_i;
 	int ret;
+	size_t blocks;
 
 	c = JFFS2_SB_INFO(sb);
 
-	c->sector_size = c->mtd->erasesize;
 	c->flash_size = c->mtd->size;
 
-#if 0
-	if (c->sector_size < 0x10000) {
-		printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using 64KiB instead\n",
-		       c->sector_size / 1024);
-		c->sector_size = 0x10000;
-	}
-#endif
+	/* 
+	 * Check, if we have to concatenate physical blocks to larger virtual blocks
+	 * to reduce the memorysize for c->blocks. (kmalloc allows max. 128K allocation)
+	 */
+	blocks = c->flash_size / c->mtd->erasesize;
+	while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024))
+		blocks >>= 1;
+	
+	c->sector_size = c->flash_size / blocks;
+	if (c->sector_size != c->mtd->erasesize)
+		printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using virtual blocks size (%dKiB) instead\n", 
+			c->mtd->erasesize / 1024, c->sector_size / 1024);
+
 	if (c->flash_size < 5*c->sector_size) {
-		printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n",
-		       c->flash_size / c->sector_size);
+		printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n", c->flash_size / c->sector_size);
 		return -EINVAL;
 	}
 
 	c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
-	/* Jörn -- stick alignment for weird 8-byte-page flash here */
+	/* Joern -- stick alignment for weird 8-byte-page flash here */
 
 	if (jffs2_cleanmarker_oob(c)) {
 		/* Cleanmarker is out-of-band, so inline size zero */
diff -Nru a/fs/jffs2/gc.c b/fs/jffs2/gc.c
--- a/fs/jffs2/gc.c	Tue Nov 12 08:11:54 2002
+++ b/fs/jffs2/gc.c	Wed May 28 08:01:06 2003
@@ -7,19 +7,22 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: gc.c,v 1.88 2002/10/08 16:56:08 dwmw2 Exp $
+ * $Id: gc.c,v 1.103 2003/05/22 18:01:02 dwmw2 Exp $
  *
  */
 
 #include <linux/kernel.h>
 #include <linux/mtd/mtd.h>
 #include <linux/slab.h>
-#include <linux/interrupt.h>
 #include <linux/pagemap.h>
 #include <linux/crc32.h>
 #include <linux/compiler.h>
+#include <linux/stat.h>
 #include "nodelist.h"
 
+static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, 
+					  struct jffs2_inode_cache *ic,
+					  struct jffs2_raw_node_ref *raw);
 static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
 					struct jffs2_inode_info *f, struct jffs2_full_dnode *fd);
 static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
@@ -32,6 +35,8 @@
 static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
 				       struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
 				       uint32_t start, uint32_t end);
+static int jffs2_garbage_collect_live(struct jffs2_sb_info *c,  struct jffs2_eraseblock *jeb,
+			       struct jffs2_raw_node_ref *raw, struct jffs2_inode_cache *ic);
 
 /* Called with erase_completion_lock held */
 static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
@@ -107,61 +112,87 @@
  */
 int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
 {
+	struct jffs2_inode_cache *ic;
 	struct jffs2_eraseblock *jeb;
-	struct jffs2_inode_info *f;
 	struct jffs2_raw_node_ref *raw;
-	struct jffs2_node_frag *frag;
-	struct jffs2_full_dnode *fn = NULL;
-	struct jffs2_full_dirent *fd;
-	uint32_t start = 0, end = 0, nrfrags = 0;
 	uint32_t inum;
-	struct inode *inode;
 	int ret = 0;
 
 	if (down_interruptible(&c->alloc_sem))
 		return -EINTR;
 
-	spin_lock_bh(&c->erase_completion_lock);
+	for (;;) {
+		spin_lock(&c->erase_completion_lock);
+		if (!c->unchecked_size)
+			break;
 
-	while (c->unchecked_size) {
 		/* We can't start doing GC yet. We haven't finished checking
-		   the node CRCs etc. Do it now and wait for it. */
-		struct jffs2_inode_cache *ic;
-
+		   the node CRCs etc. Do it now. */
+		
+		/* checked_ino is protected by the alloc_sem */
 		if (c->checked_ino > c->highest_ino) {
 			printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n",
 			       c->unchecked_size);
 			D1(jffs2_dump_block_lists(c));
+			spin_unlock(&c->erase_completion_lock);
 			BUG();
 		}
+
+		spin_unlock(&c->erase_completion_lock);
+
+		spin_lock(&c->inocache_lock);
+
 		ic = jffs2_get_ino_cache(c, c->checked_ino++);
-		if (!ic)
+
+		if (!ic) {
+			spin_unlock(&c->inocache_lock);
 			continue;
+		}
+
 		if (!ic->nlink) {
 			D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n",
 				  ic->ino));
+			spin_unlock(&c->inocache_lock);
 			continue;
 		}
-		if (ic->state != INO_STATE_UNCHECKED) {
-			D1(printk(KERN_DEBUG "Skipping check of ino #%d already in state %d\n",
-				  ic->ino, ic->state));
+		switch(ic->state) {
+		case INO_STATE_CHECKEDABSENT:
+		case INO_STATE_PRESENT:
+			D1(printk(KERN_DEBUG "Skipping ino #%u already checked\n", ic->ino));
+			spin_unlock(&c->inocache_lock);
 			continue;
-		}
 
-		spin_unlock_bh(&c->erase_completion_lock);
+		case INO_STATE_GC:
+		case INO_STATE_CHECKING:
+			printk(KERN_WARNING "Inode #%u is in state %d during CRC check phase!\n", ic->ino, ic->state);
+			spin_unlock(&c->inocache_lock);
+			BUG();
 
-		D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%d\n", ic->ino));
-		
-		{
-			/* XXX: This wants doing more sensibly -- split the core of jffs2_do_read_inode up */
-			struct inode *i = iget(OFNI_BS_2SFFJ(c), ic->ino);
-			if (is_bad_inode(i)) {
-				printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", ic->ino);
-				ret = -EIO;
-			}
-			iput(i);
+		case INO_STATE_READING:
+			/* We need to wait for it to finish, lest we move on
+			   and trigger the BUG() above while we haven't yet 
+			   finished checking all its nodes */
+			D1(printk(KERN_DEBUG "Waiting for ino #%u to finish reading\n", ic->ino));
+			up(&c->alloc_sem);
+			sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
+			return 0;
+
+		default:
+			BUG();
+
+		case INO_STATE_UNCHECKED:
+			;
 		}
+		ic->state = INO_STATE_CHECKING;
+		spin_unlock(&c->inocache_lock);
 
+		D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%d\n", ic->ino));
+
+		ret = jffs2_do_crccheck_inode(c, ic);
+		if (ret)
+			printk(KERN_WARNING "Returned error for crccheck of ino #%u. Expect badness...\n", ic->ino);
+
+		jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT);
 		up(&c->alloc_sem);
 		return ret;
 	}
@@ -174,7 +205,7 @@
 
 	if (!jeb) {
 		printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n");
-		spin_unlock_bh(&c->erase_completion_lock);
+		spin_unlock(&c->erase_completion_lock);
 		up(&c->alloc_sem);
 		return -EIO;
 	}
@@ -197,7 +228,7 @@
 			printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n");
 			printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n", 
 			       jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size);
-			spin_unlock_bh(&c->erase_completion_lock);
+			spin_unlock(&c->erase_completion_lock);
 			up(&c->alloc_sem);
 			BUG();
 		}
@@ -207,7 +238,7 @@
 		/* Inode-less node. Clean marker, snapshot or something like that */
 		/* FIXME: If it's something that needs to be copied, including something
 		   we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */
-		spin_unlock_bh(&c->erase_completion_lock);
+		spin_unlock(&c->erase_completion_lock);
 		jffs2_mark_node_obsolete(c, raw);
 		up(&c->alloc_sem);
 		goto eraseit_lock;
@@ -216,13 +247,136 @@
 	inum = jffs2_raw_ref_to_inum(raw);
 	D1(printk(KERN_DEBUG "Inode number is #%u\n", inum));
 
-	spin_unlock_bh(&c->erase_completion_lock);
+	spin_unlock(&c->erase_completion_lock);
+
+	D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n", jeb->offset, ref_offset(raw), ref_flags(raw), inum));
+
+	/* Three possibilities:
+	   1. Inode is already in-core. We must iget it and do proper
+	      updating to its fragtree, etc.
+	   2. Inode is not in-core, node is REF_PRISTINE. We lock the
+	      inocache to prevent a read_inode(), copy the node intact.
+	   3. Inode is not in-core, node is not pristine. We must iget()
+	      and take the slow path.
+	*/
+	spin_lock(&c->inocache_lock);
+	ic = jffs2_get_ino_cache(c, inum);
+
+	/* This should never fail unless I'm particularly stupid.
+	   So we don't check before dereferencing it */
+
+	switch(ic->state) {
+	case INO_STATE_CHECKEDABSENT:
+		/* It's been checked, but it's not currently in-core. 
+		   We can just copy any pristine nodes, but have
+		   to prevent anyone else from doing read_inode() while
+		   we're at it, so we set the state accordingly */
+		if (ref_flags(raw) == REF_PRISTINE)
+			ic->state = INO_STATE_GC;
+		else {
+			D1(printk("Ino #%u is absent but node not REF_PRISTINE. Reading.\n", 
+				  inum));
+		}
+		break;
+
+	case INO_STATE_PRESENT:
+	case INO_STATE_UNCHECKED:
+		/* It's in-core or hasn't been checked. GC must iget() it. */
+		break;
+
+	case INO_STATE_CHECKING:
+		/* Should never happen. We should have finished checking
+		   by the time we actually start doing any GC. */
+		BUG();
+
+	
+	case INO_STATE_GC:
+		/* Should never happen. We are holding the alloc_sem, 
+		   no other garbage collection can happen. Note that we
+		   do depend on this later when deciding to do a simple
+		   node copy */
+		BUG();
+			 
+	case INO_STATE_READING:
+		/* Someone's currently trying to read it. We must wait for
+		   them to finish and then go through the full iget() route
+		   to do the GC. However, sometimes read_inode() needs to get
+		   the alloc_sem() (for marking nodes invalid) so we must
+		   drop the alloc_sem before sleeping. */
+
+		up(&c->alloc_sem);
+		D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n",
+			  inum, ic->state));
+		sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
+		/* And because we dropped the alloc_sem we must start again from the 
+		   beginning. Ponder chance of livelock here -- we're returning success
+		   without actually making any progress.
+
+		   Q: What are the chances that the inode is back in INO_STATE_READING 
+		   again by the time we next enter this function? And that this happens
+		   enough times to cause a real delay?
+
+		   A: Small enough that I don't care :) 
+		*/
+		return 0;
+
+	}
+
+	spin_unlock(&c->inocache_lock);
+
+	/* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the
+	   node intact, and we don't have to muck about with the fragtree etc. 
+	   because we know it's not in-core. If it _was_ in-core, we go through
+	   all the iget() crap anyway */
+
+	if (ic->state == INO_STATE_GC) {
+		ret = jffs2_garbage_collect_pristine(c, ic, raw);
+		jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT);
+
+		if (ret != -EBADFD)
+			goto release_sem;
+
+		/* Fall through if it wanted us to */
+	}
+
+	ret = jffs2_garbage_collect_live(c, jeb, raw, ic);
+
+ release_sem:
+	up(&c->alloc_sem);
+
+ eraseit_lock:
+	/* If we've finished this block, start it erasing */
+	spin_lock(&c->erase_completion_lock);
+
+ eraseit:
+	if (c->gcblock && !c->gcblock->used_size) {
+		D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset));
+		/* We're GC'ing an empty block? */
+		list_add_tail(&c->gcblock->list, &c->erase_pending_list);
+		c->gcblock = NULL;
+		c->nr_erasing_blocks++;
+		jffs2_erase_pending_trigger(c);
+	}
+	spin_unlock(&c->erase_completion_lock);
+
+	return ret;
+}
 
-	D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x, ino #%u\n", jeb->offset, ref_offset(raw), inum));
 
-	inode = iget(OFNI_BS_2SFFJ(c), inum);
+static int jffs2_garbage_collect_live(struct jffs2_sb_info *c,  struct jffs2_eraseblock *jeb,
+			       struct jffs2_raw_node_ref *raw, struct jffs2_inode_cache *ic)
+{
+	struct jffs2_inode_info *f;
+	struct jffs2_node_frag *frag;
+	struct jffs2_full_dnode *fn = NULL;
+	struct jffs2_full_dirent *fd;
+	uint32_t start = 0, end = 0, nrfrags = 0;
+	struct inode *inode;
+	int ret = 0;
+
+	inode = iget(OFNI_BS_2SFFJ(c), ic->ino);
 	if (is_bad_inode(inode)) {
-		printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", inum);
+		printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", ic->ino);
 		/* NB. This will happen again. We need to do something appropriate here. */
 		up(&c->alloc_sem);
 		iput(inode);
@@ -254,16 +408,26 @@
 			end = frag->ofs + frag->size;
 #if 1 /* Temporary debugging sanity checks, till we're ready to _trust_ the REF_PRISTINE flag stuff */ 
 			if (!nrfrags && ref_flags(fn->raw) == REF_PRISTINE) {
-				if (fn->frags > 1)
+				if (fn->frags > 1) {
 					printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(raw), fn->frags);
-
-				if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->node)
+					mark_ref_normal(raw);
+				}
+				/* A hole node which isn't multi-page should be garbage-collected
+				   and merged anyway, so we just check for the frag size here,
+				   rather than mucking around with actually reading the node
+				   and checking the compression type, which is the real way
+				   to tell a hole node. */
+				if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->size < PAGE_CACHE_SIZE) {
 					printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n",
 					       ref_offset(raw));
+					mark_ref_normal(raw);
+				}
 
-				if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->node)
+				if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->size < PAGE_CACHE_SIZE) {
 					printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n",
 					       ref_offset(raw), frag->ofs, frag->ofs+frag->size);
+					mark_ref_normal(raw);
+				}
 			}
 #endif
 			if (!nrfrags++)
@@ -273,6 +437,15 @@
 		}
 	}
 	if (fn) {
+		if (ref_flags(raw) == REF_PRISTINE) {
+			ret = jffs2_garbage_collect_pristine(c, ic, raw);
+			if (!ret) {
+				/* Urgh. Return it sensibly. */
+				frag->node->raw = ic->nodes;
+			}	
+			if (ret != -EBADFD)
+				goto upnout;
+		}
 		/* We found a datanode. Do the GC */
 		if((start >> PAGE_CACHE_SHIFT) < ((end-1) >> PAGE_CACHE_SHIFT)) {
 			/* It crosses a page boundary. Therefore, it must be a hole. */
@@ -305,25 +478,145 @@
 	}
  upnout:
 	up(&f->sem);
-	up(&c->alloc_sem);
 	iput(inode);
 
- eraseit_lock:
-	/* If we've finished this block, start it erasing */
-	spin_lock_bh(&c->erase_completion_lock);
+	return ret;
+}
 
- eraseit:
-	if (c->gcblock && !c->gcblock->used_size) {
-		D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset));
-		/* We're GC'ing an empty block? */
-		list_add_tail(&c->gcblock->list, &c->erase_pending_list);
-		c->gcblock = NULL;
-		c->nr_erasing_blocks++;
-		jffs2_erase_pending_trigger(c);
+static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, 
+					  struct jffs2_inode_cache *ic,
+					  struct jffs2_raw_node_ref *raw)
+{
+	union jffs2_node_union *node;
+	struct jffs2_raw_node_ref *nraw;
+	size_t retlen;
+	int ret;
+	uint32_t phys_ofs, alloclen;
+	uint32_t crc;
+
+	D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw)));
+
+	/* Ask for a small amount of space (or the totlen if smaller) because we
+	   don't want to force wastage of the end of a block if splitting would
+	   work. */
+	ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN, raw->totlen),
+				     &phys_ofs, &alloclen);
+	if (ret)
+		return ret;
+
+	if (alloclen < raw->totlen) {
+		/* Doesn't fit untouched. We'll go the old route and split it */
+		return -EBADFD;
+	}
+
+	node = kmalloc(raw->totlen, GFP_KERNEL);
+	if (!node)
+               return -ENOMEM;
+
+	ret = jffs2_flash_read(c, ref_offset(raw), raw->totlen, &retlen, (char *)node);
+	if (!ret && retlen != raw->totlen)
+		ret = -EIO;
+	if (ret)
+		goto out_node;
+
+	crc = crc32(0, node, sizeof(struct jffs2_unknown_node)-4);
+	if (je32_to_cpu(node->u.hdr_crc) != crc) {
+		printk(KERN_WARNING "Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+		       ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc);
+		goto bail;
+	}
+
+	switch(je16_to_cpu(node->u.nodetype)) {
+	case JFFS2_NODETYPE_INODE:
+		crc = crc32(0, node, sizeof(node->i)-8);
+		if (je32_to_cpu(node->i.node_crc) != crc) {
+			printk(KERN_WARNING "Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+			       ref_offset(raw), je32_to_cpu(node->i.node_crc), crc);
+			goto bail;
+		}
+
+		if (je32_to_cpu(node->i.dsize)) {
+			crc = crc32(0, node->i.data, je32_to_cpu(node->i.csize));
+			if (je32_to_cpu(node->i.data_crc) != crc) {
+				printk(KERN_WARNING "Data CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+				       ref_offset(raw), je32_to_cpu(node->i.data_crc), crc);
+				goto bail;
+			}
+		}
+		break;
+
+	case JFFS2_NODETYPE_DIRENT:
+		crc = crc32(0, node, sizeof(node->d)-8);
+		if (je32_to_cpu(node->d.node_crc) != crc) {
+			printk(KERN_WARNING "Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+			       ref_offset(raw), je32_to_cpu(node->d.node_crc), crc);
+			goto bail;
+		}
+
+		if (node->d.nsize) {
+			crc = crc32(0, node->d.name, node->d.nsize);
+			if (je32_to_cpu(node->d.name_crc) != crc) {
+				printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent ode at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+				       ref_offset(raw), je32_to_cpu(node->d.name_crc), crc);
+				goto bail;
+			}
+		}
+		break;
+	default:
+		printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", 
+		       ref_offset(raw), je16_to_cpu(node->u.nodetype));
+		goto bail;
+	}
+
+	nraw = jffs2_alloc_raw_node_ref();
+	if (!nraw) {
+		ret = -ENOMEM;
+		goto out_node;
+	}
+	nraw->flash_offset = phys_ofs;
+	nraw->totlen = raw->totlen;
+	nraw->next_phys = NULL;
+
+	/* OK, all the CRCs are good; this node can just be copied as-is. */
+
+	ret = jffs2_flash_write(c, phys_ofs, raw->totlen, &retlen, (char *)node);
+	if (ret || (retlen != raw->totlen)) {
+		printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n",
+                       raw->totlen, phys_ofs, ret, retlen);
+		if (retlen) {
+                        /* Doesn't belong to any inode */
+			nraw->next_in_ino = NULL;
+
+			nraw->flash_offset |= REF_OBSOLETE;
+			jffs2_add_physical_node_ref(c, nraw);
+			jffs2_mark_node_obsolete(c, nraw);
+		} else {
+			printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset);
+                        jffs2_free_raw_node_ref(raw);
+		}
+		if (!ret)
+			ret = -EIO;
+		goto out_node;
 	}
-	spin_unlock_bh(&c->erase_completion_lock);
+	nraw->flash_offset |= REF_PRISTINE;
+	jffs2_add_physical_node_ref(c, nraw);
+
+	/* Link into per-inode list. This is safe because of the ic
+	   state being INO_STATE_GC. Note that if we're doing this
+	   for an inode which is in-code, the 'nraw' pointer is then
+	   going to be fetched from ic->nodes by our caller. */
+        nraw->next_in_ino = ic->nodes;
+        ic->nodes = nraw;
 
+	jffs2_mark_node_obsolete(c, raw);
+	D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw)));
+
+ out_node:
+	kfree(node);
 	return ret;
+ bail:
+	ret = -EBADFD;
+	goto out_node;
 }
 
 static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
@@ -331,7 +624,7 @@
 {
 	struct jffs2_full_dnode *new_fn;
 	struct jffs2_raw_inode ri;
-	unsigned short dev;
+	jint16_t dev;
 	char *mdata = NULL, mdatalen = 0;
 	uint32_t alloclen, phys_ofs;
 	int ret;
@@ -340,8 +633,8 @@
 	    S_ISCHR(JFFS2_F_I_MODE(f)) ) {
 		/* For these, we don't actually need to read the old node */
 		/* FIXME: for minor or major > 255. */
-		dev =  ((JFFS2_F_I_RDEV_MAJ(f) << 8) | 
-			JFFS2_F_I_RDEV_MIN(f));
+		dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) | 
+			JFFS2_F_I_RDEV_MIN(f)));
 		mdata = (char *)&dev;
 		mdatalen = sizeof(dev);
 		D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen));
@@ -364,7 +657,7 @@
 	
 	ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen);
 	if (ret) {
-		printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_metadata failed: %d\n",
+		printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n",
 		       sizeof(ri)+ mdatalen, ret);
 		goto out;
 	}
@@ -377,7 +670,7 @@
 
 	ri.ino = cpu_to_je32(f->inocache->ino);
 	ri.version = cpu_to_je32(++f->highest_version);
-	ri.mode = cpu_to_je32(JFFS2_F_I_MODE(f));
+	ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));
 	ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
 	ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
 	ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
@@ -431,7 +724,7 @@
 	
 	ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen);
 	if (ret) {
-		printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dirent failed: %d\n",
+		printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n",
 		       sizeof(rd)+rd.nsize, ret);
 		return ret;
 	}
@@ -489,7 +782,7 @@
 				continue;
 			}
 			if (retlen != sizeof(struct jffs2_unknown_node)) {
-				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading header from obsolete node at %08x\n",
+				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %zd) reading header from obsolete node at %08x\n",
 				       retlen, sizeof(struct jffs2_unknown_node), ref_offset(raw));
 				continue;
 			}
@@ -506,7 +799,7 @@
 				continue;
 			}
 			if (retlen != sizeof(rd)) {
-				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading from obsolete node at %08x\n",
+				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %zd) reading from obsolete node at %08x\n",
 				       retlen, sizeof(rd), ref_offset(raw));
 				continue;
 			}
@@ -534,7 +827,7 @@
 				continue;
 			}
 			if (retlen != name_len+1) {
-				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading name from obsolete node at %08x\n",
+				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %d) reading name from obsolete node at %08x\n",
 				       retlen, name_len+1, ref_offset(raw));
 				continue;
 			}
@@ -597,7 +890,7 @@
 		   write it out again with the _same_ version as before */
 		ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri);
 		if (readlen != sizeof(ri) || ret) {
-			printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %d. Data will be lost by writing new hole node\n", ret, readlen);
+			printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %zd. Data will be lost by writing new hole node\n", ret, readlen);
 			goto fill;
 		}
 		if (je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE) {
@@ -607,7 +900,7 @@
 			return -EIO;
 		}
 		if (je32_to_cpu(ri.totlen) != sizeof(ri)) {
-			printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%x\n",
+			printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%zx\n",
 			       ref_offset(fn->raw),
 			       je32_to_cpu(ri.totlen), sizeof(ri));
 			return -EIO;
@@ -642,7 +935,7 @@
 		ri.csize = cpu_to_je32(0);
 		ri.compr = JFFS2_COMPR_ZERO;
 	}
-	ri.mode = cpu_to_je32(JFFS2_F_I_MODE(f));
+	ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));
 	ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
 	ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
 	ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
@@ -654,7 +947,7 @@
 
 	ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen);
 	if (ret) {
-		printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_hole failed: %d\n",
+		printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n",
 		       sizeof(ri), ret);
 		return ret;
 	}
@@ -762,8 +1055,11 @@
 	 *    page OK. We'll actually write it out again in commit_write, which is a little
 	 *    suboptimal, but at least we're correct.
 	 */
+#ifdef __ECOS
+	pg = read_cache_page(start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode);
+#else
 	pg = read_cache_page(inode->i_mapping, start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode);
-
+#endif
 	if (IS_ERR(pg)) {
 		printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg));
 		return PTR_ERR(pg);
@@ -780,11 +1076,11 @@
 		ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen);
 
 		if (ret) {
-			printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dnode failed: %d\n",
+			printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n",
 			       sizeof(ri)+ JFFS2_MIN_DATA_LEN, ret);
 			break;
 		}
-		cdatalen = min(alloclen - sizeof(ri), end - offset);
+		cdatalen = min_t(uint32_t, alloclen - sizeof(ri), end - offset);
 		datalen = end - offset;
 
 		writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1));
@@ -804,7 +1100,7 @@
 
 		ri.ino = cpu_to_je32(f->inocache->ino);
 		ri.version = cpu_to_je32(++f->highest_version);
-		ri.mode = cpu_to_je32(JFFS2_F_I_MODE(f));
+		ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));
 		ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
 		ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
 		ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
diff -Nru a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c
--- a/fs/jffs2/malloc.c	Sun May 25 14:07:56 2003
+++ b/fs/jffs2/malloc.c	Wed May 28 08:01:06 2003
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: malloc.c,v 1.22 2002/05/20 14:56:38 dwmw2 Exp $
+ * $Id: malloc.c,v 1.24 2003/03/11 17:30:29 gleixner Exp $
  *
  */
 
@@ -23,6 +23,9 @@
 #define JFFS2_SLAB_POISON 0
 #endif
 
+// replace this by #define D3 (x) x for cache debugging
+#define D3(x)
+
 /* These are initialised to NULL in the kernel startup code.
    If you're porting to other operating systems, beware */
 static kmem_cache_t *full_dnode_slab;
@@ -73,8 +76,7 @@
 
 	inode_cache_slab = kmem_cache_create("jffs2_inode_cache",
 					     sizeof(struct jffs2_inode_cache),
-					     0, JFFS2_SLAB_POISON|SLAB_RECLAIM_ACCOUNT, 
-					     NULL, NULL);
+					     0, JFFS2_SLAB_POISON, NULL, NULL);
 	if (inode_cache_slab)
 		return 0;
  err:
@@ -112,75 +114,92 @@
 
 struct jffs2_full_dnode *jffs2_alloc_full_dnode(void)
 {
-	void *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL);
+	struct jffs2_full_dnode *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL);
+	D3 (printk (KERN_DEBUG "alloc_full_dnode at %p\n", ret));
 	return ret;
 }
 
 void jffs2_free_full_dnode(struct jffs2_full_dnode *x)
 {
+	D3 (printk (KERN_DEBUG "free full_dnode at %p\n", x));
 	kmem_cache_free(full_dnode_slab, x);
 }
 
 struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void)
 {
-	return kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL);
+	struct jffs2_raw_dirent *ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL);
+	D3 (printk (KERN_DEBUG "alloc_raw_dirent\n", ret));
+	return ret;
 }
 
 void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x)
 {
+	D3 (printk (KERN_DEBUG "free_raw_dirent at %p\n", x));
 	kmem_cache_free(raw_dirent_slab, x);
 }
 
 struct jffs2_raw_inode *jffs2_alloc_raw_inode(void)
 {
-	return kmem_cache_alloc(raw_inode_slab, GFP_KERNEL);
+	struct jffs2_raw_inode *ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL);
+	D3 (printk (KERN_DEBUG "alloc_raw_inode at %p\n", ret));
+	return ret;
 }
 
 void jffs2_free_raw_inode(struct jffs2_raw_inode *x)
 {
+	D3 (printk (KERN_DEBUG "free_raw_inode at %p\n", x));
 	kmem_cache_free(raw_inode_slab, x);
 }
 
 struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void)
 {
-	return kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL);
+	struct jffs2_tmp_dnode_info *ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL);
+	D3 (printk (KERN_DEBUG "alloc_tmp_dnode_info at %p\n", ret));
+	return ret;
 }
 
 void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x)
 {
+	D3 (printk (KERN_DEBUG "free_tmp_dnode_info at %p\n", x));
 	kmem_cache_free(tmp_dnode_info_slab, x);
 }
 
 struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void)
 {
-	return kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL);
+	struct jffs2_raw_node_ref *ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL);
+	D3 (printk (KERN_DEBUG "alloc_raw_node_ref at %p\n", ret));
+	return ret;
 }
 
 void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x)
 {
+	D3 (printk (KERN_DEBUG "free_raw_node_ref at %p\n", x));
 	kmem_cache_free(raw_node_ref_slab, x);
 }
 
 struct jffs2_node_frag *jffs2_alloc_node_frag(void)
 {
-	return kmem_cache_alloc(node_frag_slab, GFP_KERNEL);
+	struct jffs2_node_frag *ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL);
+	D3 (printk (KERN_DEBUG "alloc_node_frag at %p\n", ret));
+	return ret;
 }
 
 void jffs2_free_node_frag(struct jffs2_node_frag *x)
 {
+	D3 (printk (KERN_DEBUG "free_node_frag at %p\n", x));
 	kmem_cache_free(node_frag_slab, x);
 }
 
 struct jffs2_inode_cache *jffs2_alloc_inode_cache(void)
 {
 	struct jffs2_inode_cache *ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL);
-	D1(printk(KERN_DEBUG "Allocated inocache at %p\n", ret));
+	D3 (printk(KERN_DEBUG "Allocated inocache at %p\n", ret));
 	return ret;
 }
 
 void jffs2_free_inode_cache(struct jffs2_inode_cache *x)
 {
-	D1(printk(KERN_DEBUG "Freeing inocache at %p\n", x));
+	D3 (printk(KERN_DEBUG "Freeing inocache at %p\n", x));
 	kmem_cache_free(inode_cache_slab, x);
 }
 
diff -Nru a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
--- a/fs/jffs2/nodelist.c	Tue Nov 12 08:11:55 2002
+++ b/fs/jffs2/nodelist.c	Wed May 28 08:01:06 2003
@@ -7,17 +7,18 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.c,v 1.65 2002/11/12 09:50:13 dwmw2 Exp $
+ * $Id: nodelist.c,v 1.79 2003/04/08 08:20:01 dwmw2 Exp $
  *
  */
 
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/mtd/mtd.h>
-#include <linux/interrupt.h>
 #include <linux/rbtree.h>
 #include <linux/crc32.h>
 #include <linux/slab.h>
+#include <linux/pagemap.h>
 #include "nodelist.h"
 
 void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list)
@@ -112,10 +113,10 @@
 
 	D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%lu\n", ino));
 	if (!f->inocache->nodes) {
-		printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", ino);
+		printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", (unsigned long)ino);
 	}
 
-	spin_lock_bh(&c->erase_completion_lock);
+	spin_lock(&c->erase_completion_lock);
 
 	for (ref = f->inocache->nodes; ref && ref->next_in_ino; ref = ref->next_in_ino) {
 		/* Work out whether it's a data node or a dirent node */
@@ -127,12 +128,12 @@
 		/* We can hold a pointer to a non-obsolete node without the spinlock,
 		   but _obsolete_ nodes may disappear at any time, if the block
 		   they're in gets erased */
-		spin_unlock_bh(&c->erase_completion_lock);
+		spin_unlock(&c->erase_completion_lock);
 
 		cond_resched();
 
 		/* FIXME: point() */
-		err = jffs2_flash_read(c, (ref_offset(ref)), min(ref->totlen, sizeof(node)), &retlen, (void *)&node);
+		err = jffs2_flash_read(c, (ref_offset(ref)), min_t(uint32_t, ref->totlen, sizeof(node)), &retlen, (void *)&node);
 		if (err) {
 			printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref));
 			goto free_out;
@@ -140,7 +141,7 @@
 			
 
 			/* Check we've managed to read at least the common node header */
-		if (retlen < min(ref->totlen, sizeof(node.u))) {
+		if (retlen < min_t(uint32_t, ref->totlen, sizeof(node.u))) {
 			printk(KERN_WARNING "short read in get_inode_nodes()\n");
 			err = -EIO;
 			goto free_out;
@@ -158,6 +159,14 @@
 				err = -EIO;
 				goto free_out;
 			}
+			/* sanity check */
+			if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) {
+				printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n",
+				       ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen));
+				jffs2_mark_node_obsolete(c, ref);
+				spin_lock(&c->erase_completion_lock);
+				continue;
+			}
 			if (je32_to_cpu(node.d.version) > *highest_version)
 				*highest_version = je32_to_cpu(node.d.version);
 			if (ref_obsolete(ref)) {
@@ -166,6 +175,7 @@
 				       ref_offset(ref));
 				BUG();
 			}
+			
 			fd = jffs2_alloc_full_dirent(node.d.nsize+1);
 			if (!fd) {
 				err = -ENOMEM;
@@ -187,7 +197,7 @@
 			   dirent we've already read from the flash
 			*/
 			if (retlen > sizeof(struct jffs2_raw_dirent))
-				memcpy(&fd->name[0], &node.d.name[0], min((uint32_t)node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent))));
+				memcpy(&fd->name[0], &node.d.name[0], min_t(uint32_t, node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent))));
 				
 			/* Do we need to copy any more of the name directly
 			   from the flash?
@@ -244,46 +254,95 @@
 					printk(KERN_NOTICE "jffs2_get_inode_nodes(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
 					       ref_offset(ref), je32_to_cpu(node.i.node_crc), crc);
 					jffs2_mark_node_obsolete(c, ref);
-					spin_lock_bh(&c->erase_completion_lock);
+					spin_lock(&c->erase_completion_lock);
+					continue;
+				}
+				
+				/* sanity checks */
+				if ( je32_to_cpu(node.i.offset) > je32_to_cpu(node.i.isize) ||
+				     PAD(je32_to_cpu(node.i.csize) + sizeof (node.i)) != PAD(je32_to_cpu(node.i.totlen))) {
+					printk(KERN_NOTICE "jffs2_get_inode_nodes(): Inode corrupted at 0x%08x, totlen %d, #ino  %d, version %d, isize %d, csize %d, dsize %d \n",
+						ref_offset(ref),  je32_to_cpu(node.i.totlen),  je32_to_cpu(node.i.ino),
+						je32_to_cpu(node.i.version),  je32_to_cpu(node.i.isize), 
+						je32_to_cpu(node.i.csize), je32_to_cpu(node.i.dsize));
+					jffs2_mark_node_obsolete(c, ref);
+					spin_lock(&c->erase_completion_lock);
 					continue;
 				}
 
 				if (node.i.compr != JFFS2_COMPR_ZERO && je32_to_cpu(node.i.csize)) {
-					/* FIXME: point() */
-					char *buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL);
-					if (!buf)
-						return -ENOMEM;
-
-					err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
-							       &retlen, buf);
-					if (!err && retlen != je32_to_cpu(node.i.csize))
-						err = -EIO;
-					if (err) {
-						kfree(buf);
-						return err;
+					unsigned char *buf=NULL;
+					uint32_t pointed = 0;
+#ifndef __ECOS
+					if (c->mtd->point) {
+						err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
+								     &retlen, &buf);
+						if (!err && retlen < je32_to_cpu(node.i.csize)) {
+							D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen));
+							c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize));
+						} else if (err){
+							D1(printk(KERN_DEBUG "MTD point failed %d\n", err));
+						} else
+							pointed = 1; /* succefully pointed to device */
+					}
+#endif					
+					if(!pointed){
+						buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL);
+						if (!buf)
+							return -ENOMEM;
+						
+						err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
+								       &retlen, buf);
+						if (!err && retlen != je32_to_cpu(node.i.csize))
+							err = -EIO;
+						if (err) {
+							kfree(buf);
+							return err;
+						}
 					}
-					
 					crc = crc32(0, buf, je32_to_cpu(node.i.csize));
-					kfree(buf);
+					if(!pointed)
+						kfree(buf);
+#ifndef __ECOS
+					else
+						c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize));
+#endif
 
 					if (crc != je32_to_cpu(node.i.data_crc)) {
 						printk(KERN_NOTICE "jffs2_get_inode_nodes(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
 						       ref_offset(ref), je32_to_cpu(node.i.data_crc), crc);
 						jffs2_mark_node_obsolete(c, ref);
-						spin_lock_bh(&c->erase_completion_lock);
+						spin_lock(&c->erase_completion_lock);
 						continue;
 					}
 					
 				}
 
 				/* Mark the node as having been checked and fix the accounting accordingly */
+				spin_lock(&c->erase_completion_lock);
 				jeb = &c->blocks[ref->flash_offset / c->sector_size];
 				jeb->used_size += ref->totlen;
 				jeb->unchecked_size -= ref->totlen;
 				c->used_size += ref->totlen;
 				c->unchecked_size -= ref->totlen;
 
-				mark_ref_normal(ref);
+				/* If node covers at least a whole page, or if it starts at the 
+				   beginning of a page and runs to the end of the file, or if 
+				   it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. 
+
+				   If it's actually overlapped, it'll get made NORMAL (or OBSOLETE) 
+				   when the overlapping node(s) get added to the tree anyway. 
+				*/
+				if ((je32_to_cpu(node.i.dsize) >= PAGE_CACHE_SIZE) ||
+				    ( ((je32_to_cpu(node.i.offset)&(PAGE_CACHE_SIZE-1))==0) &&
+				      (je32_to_cpu(node.i.dsize)+je32_to_cpu(node.i.offset) ==  je32_to_cpu(node.i.isize)))) {
+					D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_PRISTINE\n", ref_offset(ref)));
+					ref->flash_offset = ref_offset(ref) | REF_PRISTINE;
+				} else {
+					D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_NORMAL\n", ref_offset(ref)));
+					ref->flash_offset = ref_offset(ref) | REF_NORMAL;
+				}
+				spin_unlock(&c->erase_completion_lock);
 			}
 
 			tn = jffs2_alloc_tmp_dnode_info();
@@ -323,13 +382,15 @@
 				       je16_to_cpu(node.u.nodetype), ref_offset(ref));
 
 				/* Mark the node as having been checked and fix the accounting accordingly */
+				spin_lock(&c->erase_completion_lock);
 				jeb = &c->blocks[ref->flash_offset / c->sector_size];
 				jeb->used_size += ref->totlen;
 				jeb->unchecked_size -= ref->totlen;
 				c->used_size += ref->totlen;
 				c->unchecked_size -= ref->totlen;
-				
+
 				mark_ref_normal(ref);
+				spin_unlock(&c->erase_completion_lock);
 			}
 			node.u.nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(node.u.nodetype));
 			if (crc32(0, &node, sizeof(struct jffs2_unknown_node)-4) != je32_to_cpu(node.u.hdr_crc)) {
@@ -361,10 +422,10 @@
 			}
 
 		}
-		spin_lock_bh(&c->erase_completion_lock);
+		spin_lock(&c->erase_completion_lock);
 
 	}
-	spin_unlock_bh(&c->erase_completion_lock);
+	spin_unlock(&c->erase_completion_lock);
 	*tnp = ret_tn;
 	*fdp = ret_fd;
 
@@ -376,12 +437,24 @@
 	return err;
 }
 
-struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, int ino)
+void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state)
+{
+	spin_lock(&c->inocache_lock);
+	ic->state = state;
+	wake_up(&c->inocache_wq);
+	spin_unlock(&c->inocache_lock);
+}
+
+/* During mount, this needs no locking. During normal operation, its
+   callers want to do other stuff while still holding the inocache_lock.
+   Rather than introducing special case get_ino_cache functions or 
+   callbacks, we just let the caller do the locking itself. */
+   
+struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
 {
 	struct jffs2_inode_cache *ret;
 
 	D2(printk(KERN_DEBUG "jffs2_get_ino_cache(): ino %u\n", ino));
-	spin_lock (&c->inocache_lock);
 
 	ret = c->inocache_list[ino % INOCACHE_HASHSIZE];
 	while (ret && ret->ino < ino) {
@@ -390,8 +463,6 @@
 	
 	if (ret && ret->ino != ino)
 		ret = NULL;
-
-	spin_unlock(&c->inocache_lock);
 
 	D2(printk(KERN_DEBUG "jffs2_get_ino_cache found %p for ino %u\n", ret, ino));
 	return ret;
diff -Nru a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
--- a/fs/jffs2/nodelist.h	Tue Nov 12 08:11:55 2002
+++ b/fs/jffs2/nodelist.h	Wed May 28 08:01:06 2003
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.h,v 1.87 2002/11/12 13:36:18 dwmw2 Exp $
+ * $Id: nodelist.h,v 1.93 2003/02/24 21:47:28 dwmw2 Exp $
  *
  */
 
@@ -16,12 +16,17 @@
 
 #include <linux/config.h>
 #include <linux/fs.h>
-
-#include <linux/mtd/compatmac.h> /* For min/max in older kernels */
+#include <linux/types.h>
 #include <linux/jffs2.h>
 #include <linux/jffs2_fs_sb.h>
 #include <linux/jffs2_fs_i.h>
+
+#ifdef __ECOS
+#include "os-ecos.h"
+#else
+#include <linux/mtd/compatmac.h> /* For min/max in older kernels */
 #include "os-linux.h"
+#endif
 
 #ifndef CONFIG_JFFS2_FS_DEBUG
 #define CONFIG_JFFS2_FS_DEBUG 2
@@ -98,13 +103,18 @@
 	uint32_t ino;
 	int nlink;
 	int state;
-#define INO_STATE_UNCHECKED 0
-#define INO_STATE_CHECKING 1
-#define INO_STATE_CHECKEDABSENT 2
-#define INO_STATE_READINGINODE 3
-#define INO_STATE_PRESENT 5
 };
 
+/* Inode states for 'state' above. We need the 'GC' state to prevent
+   someone from doing a read_inode() while we're moving a 'REF_PRISTINE'
+   node without going through all the iget() nonsense */
+#define INO_STATE_UNCHECKED	0	/* CRC checks not yet done */
+#define INO_STATE_CHECKING	1	/* CRC checks in progress */
+#define INO_STATE_PRESENT	2	/* In core */
+#define INO_STATE_CHECKEDABSENT	3	/* Checked, cleared again */
+#define INO_STATE_GC		4	/* GCing a 'pristine' node */
+#define INO_STATE_READING	5	/* In read_inode() */
+
 #define INOCACHE_HASHSIZE 128
 
 struct jffs2_scan_info {
@@ -281,7 +291,8 @@
 			  struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
 			  uint32_t *highest_version, uint32_t *latest_mctime,
 			  uint32_t *mctime_ver);
-struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, int ino);
+void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state);
+struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino);
 void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new);
 void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old);
 void jffs2_free_ino_caches(struct jffs2_sb_info *c);
@@ -315,10 +326,10 @@
 
 /* readinode.c */
 void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size);
-int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_full_dnode *fn);
 int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn);
 int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, 
 			uint32_t ino, struct jffs2_raw_inode *latest_node);
+int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
 void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
 
 /* malloc.c */
diff -Nru a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
--- a/fs/jffs2/nodemgmt.c	Tue Nov 12 08:11:55 2002
+++ b/fs/jffs2/nodemgmt.c	Wed May 28 08:01:06 2003
@@ -7,14 +7,15 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodemgmt.c,v 1.84 2002/11/12 11:17:29 dwmw2 Exp $
+ * $Id: nodemgmt.c,v 1.94 2003/02/19 17:50:26 gleixner Exp $
  *
  */
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
-#include <linux/interrupt.h>
+#include <linux/compiler.h>
+#include <linux/sched.h> /* For cond_resched() */
 #include "nodelist.h"
 
 /**
@@ -54,26 +55,57 @@
 
 	D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n"));
 
-	spin_lock_bh(&c->erase_completion_lock);
+	spin_lock(&c->erase_completion_lock);
 
-	/* this needs a little more thought */
+	/* this needs a little more thought (true <tglx> :)) */
 	while(ret == -EAGAIN) {
 		while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) {
 			int ret;
+			uint32_t dirty, avail;
 
 			up(&c->alloc_sem);
 			
-			if (c->dirty_size + c->unchecked_size < c->sector_size) {
+			/* calculate real dirty size
+			 * dirty_size contains blocks on erase_pending_list
+			 * those blocks are counted in c->nr_erasing_blocks.
+			 * If one block is actually erased, it is not longer counted as dirty_space
+			 * but it is counted in c->nr_erasing_blocks, so we add it and subtract it
+			 * with c->nr_erasing_blocks * c->sector_size again.
+			 * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks
+			 * This helps us to force gc and pick eventually a clean block to spread the load.
+			 * We add unchecked_size here, as we hopefully will find some space to use.
+			 * This will affect the sum only once, as gc first finishes checking
+			 * of nodes.
+			 */
+			dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size;
+			if (dirty < c->sector_size) {
 				D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < sector size 0x%08x, returning -ENOSPC\n",
-					  c->dirty_size, c->unchecked_size, c->sector_size));
-				spin_unlock_bh(&c->erase_completion_lock);
+					  dirty, c->unchecked_size, c->sector_size));
+				spin_unlock(&c->erase_completion_lock);
+				return -ENOSPC;
+			}
+			
+			/* Calc possibly available space. Possibly available means that we
+			 * don't know, if unchecked size contains obsoleted nodes, which could give us some
+			 * more usable space. This will affect the sum only once, as gc first finishes checking
+			 * of nodes.
+			 + Return -ENOSPC, if the maximum possibly available space is less or equal than 
+			 * blocksneeded * sector_size.
+			 * This blocks endless gc looping on a filesystem, which is nearly full, even if
+			 * the check above passes.
+			 */
+			avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size;
+			if ( (avail / c->sector_size) <= blocksneeded) {
+				D1(printk(KERN_DEBUG "max. available size 0x%08x  < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n",
+					  avail, blocksneeded * c->sector_size));
+				spin_unlock(&c->erase_completion_lock);
 				return -ENOSPC;
 			}
 			
 			D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
 				  c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size,
 				  c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size));
-			spin_unlock_bh(&c->erase_completion_lock);
+			spin_unlock(&c->erase_completion_lock);
 			
 			ret = jffs2_garbage_collect_pass(c);
 			if (ret)
@@ -85,7 +117,7 @@
 				return -EINTR;
 
 			down(&c->alloc_sem);
-			spin_lock_bh(&c->erase_completion_lock);
+			spin_lock(&c->erase_completion_lock);
 		}
 
 		ret = jffs2_do_reserve_space(c, minsize, ofs, len);
@@ -93,7 +125,7 @@
 			D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret));
 		}
 	}
-	spin_unlock_bh(&c->erase_completion_lock);
+	spin_unlock(&c->erase_completion_lock);
 	if (ret)
 		up(&c->alloc_sem);
 	return ret;
@@ -106,14 +138,14 @@
 
 	D1(printk(KERN_DEBUG "jffs2_reserve_space_gc(): Requested 0x%x bytes\n", minsize));
 
-	spin_lock_bh(&c->erase_completion_lock);
+	spin_lock(&c->erase_completion_lock);
 	while(ret == -EAGAIN) {
 		ret = jffs2_do_reserve_space(c, minsize, ofs, len);
 		if (ret) {
 		        D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
 		}
 	}
-	spin_unlock_bh(&c->erase_completion_lock);
+	spin_unlock(&c->erase_completion_lock);
 	return ret;
 }
 
@@ -127,10 +159,10 @@
 		/* Skip the end of this block and file it as having some dirty space */
 		/* If there's a pending write to it, flush now */
 		if (c->wbuf_len) {
-			spin_unlock_bh(&c->erase_completion_lock);
+			spin_unlock(&c->erase_completion_lock);
 			D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));			    
 			jffs2_flush_wbuf(c, 1);
-			spin_lock_bh(&c->erase_completion_lock);
+			spin_lock(&c->erase_completion_lock);
 			/* We know nobody's going to have changed nextblock. Just continue */
 		}
 		c->wasted_size += jeb->free_size;
@@ -186,9 +218,9 @@
 			    !list_empty(&c->erasable_pending_wbuf_list)) {
 				D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
 				/* c->nextblock is NULL, no update to c->nextblock allowed */			    
-				spin_unlock_bh(&c->erase_completion_lock);
+				spin_unlock(&c->erase_completion_lock);
 				jffs2_flush_wbuf(c, 1);
-				spin_lock_bh(&c->erase_completion_lock);
+				spin_lock(&c->erase_completion_lock);
 				/* Have another go. It'll be on the erasable_list now */
 				return -EAGAIN;
 			}
@@ -203,6 +235,11 @@
 			}
 			/* Make sure this can't deadlock. Someone has to start the erases
 			   of erase_pending blocks */
+#ifdef __ECOS
+			/* In eCos, we don't have a handy kernel thread doing the erases for
+			   us. We do them ourselves right now. */
+			jffs2_erase_pending_blocks(c);
+#else
 			set_current_state(TASK_INTERRUPTIBLE);
 			add_wait_queue(&c->erase_wait, &wait);
 			D1(printk(KERN_DEBUG "Waiting for erases to complete. erasing_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n", 
@@ -212,13 +249,14 @@
 				D1(printk(KERN_DEBUG "Triggering pending erases\n"));
 				jffs2_erase_pending_trigger(c);
 			}
-			spin_unlock_bh(&c->erase_completion_lock);
+			spin_unlock(&c->erase_completion_lock);
 			schedule();
 			remove_wait_queue(&c->erase_wait, &wait);
-			spin_lock_bh(&c->erase_completion_lock);
+			spin_lock(&c->erase_completion_lock);
 			if (signal_pending(current)) {
 				return -EINTR;
 			}
+#endif
 			/* An erase may have failed, decreasing the
 			   amount of free space available. So we must
 			   restart from the beginning */
@@ -248,9 +286,9 @@
 		   already set c->nextblock so that jffs2_mark_node_obsolete()
 		   won't try to refile it to the dirty_list.
 		*/
-		spin_unlock_bh(&c->erase_completion_lock);
+		spin_unlock(&c->erase_completion_lock);
 		jffs2_mark_node_obsolete(c, jeb->first_node);
-		spin_lock_bh(&c->erase_completion_lock);
+		spin_lock(&c->erase_completion_lock);
 	}
 
 	D1(printk(KERN_DEBUG "jffs2_do_reserve_space(): Giving 0x%x bytes at 0x%x\n", *len, *ofs));
@@ -276,7 +314,7 @@
 	uint32_t len = new->totlen;
 
 	jeb = &c->blocks[new->flash_offset / c->sector_size];
-	D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x, size 0x%x\n", ref_offset(new), len));
+	D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len));
 #if 1
 	if (jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size)) {
 		printk(KERN_WARNING "argh. node added in wrong place\n");
@@ -284,7 +322,7 @@
 		return -EINVAL;
 	}
 #endif
-	spin_lock_bh(&c->erase_completion_lock);
+	spin_lock(&c->erase_completion_lock);
 
 	if (!jeb->first_node)
 		jeb->first_node = new;
@@ -308,9 +346,9 @@
 			  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
 		if (c->wbuf_len) {
 			/* Flush the last write in the block if it's outstanding */
-			spin_unlock_bh(&c->erase_completion_lock);
+			spin_unlock(&c->erase_completion_lock);
 			jffs2_flush_wbuf(c, 1);
-			spin_lock_bh(&c->erase_completion_lock);
+			spin_lock(&c->erase_completion_lock);
 		}
 
 		list_add_tail(&jeb->list, &c->clean_list);
@@ -319,7 +357,7 @@
 	ACCT_SANITY_CHECK(c,jeb);
 	D1(ACCT_PARANOIA_CHECK(jeb));
 
-	spin_unlock_bh(&c->erase_completion_lock);
+	spin_unlock(&c->erase_completion_lock);
 
 	return 0;
 }
@@ -337,7 +375,7 @@
 	struct jffs2_eraseblock *jeb;
 	int blocknr;
 	struct jffs2_unknown_node n;
-	int ret;
+	int ret, addedsize;
 	size_t retlen;
 
 	if(!ref) {
@@ -355,7 +393,7 @@
 	}
 	jeb = &c->blocks[blocknr];
 
-	spin_lock_bh(&c->erase_completion_lock);
+	spin_lock(&c->erase_completion_lock);
 
 	if (ref_flags(ref) == REF_UNCHECKED) {
 		D1(if (unlikely(jeb->unchecked_size < ref->totlen)) {
@@ -377,14 +415,17 @@
 		c->used_size -= ref->totlen;
 	}
 
+	// Take care, that wasted size is taken into concern
 	if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref->totlen)) && jeb != c->nextblock) {
 		D1(printk("Dirtying\n"));
-		jeb->dirty_size += ref->totlen + jeb->wasted_size;
-		c->dirty_size += ref->totlen + jeb->wasted_size;
+		addedsize = ref->totlen + jeb->wasted_size;
+		jeb->dirty_size += addedsize;
+		c->dirty_size += addedsize;
 		c->wasted_size -= jeb->wasted_size;
 		jeb->wasted_size = 0;
 	} else {
 		D1(printk("Wasting\n"));
+		addedsize = 0;
 		jeb->wasted_size += ref->totlen;
 		c->wasted_size += ref->totlen;	
 	}
@@ -400,7 +441,7 @@
 		   obliterate nodes that look obsolete. If they weren't 
 		   marked obsolete on the flash at the time they _became_
 		   obsolete, there was probably a reason for that. */
-		spin_unlock_bh(&c->erase_completion_lock);
+		spin_unlock(&c->erase_completion_lock);
 		return;
 	}
 
@@ -417,6 +458,10 @@
 		if (c->wbuf_len) {
 			D1(printk(KERN_DEBUG "...and adding to erasable_pending_wbuf_list\n"));
 			list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list);
+#if 0 /* This check was added to allow us to find places where we added nodes to the lists
+	 after dropping the alloc_sem, and it did that just fine. But it also caused us to
+	 lock the alloc_sem in other places, like clear_inode(), when we wouldn't otherwise
+	 have needed to. So I suspect it's outlived its usefulness. Thomas? */
 
 			/* We've changed the rules slightly. After
 			   writing a node you now mustn't drop the
@@ -436,6 +481,7 @@
 				printk(KERN_CRIT "jffs2_mark_node_obsolete() called with wbuf active but alloc_sem not locked!\n");
 				BUG();
 			}
+#endif
 		} else {
 			if (jiffies & 127) {
 				/* Most of the time, we just erase it immediately. Otherwise we
@@ -454,7 +500,7 @@
 		D1(printk(KERN_DEBUG "Done OK\n"));
 	} else if (jeb == c->gcblock) {
 		D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty_list\n", jeb->offset));
-	} else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - ref->totlen)) {
+	} else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - addedsize)) {
 		D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", jeb->offset));
 		list_del(&jeb->list);
 		D1(printk(KERN_DEBUG "...and adding to dirty_list\n"));
@@ -470,7 +516,7 @@
 			  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); 
 	}			  	
 
-	spin_unlock_bh(&c->erase_completion_lock);
+	spin_unlock(&c->erase_completion_lock);
 
 	if (!jffs2_can_mark_obsolete(c))
 		return;
@@ -484,7 +530,7 @@
 		return;
 	}
 	if (retlen != sizeof(n)) {
-		printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %d\n", ref_offset(ref), retlen);
+		printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
 		return;
 	}
 	if (PAD(je32_to_cpu(n.totlen)) != PAD(ref->totlen)) {
@@ -503,7 +549,7 @@
 		return;
 	}
 	if (retlen != sizeof(n)) {
-		printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %d\n", ref_offset(ref), retlen);
+		printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
 		return;
 	}
 }
diff -Nru a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
--- a/fs/jffs2/os-linux.h	Fri Feb  7 07:59:17 2003
+++ b/fs/jffs2/os-linux.h	Wed May 28 08:01:06 2003
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: os-linux.h,v 1.21 2002/11/12 09:44:30 dwmw2 Exp $
+ * $Id: os-linux.h,v 1.26 2003/05/16 18:45:25 dwmw2 Exp $
  *
  */
 
@@ -15,6 +15,11 @@
 #define __JFFS2_OS_LINUX_H__
 #include <linux/version.h>
 
+/* JFFS2 uses Linux mode bits natively -- no need for conversion */
+#define os_to_jffs2_mode(x) (x)
+#define jffs2_to_os_mode(x) (x)
+
+
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
 #define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode))
 #define OFNI_EDONI_2SFFJ(f)  (&(f)->vfs_inode)
@@ -37,9 +42,6 @@
 #define JFFS2_F_I_MODE(f) (OFNI_EDONI_2SFFJ(f)->i_mode)
 #define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid)
 #define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid)
-#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime.tv_sec)
-#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime.tv_sec)
-#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime.tv_sec)
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,1)
 #define JFFS2_F_I_RDEV_MIN(f) (minor(OFNI_EDONI_2SFFJ(f)->i_rdev))
@@ -49,6 +51,21 @@
 #define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev)))
 #endif
 
+/* Urgh. The things we do to keep the 2.4 build working */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,47)
+#define ITIME(sec) ((struct timespec){sec, 0})
+#define I_SEC(tv) ((tv).tv_sec)
+#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime.tv_sec)
+#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime.tv_sec)
+#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime.tv_sec)
+#else
+#define ITIME(x) (x)
+#define I_SEC(x) (x)
+#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime)
+#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime)
+#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime)
+#endif
+
 /* Hmmm. P'raps generic code should only ever see versions of signal
    functions which do the locking automatically? */
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40)
@@ -56,6 +73,16 @@
 #else
 #define current_sig_lock current->sighand->siglock
 #endif
+
+#define sleep_on_spinunlock(wq, s)				\
+	do {							\
+		DECLARE_WAITQUEUE(__wait, current);		\
+		add_wait_queue((wq), &__wait);			\
+		set_current_state(TASK_UNINTERRUPTIBLE);	\
+		spin_unlock(s);					\
+		schedule();					\
+		remove_wait_queue((wq), &__wait);		\
+	} while(0)
 
 static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
 {
diff -Nru a/fs/jffs2/read.c b/fs/jffs2/read.c
--- a/fs/jffs2/read.c	Tue Nov 12 08:11:56 2002
+++ b/fs/jffs2/read.c	Wed May 28 08:01:06 2003
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: read.c,v 1.29 2002/11/12 09:51:22 dwmw2 Exp $
+ * $Id: read.c,v 1.31 2003/01/14 14:06:22 dwmw2 Exp $
  *
  */
 
@@ -39,7 +39,7 @@
 	}
 	if (readlen != sizeof(*ri)) {
 		jffs2_free_raw_inode(ri);
-		printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%x bytes, got 0x%x\n", 
+		printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n", 
 		       ref_offset(fd->raw), sizeof(*ri), readlen);
 		return -EIO;
 	}
@@ -197,8 +197,9 @@
 			
 			fragofs = offset - frag->ofs;
 			readlen = min(frag->size - fragofs, end - offset);
-			D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%x\n", frag->ofs+fragofs, frag->ofs+fragofs+readlen, 
-				  ref_offset(frag->node->raw)));
+			D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n",
+				  frag->ofs+fragofs, frag->ofs+fragofs+readlen,
+				  ref_offset(frag->node->raw), ref_flags(frag->node->raw)));
 			ret = jffs2_read_dnode(c, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen);
 			D2(printk(KERN_DEBUG "node read done\n"));
 			if (ret) {
diff -Nru a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
--- a/fs/jffs2/readinode.c	Tue Nov 12 08:11:56 2002
+++ b/fs/jffs2/readinode.c	Wed May 28 08:01:06 2003
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: readinode.c,v 1.95 2002/11/12 11:17:29 dwmw2 Exp $
+ * $Id: readinode.c,v 1.106 2003/05/14 06:53:26 dwmw2 Exp $
  *
  */
 
@@ -17,11 +17,13 @@
 #include <linux/crc32.h>
 #include <linux/pagemap.h>
 #include <linux/mtd/mtd.h>
-#include <linux/interrupt.h>
+#include <linux/compiler.h>
 #include "nodelist.h"
 
+static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag);
 
-D1(static void jffs2_print_fragtree(struct rb_root *list, int permitbug)
+#if CONFIG_JFFS2_FS_DEBUG >= 1
+static void jffs2_print_fragtree(struct rb_root *list, int permitbug)
 {
 	struct jffs2_node_frag *this = frag_first(list);
 	uint32_t lastofs = 0;
@@ -44,31 +46,17 @@
 		printk(KERN_CRIT "Frag tree got a hole in it\n");
 		BUG();
 	}
-})
+}
 
-D1(void jffs2_print_frag_list(struct jffs2_inode_info *f)
+void jffs2_print_frag_list(struct jffs2_inode_info *f)
 {
 	jffs2_print_fragtree(&f->fragtree, 0);
 
 	if (f->metadata) {
 		printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
 	}
-})
-
-
-/* Given an inode, probably with existing list of fragments, add the new node
- * to the fragment list.
- */
-int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn)
-{
-	int ret;
-	D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn));
-
-	ret = jffs2_add_full_dnode_to_fraglist(c, &f->fragtree, fn);
-
-	D2(jffs2_print_frag_list(f));
-	return ret;
 }
+#endif /* D1 */
 
 static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this)
 {
@@ -91,26 +79,24 @@
 	jffs2_free_node_frag(this);
 }
 
-/* Doesn't set inode->i_size */
-int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_full_dnode *fn)
+/* Given an inode, probably with existing list of fragments, add the new node
+ * to the fragment list.
+ */
+int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn)
 {
-	struct jffs2_node_frag *this;
+	int ret;
 	struct jffs2_node_frag *newfrag;
-	uint32_t lastend;
+
+	D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn));
 
 	newfrag = jffs2_alloc_node_frag();
-	if (!newfrag) {
+	if (unlikely(!newfrag))
 		return -ENOMEM;
-	}
-
-	if (!fn->raw) {
-		printk(KERN_WARNING "dwmw2 is stupid. j_a_f_d_t_f should never happen with ->raw == NULL\n");
-		BUG();
-	}
 
-	D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag));
+	D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n",
+		  fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag));
 	
-	if (!fn->size) {
+	if (unlikely(!fn->size)) {
 		jffs2_free_node_frag(newfrag);
 		return 0;
 	}
@@ -120,8 +106,42 @@
 	newfrag->node = fn;
 	newfrag->node->frags = 1;
 
+	ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag);
+	if (ret)
+		return ret;
+
+	/* If we now share a page with other nodes, mark either previous
+	   or next node REF_NORMAL, as appropriate.  */
+	if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) {
+		struct jffs2_node_frag *prev = frag_prev(newfrag);
+
+		mark_ref_normal(fn->raw);
+		/* If we don't start at zero there's _always_ a previous */	
+		if (prev->node)
+			mark_ref_normal(prev->node->raw);
+	}
+
+	if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) {
+		struct jffs2_node_frag *next = frag_next(newfrag);
+		
+		if (next) {
+			mark_ref_normal(fn->raw);
+			if (next->node)
+				mark_ref_normal(next->node->raw);
+		}
+	}
+	D2(jffs2_print_frag_list(f));
+	return 0;
+}
+
+/* Doesn't set inode->i_size */
+static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag)
+{
+	struct jffs2_node_frag *this;
+	uint32_t lastend;
+
 	/* Skip all the nodes which are completed before this one starts */
-	this = jffs2_lookup_node_frag(list, fn->ofs);
+	this = jffs2_lookup_node_frag(list, newfrag->node->ofs);
 
 	if (this) {
 		D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n",
@@ -143,16 +163,18 @@
 		if ((lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) {
 			if (this->node)
 				mark_ref_normal(this->node->raw);
-			mark_ref_normal(fn->raw);
+			mark_ref_normal(newfrag->node->raw);
 		}
 
-		if (lastend < fn->ofs) {
+		if (lastend < newfrag->node->ofs) {
 			/* ... and we need to put a hole in before the new node */
 			struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag();
-			if (!holefrag)
+			if (!holefrag) {
+				jffs2_free_node_frag(newfrag);
 				return -ENOMEM;
+			}
 			holefrag->ofs = lastend;
-			holefrag->size = fn->ofs - lastend;
+			holefrag->size = newfrag->node->ofs - lastend;
 			holefrag->node = NULL;
 			if (this) {
 				/* By definition, the 'this' node has no right-hand child, 
@@ -190,9 +212,9 @@
 	if (newfrag->ofs > this->ofs) {
 		/* This node isn't completely obsoleted. The start of it remains valid */
 
-		/* Mark the new node and the partially covered node REF_NORMAL -- let 
+		/* Mark the new node and the partially covered node REF_NORMAL -- let
 		   the GC take a look at them */
-		mark_ref_normal(fn->raw);
+		mark_ref_normal(newfrag->node->raw);
 		if (this->node)
 			mark_ref_normal(this->node->raw);
 
@@ -283,7 +305,7 @@
 	/* And mark them REF_NORMAL so the GC takes a look at them */
 	if (this->node)
 		mark_ref_normal(this->node->raw);
-	mark_ref_normal(fn->raw);
+	mark_ref_normal(newfrag->node->raw);
 
 	return 0;
 }
@@ -314,24 +336,54 @@
 
 /* Scan the list of all nodes present for this ino, build map of versions, etc. */
 
+static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, 
+					struct jffs2_inode_info *f,
+					struct jffs2_raw_inode *latest_node);
+
 int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, 
 			uint32_t ino, struct jffs2_raw_inode *latest_node)
 {
-	struct jffs2_tmp_dnode_info *tn_list, *tn;
-	struct jffs2_full_dirent *fd_list;
-	struct jffs2_full_dnode *fn = NULL;
-	uint32_t crc;
-	uint32_t latest_mctime, mctime_ver;
-	uint32_t mdata_ver = 0;
-	size_t retlen;
-	int ret;
-
 	D2(printk(KERN_DEBUG "jffs2_do_read_inode(): getting inocache\n"));
 
+ retry_inocache:
+	spin_lock(&c->inocache_lock);
 	f->inocache = jffs2_get_ino_cache(c, ino);
 
 	D2(printk(KERN_DEBUG "jffs2_do_read_inode(): Got inocache at %p\n", f->inocache));
 
+	if (f->inocache) {
+		/* Check its state. We may need to wait before we can use it */
+		switch(f->inocache->state) {
+		case INO_STATE_UNCHECKED:
+		case INO_STATE_CHECKEDABSENT:
+			f->inocache->state = INO_STATE_READING;
+			break;
+			
+		case INO_STATE_CHECKING:
+		case INO_STATE_GC:
+			/* If it's in either of these states, we need
+			   to wait for whoever's got it to finish and
+			   put it back. */
+			D1(printk(KERN_DEBUG "jffs2_get_ino_cache_read waiting for ino #%u in state %d\n",
+				  ino, f->inocache->state));
+			sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
+			goto retry_inocache;
+
+		case INO_STATE_READING:
+		case INO_STATE_PRESENT:
+			/* Eep. This should never happen. It can
+			happen if Linux calls read_inode() again
+			before clear_inode() has finished though. */
+			printk(KERN_WARNING "Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state);
+			/* Fail. That's probably better than allowing it to succeed */
+			f->inocache = NULL;
+			break;
+
+		default:
+			BUG();
+		}
+	}
+	spin_unlock(&c->inocache_lock);
 	if (!f->inocache && ino == 1) {
 		/* Special case - no root inode on medium */
 		f->inocache = jffs2_alloc_inode_cache();
@@ -343,19 +395,61 @@
 		memset(f->inocache, 0, sizeof(struct jffs2_inode_cache));
 		f->inocache->ino = f->inocache->nlink = 1;
 		f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
+		f->inocache->state = INO_STATE_READING;
 		jffs2_add_ino_cache(c, f->inocache);
 	}
 	if (!f->inocache) {
 		printk(KERN_WARNING "jffs2_do_read_inode() on nonexistent ino %u\n", ino);
 		return -ENOENT;
 	}
-	D1(printk(KERN_DEBUG "jffs2_do_read_inode(): ino #%u nlink is %d\n", ino, f->inocache->nlink));
+
+	return jffs2_do_read_inode_internal(c, f, latest_node);
+}
+
+int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
+{
+	struct jffs2_raw_inode n;
+	struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL);
+	int ret;
+
+	if (!f)
+		return -ENOMEM;
+
+	memset(f, 0, sizeof(*f));
+	init_MUTEX_LOCKED(&f->sem);
+	f->inocache = ic;
+
+	ret = jffs2_do_read_inode_internal(c, f, &n);
+	if (!ret) {
+		up(&f->sem);
+		jffs2_do_clear_inode(c, f);
+	}
+	kfree (f);
+	return ret;
+}
+
+static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, 
+					struct jffs2_inode_info *f,
+					struct jffs2_raw_inode *latest_node)
+{
+	struct jffs2_tmp_dnode_info *tn_list, *tn;
+	struct jffs2_full_dirent *fd_list;
+	struct jffs2_full_dnode *fn = NULL;
+	uint32_t crc;
+	uint32_t latest_mctime, mctime_ver;
+	uint32_t mdata_ver = 0;
+	size_t retlen;
+	int ret;
+
+	D1(printk(KERN_DEBUG "jffs2_do_read_inode_internal(): ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink));
 
 	/* Grab all nodes relevant to this ino */
-	ret = jffs2_get_inode_nodes(c, ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver);
+	ret = jffs2_get_inode_nodes(c, f->inocache->ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver);
 
 	if (ret) {
-		printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %u returned %d\n", ino, ret);
+		printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %u returned %d\n", f->inocache->ino, ret);
+		if (f->inocache->state == INO_STATE_READING)
+			jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
 		return ret;
 	}
 	f->dents = fd_list;
@@ -365,13 +459,21 @@
 
 		fn = tn->fn;
 
-		if (f->metadata && tn->version > mdata_ver) {
-			D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw)));
-			jffs2_mark_node_obsolete(c, f->metadata->raw);
-			jffs2_free_full_dnode(f->metadata);
-			f->metadata = NULL;
-			
-			mdata_ver = 0;
+		if (f->metadata) {
+			if (tn->version > mdata_ver) {
+				D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw)));
+				jffs2_mark_node_obsolete(c, f->metadata->raw);
+				jffs2_free_full_dnode(f->metadata);
+				f->metadata = NULL;
+				
+				mdata_ver = 0;
+			} else {
+				D1(printk(KERN_DEBUG "Er. New metadata at 0x%08x with ver %d is actually older than previous %d\n",
+				       ref_offset(f->metadata->raw), tn->version, mdata_ver));
+				jffs2_mark_node_obsolete(c, fn->raw);
+				jffs2_free_full_dnode(fn);
+				goto next_tn;
+			}
 		}
 
 		if (fn->size) {
@@ -382,31 +484,36 @@
 			f->metadata = fn;
 			mdata_ver = tn->version;
 		}
+	next_tn:
 		tn_list = tn->next;
 		jffs2_free_tmp_dnode_info(tn);
 	}
 	if (!fn) {
 		/* No data nodes for this inode. */
-		if (ino != 1) {
-			printk(KERN_WARNING "jffs2_do_read_inode(): No data nodes found for ino #%u\n", ino);
+		if (f->inocache->ino != 1) {
+			printk(KERN_WARNING "jffs2_do_read_inode(): No data nodes found for ino #%u\n", f->inocache->ino);
 			if (!fd_list) {
+				if (f->inocache->state == INO_STATE_READING)
+					jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
 				return -EIO;
 			}
 			printk(KERN_WARNING "jffs2_do_read_inode(): But it has children so we fake some modes for it\n");
 		}
-		latest_node->mode = cpu_to_je32(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO);
+		latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO);
 		latest_node->version = cpu_to_je32(0);
 		latest_node->atime = latest_node->ctime = latest_node->mtime = cpu_to_je32(0);
 		latest_node->isize = cpu_to_je32(0);
 		latest_node->gid = cpu_to_je16(0);
 		latest_node->uid = cpu_to_je16(0);
+		if (f->inocache->state == INO_STATE_READING)
+			jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT);
 		return 0;
 	}
 
 	ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node);
 	if (ret || retlen != sizeof(*latest_node)) {
-		printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %ld of %d bytes read\n",
-		       ret, (long)retlen, sizeof(*latest_node));
+		printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %zd of %zd bytes read\n",
+		       ret, retlen, sizeof(*latest_node));
 		/* FIXME: If this fails, there seems to be a memory leak. Find it. */
 		up(&f->sem);
 		jffs2_do_clear_inode(c, f);
@@ -415,13 +522,13 @@
 
 	crc = crc32(0, latest_node, sizeof(*latest_node)-8);
 	if (crc != je32_to_cpu(latest_node->node_crc)) {
-		printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", ino, ref_offset(fn->raw));
+		printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", f->inocache->ino, ref_offset(fn->raw));
 		up(&f->sem);
 		jffs2_do_clear_inode(c, f);
 		return -EIO;
 	}
 
-	switch(je32_to_cpu(latest_node->mode) & S_IFMT) {
+	switch(jemode_to_cpu(latest_node->mode) & S_IFMT) {
 	case S_IFDIR:
 		if (mctime_ver > je32_to_cpu(latest_node->version)) {
 			/* The times in the latest_node are actually older than
@@ -447,23 +554,26 @@
 
 	case S_IFBLK:
 	case S_IFCHR:
-		/* Xertain inode types should have only one data node, and it's
+		/* Certain inode types should have only one data node, and it's
 		   kept as the metadata node */
 		if (f->metadata) {
-			printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n", ino, je32_to_cpu(latest_node->mode));
+			printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n",
+			       f->inocache->ino, jemode_to_cpu(latest_node->mode));
 			up(&f->sem);
 			jffs2_do_clear_inode(c, f);
 			return -EIO;
 		}
 		if (!frag_first(&f->fragtree)) {
-			printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n", ino, je32_to_cpu(latest_node->mode));
+			printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n",
+			       f->inocache->ino, jemode_to_cpu(latest_node->mode));
 			up(&f->sem);
 			jffs2_do_clear_inode(c, f);
 			return -EIO;
 		}
 		/* ASSERT: f->fraglist != NULL */
 		if (frag_next(frag_first(&f->fragtree))) {
-			printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had more than one node\n", ino, je32_to_cpu(latest_node->mode));
+			printk(KERN_WARNING "Argh. Special inode #%u with mode 0x%x had more than one node\n",
+			       f->inocache->ino, jemode_to_cpu(latest_node->mode));
 			/* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
 			up(&f->sem);
 			jffs2_do_clear_inode(c, f);
@@ -475,7 +585,8 @@
 		f->fragtree = RB_ROOT;
 		break;
 	}
-	f->inocache->state = INO_STATE_PRESENT;
+	if (f->inocache->state == INO_STATE_READING)
+		jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT);
 
 	return 0;
 }
@@ -494,7 +605,7 @@
 	   the nodes are marked obsolete, and jffs2_g_c_pass() won't
 	   call iget() for the inode in question.
 
-	   We also do this to keep the (maybe temporary) BUG() in 
+	   We also used to do this to keep the temporary BUG() in 
 	   jffs2_mark_node_obsolete() from triggering. 
 	*/
 	if(deleted)
@@ -518,8 +629,8 @@
 		jffs2_free_full_dirent(fd);
 	}
 
-	if (f->inocache)
-		f->inocache->state = INO_STATE_CHECKEDABSENT;
+	if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
+		jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
 
 	up(&f->sem);
 
diff -Nru a/fs/jffs2/scan.c b/fs/jffs2/scan.c
--- a/fs/jffs2/scan.c	Tue Nov 12 08:11:57 2002
+++ b/fs/jffs2/scan.c	Wed May 28 08:01:06 2003
@@ -7,10 +7,11 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: scan.c,v 1.92 2002/09/09 16:29:08 dwmw2 Exp $
+ * $Id: scan.c,v 1.99 2003/04/28 10:17:17 dwmw2 Exp $
  *
  */
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
 #include <linux/pagemap.h>
@@ -70,23 +71,21 @@
 	uint32_t empty_blocks = 0, bad_blocks = 0;
 	unsigned char *flashbuf = NULL;
 	uint32_t buf_size = 0;
+#ifndef __ECOS
 	size_t pointlen;
 
-	if (!c->blocks) {
-		printk(KERN_WARNING "EEEK! c->blocks is NULL!\n");
-		return -EINVAL;
-	}
 	if (c->mtd->point) {
 		ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf);
 		if (!ret && pointlen < c->mtd->size) {
 			/* Don't muck about if it won't let us point to the whole flash */
-			D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%x\n", pointlen));
-			c->mtd->unpoint(c->mtd, flashbuf);
+			D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen));
+			c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);
 			flashbuf = NULL;
 		}
 		if (ret)
 			D1(printk(KERN_DEBUG "MTD point failed %d\n", ret));
 	}
+#endif
 	if (!flashbuf) {
 		/* For NAND it's quicker to read a whole eraseblock at a time,
 		   apparently */
@@ -237,9 +236,10 @@
 	}
 	if (buf_size)
 		kfree(flashbuf);
+#ifndef __ECOS
 	else 
-		c->mtd->unpoint(c->mtd, flashbuf);
-
+		c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);
+#endif
 	return 0;
 }
 
@@ -255,7 +255,7 @@
 		return ret;
 	}
 	if (retlen < len) {
-		D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%x bytes\n", ofs, retlen));
+		D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%zx bytes\n", ofs, retlen));
 		return -EIO;
 	}
 	D2(printk(KERN_DEBUG "Read 0x%x bytes from 0x%08x into buf\n", len, ofs));
@@ -366,7 +366,7 @@
 		prevofs = ofs;
 
 		if (jeb->offset + c->sector_size < ofs + sizeof(*node)) {
-			D1(printk(KERN_DEBUG "Fewer than %d bytes left to end of block. (%x+%x<%x+%x) Not reading\n", sizeof(struct jffs2_unknown_node),
+			D1(printk(KERN_DEBUG "Fewer than %zd bytes left to end of block. (%x+%x<%x+%zx) Not reading\n", sizeof(struct jffs2_unknown_node),
 				  jeb->offset, c->sector_size, ofs, sizeof(*node)));
 			DIRTY_SPACE((jeb->offset + c->sector_size)-ofs);
 			break;
@@ -374,7 +374,7 @@
 
 		if (buf_ofs + buf_len < ofs + sizeof(*node)) {
 			buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
-			D1(printk(KERN_DEBUG "Fewer than %d bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n",
+			D1(printk(KERN_DEBUG "Fewer than %zd bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n",
 				  sizeof(struct jffs2_unknown_node), buf_len, ofs));
 			err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
 			if (err)
@@ -410,8 +410,8 @@
 			/* Ran off end. */
 			D1(printk(KERN_DEBUG "Empty flash ends normally at 0x%08x\n", ofs));
 
-			if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && 
-			    !jeb->first_node->next_in_ino && !jeb->dirty_size)
+			if (buf_ofs == jeb->offset &&  jeb->used_size == PAD(c->cleanmarker_size) && 
+			    c->cleanmarker_size && !jeb->first_node->next_in_ino && !jeb->dirty_size)
 				return BLK_STATE_CLEANMARKER;
 			wasempty = 1;
 			continue;
@@ -430,7 +430,7 @@
 			continue;
 		}
 		if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) {
-			D1(printk(KERN_DEBUG "Empty bitmask at 0x%08x\n", ofs));
+			D1(printk(KERN_DEBUG "Dirty bitmask at 0x%08x\n", ofs));
 			DIRTY_SPACE(4);
 			ofs += 4;
 			continue;
@@ -492,7 +492,7 @@
 		case JFFS2_NODETYPE_INODE:
 			if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) {
 				buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
-				D1(printk(KERN_DEBUG "Fewer than %d bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n",
+				D1(printk(KERN_DEBUG "Fewer than %zd bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n",
 					  sizeof(struct jffs2_raw_inode), buf_len, ofs));
 				err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
 				if (err)
@@ -585,8 +585,8 @@
 	}
 
 
-	D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, used 0x%08x\n", jeb->offset, 
-		  jeb->free_size, jeb->dirty_size, jeb->used_size));
+	D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset, 
+		  jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size));
 
 	/* mark_node_obsolete can add to wasted !! */
 	if (jeb->wasted_size) {
@@ -596,9 +596,10 @@
 		jeb->wasted_size = 0;
 	}
 
-	if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && 
-	    !jeb->first_node->next_in_ino && !jeb->dirty_size)
+	if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size 
+		&& (!jeb->first_node || jeb->first_node->next_in_ino) )
 		return BLK_STATE_CLEANMARKER;
+		
 	/* move blocks with max 4 byte dirty space to cleanlist */	
 	else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) {
 		c->dirty_size -= jeb->dirty_size;
diff -Nru a/fs/jffs2/super.c b/fs/jffs2/super.c
--- a/fs/jffs2/super.c	Sun May 25 19:36:50 2003
+++ b/fs/jffs2/super.c	Wed May 28 08:01:07 2003
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: super.c,v 1.74 2002/11/12 09:37:39 dwmw2 Exp $
+ * $Id: super.c,v 1.79 2003/05/27 22:35:42 dwmw2 Exp $
  *
  */
 
@@ -23,7 +23,6 @@
 #include <linux/jffs2.h>
 #include <linux/pagemap.h>
 #include <linux/mtd/mtd.h>
-#include <linux/interrupt.h>
 #include <linux/ctype.h>
 #include <linux/namei.h>
 #include "nodelist.h"
@@ -53,7 +52,7 @@
 
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR) {
-		init_MUTEX(&ei->sem);
+		init_MUTEX_LOCKED(&ei->sem);
 		inode_init_once(&ei->vfs_inode);
 	}
 }
@@ -101,9 +100,9 @@
 	return 0;
 }
 
-static struct super_block *
-jffs2_get_sb_mtd(struct file_system_type *fs_type, int flags,
-		 const char *dev_name, void *data, struct mtd_info *mtd)
+static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
+					      int flags, const char *dev_name, 
+					      void *data, struct mtd_info *mtd)
 {
 	struct super_block *sb;
 	struct jffs2_sb_info *c;
@@ -153,9 +152,9 @@
 	return sb;
 }
 
-static struct super_block *
-jffs2_get_sb_mtdnr(struct file_system_type *fs_type, int flags,
-		   const char *dev_name, void *data, int mtdnr)
+static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type,
+					      int flags, const char *dev_name, 
+					      void *data, int mtdnr)
 {
 	struct mtd_info *mtd;
 
@@ -168,9 +167,9 @@
 	return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd);
 }
 
-static struct super_block *
-jffs2_get_sb(struct file_system_type *fs_type, int flags,
-	     const char *dev_name, void *data)
+static struct super_block *jffs2_get_sb(struct file_system_type *fs_type,
+					int flags, const char *dev_name,
+					void *data)
 {
 	int err;
 	struct nameidata nd;
diff -Nru a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
--- a/fs/jffs2/wbuf.c	Tue Feb 18 10:50:38 2003
+++ b/fs/jffs2/wbuf.c	Wed May 28 08:01:07 2003
@@ -7,39 +7,40 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: wbuf.c,v 1.20 2002/11/12 11:33:02 dwmw2 Exp $
- * + some of the dependencies on later MTD NAND code temporarily reverted.
+ * $Id: wbuf.c,v 1.30 2003/02/19 17:48:49 gleixner Exp $
  *
  */
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
-#include <linux/interrupt.h>
 #include <linux/crc32.h>
 #include <linux/mtd/nand.h>
 #include "nodelist.h"
 
-/* FIXME duplicated defines in wbuf.c and nand.c
- * Constants for out of band layout
- */
-#ifndef NAND_BADBLOCK_POS
-#define NAND_BADBLOCK_POS		5
-#endif
-#ifndef NAND_JFFS2_OOB_BADBPOS
-#define NAND_JFFS2_OOB_BADBPOS		5
-#define NAND_JFFS2_OOB8_FSDAPOS		6
-#define NAND_JFFS2_OOB16_FSDAPOS	8
-#define NAND_JFFS2_OOB8_FSDALEN		2
-#define NAND_JFFS2_OOB16_FSDALEN	8
-#endif
-
 /* max. erase failures before we mark a block bad */
 #define MAX_ERASE_FAILURES 	5
 
 /* two seconds timeout for timed wbuf-flushing */
 #define WBUF_FLUSH_TIMEOUT	2 * HZ
 
+#define JFFS2_OOB_ECCPOS0		0
+#define JFFS2_OOB_ECCPOS1		1
+#define JFFS2_OOB_ECCPOS2		2
+#define JFFS2_OOB_ECCPOS3		3
+#define JFFS2_OOB_ECCPOS4		6
+#define JFFS2_OOB_ECCPOS5		7
+
+#define NAND_JFFS2_OOB8_FSDAPOS		6
+#define NAND_JFFS2_OOB16_FSDAPOS	8
+#define NAND_JFFS2_OOB8_FSDALEN		2
+#define NAND_JFFS2_OOB16_FSDALEN	8
+
+struct nand_oobinfo jffs2_oobinfo = {
+	useecc: 1,
+	eccpos: {JFFS2_OOB_ECCPOS0, JFFS2_OOB_ECCPOS1, JFFS2_OOB_ECCPOS2, JFFS2_OOB_ECCPOS3, JFFS2_OOB_ECCPOS4, JFFS2_OOB_ECCPOS5}
+};
+
 static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c)
 {
 	struct list_head *this, *next;
@@ -178,13 +179,14 @@
 	/* else jffs2_flash_writev has actually filled in the rest of the
 	   buffer for us, and will deal with the node refs etc. later. */
 	
-	ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf);
+	ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, &jffs2_oobinfo);
 	
 	if (ret || retlen != c->wbuf_pagesize) {
 		if (ret)
 			printk(KERN_CRIT "jffs2_flush_wbuf(): Write failed with %d\n",ret);
 		else
-			printk(KERN_CRIT "jffs2_flush_wbuf(): Write was short %d instead of %d\n",retlen,c->wbuf_pagesize);
+			printk(KERN_CRIT "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
+				retlen, c->wbuf_pagesize);
 			
 		ret = -EIO;		
 		/* CHECKME NAND 
@@ -205,7 +207,7 @@
 	/* Adjusting free size of next block only, if it's called from fsync ! */
 	if (pad == 2) {
 		D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of c->nextblock\n"));
-		spin_lock_bh(&c->erase_completion_lock);
+		spin_lock(&c->erase_completion_lock);
 		if (!c->nextblock)
 			BUG();
 		/* wbuf_pagesize - wbuf_len is the amount of space that's to be 
@@ -222,13 +224,13 @@
 		c->free_size -= (c->wbuf_pagesize - c->wbuf_len);
 		c->nextblock->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
 		c->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
-		spin_unlock_bh(&c->erase_completion_lock);
+		spin_unlock(&c->erase_completion_lock);
 	}
 
 	/* Stick any now-obsoleted blocks on the erase_pending_list */
-	spin_lock_bh(&c->erase_completion_lock);
+	spin_lock(&c->erase_completion_lock);
 	jffs2_refile_wbuf_blocks(c);
-	spin_unlock_bh(&c->erase_completion_lock);
+	spin_unlock(&c->erase_completion_lock);
 
 	memset(c->wbuf,0xff,c->wbuf_pagesize);
 	/* adjust write buffer offset, else we get a non contigous write bug */
@@ -394,7 +396,7 @@
 		outvecs[splitvec].iov_len = split_ofs;
 
 		/* We did cross a page boundary, so we write some now */
-		ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen); 
+		ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, &jffs2_oobinfo); 
 		if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {
 			/* At this point we have no problem,
 			   c->wbuf is empty. 
@@ -442,11 +444,19 @@
 }
 
 /*
-	This is the entry for NOR-Flash. We use it also for NAND to flush wbuf
+ *	This is the entry for flash write.
+ *	Check, if we work on NAND FLASH, if so build an iovec and write it via vritev
 */
 int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf)
 {
-	return c->mtd->write(c->mtd, ofs, len, retlen, buf);
+	struct iovec vecs[1];
+
+	if (jffs2_can_mark_obsolete(c))
+		return c->mtd->write(c->mtd, ofs, len, retlen, buf);
+
+	vecs[0].iov_base = (unsigned char *) buf;
+	vecs[0].iov_len = len;
+	return jffs2_flash_writev(c, vecs, 1, ofs, retlen);
 }
 
 /*
@@ -459,10 +469,11 @@
 
 	/* Read flash */
 	if (!jffs2_can_mark_obsolete(c)) {
-		ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
+		ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, &jffs2_oobinfo);
 
 		if ( (ret == -EIO) && (*retlen == len) ) {
-			printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%llx) returned ECC error\n", len, ofs);
+			printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
+			       len, ofs);
 			/* 
 			 * We have the raw data without ECC correction in the buffer, maybe 
 			 * we are lucky and all data or parts are correct. We check the node.
@@ -549,7 +560,7 @@
 	
 	if (retlen < len) {
 		D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB return short read "
-			  "(%d bytes not %d) for block at %08x\n", retlen, len, jeb->offset));
+			  "(%zd bytes not %d) for block at %08x\n", retlen, len, jeb->offset));
 		ret = -EIO;
 		goto out;
 	}
@@ -593,69 +604,83 @@
 	return ret;
 }
 
-int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+/*
+*	Scan for a valid cleanmarker and for bad blocks
+*	For virtual blocks (concatenated physical blocks) check the cleanmarker
+*	only in the first page of the first physical block, but scan for bad blocks in all
+*	physical blocks
+*/
+int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
 	struct jffs2_unknown_node n;
 	unsigned char buf[32];
 	unsigned char *p;
-	int ret,i;
-	size_t retlen;
-	int	fsdata_pos,fsdata_len, oob_size, badblock_pos;
+	int ret, i, cnt, retval = 0;
+	size_t retlen, offset;
+	int fsdata_pos, fsdata_len, oob_size, badblock_pos;
 
+	offset = jeb->offset;
 	oob_size = c->mtd->oobsize;
 
-	switch(c->mtd->ecctype) {
-	case MTD_ECC_SW:	
+	switch (c->mtd->ecctype) {
+	case MTD_ECC_SW:
 		fsdata_pos = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDAPOS : NAND_JFFS2_OOB16_FSDAPOS;
 		fsdata_len = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDALEN : NAND_JFFS2_OOB16_FSDALEN;
 		badblock_pos = NAND_BADBLOCK_POS;
 		break;
 	default:
-		D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Invalid ECC type\n"));
+		D1 (printk (KERN_WARNING "jffs2_write_nand_cleanmarker(): Invalid ECC type\n"));
 		return -EINVAL;
-	}	
-
-	/*
-	*	We read oob data from page 0 and 1 of the block.
-	*	page 0 contains cleanmarker and badblock info
-	*	page 2 contains failure count of this block
-	*/
-	ret = c->mtd->read_oob(c->mtd, jeb->offset, oob_size << 1 , &retlen, buf);
-	
-	if (ret) {
-		D1(printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB failed %d for block at %08x\n", ret, jeb->offset));
-		return ret;
-	}
-	if (retlen < (oob_size << 1) ) {
-		D1(printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB return short read (%d bytes not %d) for block at %08x\n", retlen, oob_size << 1 , jeb->offset));
-		return -EIO;
 	}
 
-	/* Check for bad block marker */
-	if (buf[badblock_pos] != 0xff) {
-		D1(printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n",jeb->offset));
-		return 2;
-	}
 
-	/* Check for failure counter in the second page */
-	if (buf[badblock_pos+oob_size] != 0xff) {
-		D1(printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Block marked as failed at %08x, fail count:%d\n",jeb->offset,buf[badblock_pos+oob_size]));
-		return 3;
-	}
+	/* Loop through the physical blocks */
+	for (cnt = 0; cnt < (c->sector_size / c->mtd->erasesize); cnt++) {
+		/*
+		   *    We read oob data from page 0 and 1 of the block.
+		   *    page 0 contains cleanmarker and badblock info
+		   *    page 1 contains failure count of this block
+		 */
+		ret = c->mtd->read_oob (c->mtd, offset, oob_size << 1, &retlen, buf);
 
-	n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-	n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
-	n.totlen = cpu_to_je32(8);
-	p = (unsigned char *) &n;
-	
-	for (i = 0; i < fsdata_len; i++) {
-		if (buf[fsdata_pos+i] != p[i]) {
-			D2(printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset));
-			return 1;
+		if (ret) {
+			D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB failed %d for block at %08x\n", ret, jeb->offset));
+			return ret;
 		}
+		if (retlen < (oob_size << 1)) {
+			D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size << 1, jeb->offset));
+			return -EIO;
+		}
+
+		/* Check for bad block marker */
+		if (buf[badblock_pos] != 0xff) {
+			D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n", jeb->offset));
+			return 2;
+		}
+
+		/* Check for failure counter in the second page */
+		if (buf[badblock_pos + oob_size] != 0xff) {
+			D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Block marked as failed at %08x, fail count:%d\n", jeb->offset, buf[badblock_pos + oob_size]));
+			return 3;
+		}
+
+		/* Check cleanmarker only on the first physical block */
+		if (!cnt) {
+			n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
+			n.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
+			n.totlen = cpu_to_je32 (8);
+			p = (unsigned char *) &n;
+
+			for (i = 0; i < fsdata_len; i++) {
+				if (buf[fsdata_pos + i] != p[i]) {
+					D2 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset));
+					retval = 1;
+				}
+			}
+		}
+		offset += c->mtd->erasesize;
 	}
-	
-	return 0;
+	return retval;
 }
 
 int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
@@ -686,7 +711,7 @@
 		return ret;
 	}
 	if (retlen != fsdata_len) {
-		D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %d not %d\n", jeb->offset, retlen, fsdata_len));
+		D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %zd not %d\n", jeb->offset, retlen, fsdata_len));
 		return ret;
 	}
 	return 0;
@@ -721,7 +746,7 @@
 	}
 
 	if (retlen < oob_size) {
-		D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Read OOB return short read (%d bytes not %d) for block at %08x\n", retlen, oob_size, jeb->offset));
+		D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size, jeb->offset));
 		return -EIO;
 	}
 
@@ -767,9 +792,8 @@
 		return ret;
 	}
 	if (retlen != 1) {
-		D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Short write for block at %08x: %d not 1\n", jeb->offset, retlen));
+		D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Short write for block at %08x: %zd not 1\n", jeb->offset, retlen));
 		return ret;
 	}
 	return 0;
 }
-
diff -Nru a/fs/jffs2/write.c b/fs/jffs2/write.c
--- a/fs/jffs2/write.c	Tue Nov 19 05:28:42 2002
+++ b/fs/jffs2/write.c	Wed May 28 08:01:07 2003
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: write.c,v 1.60 2002/09/09 16:29:08 dwmw2 Exp $
+ * $Id: write.c,v 1.65 2003/01/21 18:11:29 dwmw2 Exp $
  *
  */
 
@@ -47,7 +47,7 @@
 	ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
 	ri->totlen = cpu_to_je32(PAD(sizeof(*ri)));
 	ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
-	ri->mode = cpu_to_je32(mode);
+	ri->mode = cpu_to_jemode(mode);
 
 	f->highest_version = 1;
 	ri->version = cpu_to_je32(f->highest_version);
@@ -55,6 +55,7 @@
 	return 0;
 }
 
+#if CONFIG_JFFS2_FS_DEBUG > 0
 static void writecheck(struct jffs2_sb_info *c, uint32_t ofs)
 {
 	unsigned char buf[16];
@@ -63,7 +64,7 @@
 
 	ret = jffs2_flash_read(c, ofs, 16, &retlen, buf);
 	if (ret || (retlen != 16)) {
-		D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %d\n", ret, retlen));
+		D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %zd\n", ret, retlen));
 		return;
 	}
 	ret = 0;
@@ -79,7 +80,7 @@
 		       buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
 	}
 }
-
+#endif
 
 
 /* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it, 
@@ -105,10 +106,10 @@
 	vecs[1].iov_base = (unsigned char *)data;
 	vecs[1].iov_len = datalen;
 
-	writecheck(c, flash_ofs);
+	D1(writecheck(c, flash_ofs));
 
 	if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) {
-		printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08x) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen);
+		printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen);
 	}
 	raw = jffs2_alloc_raw_node_ref();
 	if (!raw)
@@ -135,7 +136,7 @@
 	ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen);
 		
 	if (ret || (retlen != sizeof(*ri) + datalen)) {
-		printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n", 
+		printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", 
 		       sizeof(*ri)+datalen, flash_ofs, ret, retlen);
 		/* Mark the space as dirtied */
 		if (retlen) {
@@ -162,20 +163,27 @@
 		return ERR_PTR(ret?ret:-EIO);
 	}
 	/* Mark the space used */
-	if (datalen == PAGE_CACHE_SIZE)
+	/* If node covers at least a whole page, or if it starts at the 
+	   beginning of a page and runs to the end of the file, or if 
+	   it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. 
+	*/
+	if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) ||
+	    ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) &&
+	      (je32_to_cpu(ri->dsize)+je32_to_cpu(ri->offset) ==  je32_to_cpu(ri->isize)))) {
 		raw->flash_offset |= REF_PRISTINE;
-	else
+	} else {
 		raw->flash_offset |= REF_NORMAL;
+	}
 	jffs2_add_physical_node_ref(c, raw);
 
 	/* Link into per-inode list */
 	raw->next_in_ino = f->inocache->nodes;
 	f->inocache->nodes = raw;
 
-	D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n",
-		  flash_ofs, je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize),
-		  je32_to_cpu(ri->node_crc), je32_to_cpu(ri->data_crc), 
-		  je32_to_cpu(ri->totlen)));
+	D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n",
+		  flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), 
+		  je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc),
+		  je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen)));
 	if (writelen)
 		*writelen = retlen;
 
@@ -194,7 +202,7 @@
 	D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", 
 		  je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino),
 		  je32_to_cpu(rd->name_crc)));
-	writecheck(c, flash_ofs);
+	D1(writecheck(c, flash_ofs));
 
 	D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) {
 		printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n");
@@ -233,7 +241,7 @@
 
 	ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen);
 	if (ret || (retlen != sizeof(*rd) + namelen)) {
-		printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n", 
+		printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", 
 			       sizeof(*rd)+namelen, flash_ofs, ret, retlen);
 		/* Mark the space as dirtied */
 		if (retlen) {
@@ -290,7 +298,7 @@
 		}
 		down(&f->sem);
 		datalen = writelen;
-		cdatalen = min(alloclen - sizeof(*ri), writelen);
+		cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), writelen);
 
 		comprbuf = kmalloc(cdatalen, GFP_KERNEL);
 		if (comprbuf) {
@@ -392,7 +400,7 @@
 	fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, &writtenlen);
 
 	D1(printk(KERN_DEBUG "jffs2_do_create created file with mode 0x%x\n",
-		  je32_to_cpu(ri->mode)));
+		  jemode_to_cpu(ri->mode)));
 
 	if (IS_ERR(fn)) {
 		D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n"));
diff -Nru a/fs/msdos/namei.c b/fs/msdos/namei.c
--- a/fs/msdos/namei.c	Sun Nov 17 12:40:03 2002
+++ b/fs/msdos/namei.c	Tue May 27 07:32:40 2003
@@ -112,8 +112,9 @@
 }
 
 /***** Locates a directory entry.  Uses unformatted name. */
-static int msdos_find(struct inode *dir,const char *name,int len,
-    struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
+static int msdos_find(struct inode *dir, const char *name, int len,
+		      struct buffer_head **bh, struct msdos_dir_entry **de,
+		      loff_t *i_pos)
 {
 	int res;
 	char dotsOK;
@@ -123,7 +124,7 @@
 	res = msdos_format_name(name,len, msdos_name,&MSDOS_SB(dir->i_sb)->options);
 	if (res < 0)
 		return -ENOENT;
-	res = fat_scan(dir,msdos_name,bh,de,ino);
+	res = fat_scan(dir, msdos_name, bh, de, i_pos);
 	if (!res && dotsOK) {
 		if (name[0]=='.') {
 			if (!((*de)->attr & ATTR_HIDDEN))
@@ -134,7 +135,6 @@
 		}
 	}
 	return res;
-
 }
 
 /*
@@ -199,19 +199,19 @@
 	struct inode *inode = NULL;
 	struct msdos_dir_entry *de;
 	struct buffer_head *bh = NULL;
-	int ino,res;
+	loff_t i_pos;
+	int res;
 	
 	dentry->d_op = &msdos_dentry_operations;
 
 	lock_kernel();
 	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh,
-			&de, &ino);
-
+			 &de, &i_pos);
 	if (res == -ENOENT)
 		goto add;
 	if (res < 0)
 		goto out;
-	inode = fat_build_inode(sb, de, ino, &res);
+	inode = fat_build_inode(sb, de, i_pos, &res);
 	if (res)
 		goto out;
 add:
@@ -231,12 +231,11 @@
 static int msdos_add_entry(struct inode *dir, const char *name,
 			   struct buffer_head **bh,
 			   struct msdos_dir_entry **de,
-			   int *ino,
-			   int is_dir, int is_hid)
+			   loff_t *i_pos, int is_dir, int is_hid)
 {
 	int res;
 
-	res = fat_add_entries(dir, 1, bh, de, ino);
+	res = fat_add_entries(dir, 1, bh, de, i_pos);
 	if (res < 0)
 		return res;
 
@@ -268,7 +267,8 @@
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
 	struct inode *inode;
-	int ino,res,is_hid;
+	loff_t i_pos;
+	int res, is_hid;
 	char msdos_name[MSDOS_NAME];
 
 	lock_kernel();
@@ -280,18 +280,18 @@
 	}
 	is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
 	/* Have to do it due to foo vs. .foo conflicts */
-	if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
+	if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0) {
 		brelse(bh);
 		unlock_kernel();
 		return -EINVAL;
  	}
 	inode = NULL;
-	res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 0, is_hid);
+	res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 0, is_hid);
 	if (res) {
 		unlock_kernel();
 		return res;
 	}
-	inode = fat_build_inode(dir->i_sb, de, ino, &res);
+	inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
 	brelse(bh);
 	if (!inode) {
 		unlock_kernel();
@@ -308,14 +308,15 @@
 int msdos_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
-	int res,ino;
+	loff_t i_pos;
+	int res;
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
 
 	bh = NULL;
 	lock_kernel();
 	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
-				&bh, &de, &ino);
+			 &bh, &de, &i_pos);
 	if (res < 0)
 		goto rmdir_done;
 	/*
@@ -351,7 +352,7 @@
 	struct inode *inode;
 	int res,is_hid;
 	char msdos_name[MSDOS_NAME];
-	int ino;
+	loff_t i_pos;
 
 	lock_kernel();
 	res = msdos_format_name(dentry->d_name.name,dentry->d_name.len,
@@ -362,13 +363,13 @@
 	}
 	is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
 	/* foo vs .foo situation */
-	if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0)
+	if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0)
 		goto out_exist;
 
-	res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 1, is_hid);
+	res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 1, is_hid);
 	if (res)
 		goto out_unlock;
-	inode = fat_build_inode(dir->i_sb, de, ino, &res);
+	inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
 	if (!inode) {
 		brelse(bh);
 		goto out_unlock;
@@ -414,14 +415,15 @@
 int msdos_unlink( struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
-	int res,ino;
+	loff_t i_pos;
+	int res;
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
 
 	bh = NULL;
 	lock_kernel();
 	res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
-			&bh, &de, &ino);
+			 &bh, &de, &i_pos);
 	if (res < 0)
 		goto unlink_done;
 
@@ -443,12 +445,12 @@
     struct dentry *old_dentry,
     struct inode *new_dir,char *new_name, struct dentry *new_dentry,
     struct buffer_head *old_bh,
-    struct msdos_dir_entry *old_de, int old_ino, int is_hid)
+    struct msdos_dir_entry *old_de, loff_t old_i_pos, int is_hid)
 {
 	struct buffer_head *new_bh=NULL,*dotdot_bh=NULL;
 	struct msdos_dir_entry *new_de,*dotdot_de;
 	struct inode *old_inode,*new_inode;
-	int new_ino,dotdot_ino;
+	loff_t new_i_pos, dotdot_i_pos;
 	int error;
 	int is_dir;
 
@@ -456,7 +458,8 @@
 	new_inode = new_dentry->d_inode;
 	is_dir = S_ISDIR(old_inode->i_mode);
 
-	if (fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)>=0 &&!new_inode)
+	if (fat_scan(new_dir, new_name, &new_bh, &new_de, &new_i_pos) >= 0
+	    && !new_inode)
 		goto degenerate_case;
 	if (is_dir) {
 		if (new_inode) {
@@ -465,7 +468,7 @@
 				goto out;
 		}
 		error = fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
-				&dotdot_de, &dotdot_ino);
+				&dotdot_de, &dotdot_i_pos);
 		if (error < 0) {
 			printk(KERN_WARNING
 				"MSDOS: %s/%s, get dotdot failed, ret=%d\n",
@@ -476,7 +479,7 @@
 	}
 	if (!new_bh) {
 		error = msdos_add_entry(new_dir, new_name, &new_bh, &new_de,
-					&new_ino, is_dir, is_hid);
+					&new_i_pos, is_dir, is_hid);
 		if (error)
 			goto out;
 	}
@@ -489,7 +492,7 @@
 	old_de->name[0] = DELETED_FLAG;
 	mark_buffer_dirty(old_bh);
 	fat_detach(old_inode);
-	fat_attach(old_inode, new_ino);
+	fat_attach(old_inode, new_i_pos);
 	if (is_hid)
 		MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
 	else
@@ -544,8 +547,8 @@
 {
 	struct buffer_head *old_bh;
 	struct msdos_dir_entry *old_de;
-	int old_ino, error;
-	int is_hid,old_hid; /* if new file and old file are hidden */
+	loff_t old_i_pos;
+	int error, is_hid, old_hid; /* if new file and old file are hidden */
 	char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
 
 	lock_kernel();
@@ -562,13 +565,13 @@
 
 	is_hid  = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.');
 	old_hid = (old_dentry->d_name.name[0]=='.') && (old_msdos_name[0]!='.');
-	error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_ino);
+	error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_i_pos);
 	if (error < 0)
 		goto rename_done;
 
 	error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
 				new_dir, new_msdos_name, new_dentry,
-				old_bh, old_de, (ino_t)old_ino, is_hid);
+				old_bh, old_de, old_i_pos, is_hid);
 	brelse(old_bh);
 
 rename_done:
diff -Nru a/fs/namei.c b/fs/namei.c
--- a/fs/namei.c	Sun May  4 22:49:54 2003
+++ b/fs/namei.c	Thu May 29 22:42:41 2003
@@ -1671,7 +1671,7 @@
 			goto slashes;
 		inode = dentry->d_inode;
 		if (inode)
-			inode = igrab(inode);
+			atomic_inc(&inode->i_count);
 		error = vfs_unlink(nd.dentry->d_inode, dentry);
 	exit2:
 		dput(dentry);
diff -Nru a/fs/proc/inode.c b/fs/proc/inode.c
--- a/fs/proc/inode.c	Sun May 25 14:07:56 2003
+++ b/fs/proc/inode.c	Tue May 27 13:07:01 2003
@@ -61,8 +61,6 @@
 	struct proc_dir_entry *de;
 	struct task_struct *tsk;
 
-	inode->i_state = I_CLEAR;
-
 	/* Let go of any associated process */
 	tsk = PROC_I(inode)->task;
 	if (tsk)
@@ -75,6 +73,7 @@
 			module_put(de->owner);
 		de_put(de);
 	}
+	clear_inode(inode);
 }
 
 struct vfsmount *proc_mnt;
diff -Nru a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c
--- a/fs/proc/proc_tty.c	Mon Apr 21 20:58:43 2003
+++ b/fs/proc/proc_tty.c	Mon May 26 15:29:30 2003
@@ -57,8 +57,6 @@
 		break;
 	case TTY_DRIVER_TYPE_SERIAL:
 		seq_printf(m, "serial");
-		if (p->subtype == 2)
-			seq_printf(m, ":callout");
 		break;
 	case TTY_DRIVER_TYPE_PTY:
 		if (p->subtype == PTY_TYPE_MASTER)
diff -Nru a/fs/vfat/namei.c b/fs/vfat/namei.c
--- a/fs/vfat/namei.c	Sun Nov 17 11:53:57 2002
+++ b/fs/vfat/namei.c	Tue May 27 07:32:40 2003
@@ -317,9 +317,10 @@
 {
 	struct msdos_dir_entry *de;
 	struct buffer_head *bh = NULL;
-	int ino,res;
+	loff_t i_pos;
+	int res;
 
-	res = fat_scan(dir,name,&bh,&de,&ino);
+	res = fat_scan(dir, name, &bh, &de, &i_pos);
 	brelse(bh);
 	if (res < 0)
 		return -ENOENT;
@@ -781,7 +782,7 @@
 	int res, len;
 	struct msdos_dir_entry *dummy_de;
 	struct buffer_head *dummy_bh;
-	int dummy_ino;
+	loff_t dummy_i_pos;
 
 	dir_slots = (struct msdos_dir_slot *)
 	       kmalloc(sizeof(struct msdos_dir_slot) * MSDOS_SLOTS, GFP_KERNEL);
@@ -797,7 +798,7 @@
 		goto cleanup;
 
 	/* build the empty directory entry of number of slots */
-	offset = fat_add_entries(dir, slots, &dummy_bh, &dummy_de, &dummy_ino);
+	offset = fat_add_entries(dir, slots, &dummy_bh, &dummy_de, &dummy_i_pos);
 	if (offset < 0) {
 		res = offset;
 		goto cleanup;
@@ -807,7 +808,7 @@
 	/* Now create the new entry */
 	*bh = NULL;
 	for (slot = 0; slot < slots; slot++) {
-		if (fat_get_entry(dir, &offset, bh, de, &sinfo_out->ino) < 0) {
+		if (fat_get_entry(dir, &offset, bh, de, &sinfo_out->i_pos) < 0) {
 			res = -EIO;
 			goto cleanup;
 		}
@@ -852,7 +853,7 @@
 			&offset,&sinfo->longname_offset);
 	if (res>0) {
 		sinfo->long_slots = res-1;
-		if (fat_get_entry(dir,&offset,last_bh,last_de,&sinfo->ino)>=0)
+		if (fat_get_entry(dir,&offset,last_bh,last_de,&sinfo->i_pos)>=0)
 			return 0;
 		res = -EIO;
 	} 
@@ -882,7 +883,7 @@
 		table++;
 		goto error;
 	}
-	inode = fat_build_inode(dir->i_sb, de, sinfo.ino, &res);
+	inode = fat_build_inode(dir->i_sb, de, sinfo.i_pos, &res);
 	brelse(bh);
 	if (res) {
 		unlock_kernel();
@@ -926,7 +927,7 @@
 		unlock_kernel();
 		return res;
 	}
-	inode = fat_build_inode(sb, de, sinfo.ino, &res);
+	inode = fat_build_inode(sb, de, sinfo.i_pos, &res);
 	brelse(bh);
 	if (!inode) {
 		unlock_kernel();
@@ -945,8 +946,8 @@
 static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
      struct buffer_head *bh, struct msdos_dir_entry *de)
 {
-	loff_t offset;
-	int i,ino;
+	loff_t offset, i_pos;
+	int i;
 
 	/* remove the shortname */
 	dir->i_mtime = CURRENT_TIME;
@@ -958,7 +959,7 @@
 	/* remove the longname */
 	offset = sinfo->longname_offset; de = NULL;
 	for (i = sinfo->long_slots; i > 0; --i) {
-		if (fat_get_entry(dir, &offset, &bh, &de, &ino) < 0)
+		if (fat_get_entry(dir, &offset, &bh, &de, &i_pos) < 0)
 			continue;
 		de->name[0] = DELETED_FLAG;
 		de->attr = ATTR_NONE;
@@ -1040,7 +1041,7 @@
 		unlock_kernel();
 		return res;
 	}
-	inode = fat_build_inode(sb, de, sinfo.ino, &res);
+	inode = fat_build_inode(sb, de, sinfo.i_pos, &res);
 	if (!inode)
 		goto out;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
@@ -1078,7 +1079,7 @@
 {
 	struct buffer_head *old_bh,*new_bh,*dotdot_bh;
 	struct msdos_dir_entry *old_de,*new_de,*dotdot_de;
-	int dotdot_ino;
+	loff_t dotdot_i_pos;
 	struct inode *old_inode, *new_inode;
 	int res, is_dir;
 	struct vfat_slot_info old_sinfo,sinfo;
@@ -1094,13 +1095,13 @@
 	is_dir = S_ISDIR(old_inode->i_mode);
 
 	if (is_dir && (res = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
-				&dotdot_de,&dotdot_ino)) < 0)
+				&dotdot_de,&dotdot_i_pos)) < 0)
 		goto rename_done;
 
 	if (new_dentry->d_inode) {
 		res = vfat_find(new_dir,&new_dentry->d_name,&sinfo,&new_bh,
 				&new_de);
-		if (res < 0 || MSDOS_I(new_inode)->i_location != sinfo.ino) {
+		if (res < 0 || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
 			/* WTF??? Cry and fail. */
 			printk(KERN_WARNING "vfat_rename: fs corrupted\n");
 			goto rename_done;
@@ -1124,7 +1125,7 @@
 	vfat_remove_entry(old_dir,&old_sinfo,old_bh,old_de);
 	old_bh=NULL;
 	fat_detach(old_inode);
-	fat_attach(old_inode, sinfo.ino);
+	fat_attach(old_inode, sinfo.i_pos);
 	mark_inode_dirty(old_inode);
 
 	old_dir->i_version++;
diff -Nru a/include/asm-alpha/bitops.h b/include/asm-alpha/bitops.h
--- a/include/asm-alpha/bitops.h	Sat Apr 12 15:37:38 2003
+++ b/include/asm-alpha/bitops.h	Wed May 21 08:38:17 2003
@@ -233,7 +233,7 @@
 }
 
 static inline int
-test_bit(int nr, volatile void * addr)
+test_bit(int nr, const volatile void * addr)
 {
 	return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL;
 }
diff -Nru a/include/asm-arm/uaccess.h b/include/asm-arm/uaccess.h
--- a/include/asm-arm/uaccess.h	Sat Apr 12 16:00:03 2003
+++ b/include/asm-arm/uaccess.h	Wed May 28 06:17:24 2003
@@ -144,13 +144,13 @@
 		register int __e asm("r0");				\
 		switch (sizeof(*(__p))) {				\
 		case 1:							\
-			__put_user_x(__r1, __p, __e, 1, "r2", "lr");	\
+			__put_user_x(__r1, __p, __e, 1, "ip", "lr");	\
 			break;						\
 		case 2:							\
-			__put_user_x(__r1, __p, __e, 2, "r2", "lr");	\
+			__put_user_x(__r1, __p, __e, 2, "ip", "lr");	\
 			break;						\
 		case 4:							\
-			__put_user_x(__r1, __p, __e, 4, "r2", "lr");	\
+			__put_user_x(__r1, __p, __e, 4, "ip", "lr");	\
 			break;						\
 		case 8:							\
 			__put_user_x(__r1, __p, __e, 8, "ip", "lr");	\
diff -Nru a/include/asm-ppc/bug.h b/include/asm-ppc/bug.h
--- a/include/asm-ppc/bug.h	Wed Apr 30 05:41:43 2003
+++ b/include/asm-ppc/bug.h	Mon May 26 05:18:59 2003
@@ -1,21 +1,11 @@
 #ifndef _PPC_BUG_H
 #define _PPC_BUG_H
 
-#include <linux/config.h>
-#include <asm/xmon.h>
-
-#ifdef CONFIG_XMON
-extern void xmon(struct pt_regs *);
-#define BUG() do { \
-	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
-	xmon(0); \
-} while (0)
-#else
 #define BUG() do { \
 	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
 	__asm__ __volatile__(".long 0x0"); \
 } while (0)
-#endif
+
 #define PAGE_BUG(page) do { BUG(); } while (0)
 
 #endif
diff -Nru a/include/asm-ppc/ocp.h b/include/asm-ppc/ocp.h
--- a/include/asm-ppc/ocp.h	Sun Apr 20 16:21:18 2003
+++ b/include/asm-ppc/ocp.h	Mon May 26 04:51:52 2003
@@ -36,6 +36,7 @@
 #include <linux/list.h>
 #include <linux/config.h>
 #include <linux/device.h>
+#include <linux/errno.h>
 
 #include <asm/ocp_ids.h>
 #include <asm/mmu.h>		/* For phys_addr_t */
diff -Nru a/include/asm-ppc/ptrace.h b/include/asm-ppc/ptrace.h
--- a/include/asm-ppc/ptrace.h	Sat Jan  4 00:44:11 2003
+++ b/include/asm-ppc/ptrace.h	Mon May 26 04:49:40 2003
@@ -33,7 +33,7 @@
 	/* N.B. for critical exceptions on 4xx, the dar and dsisr
 	   fields are overloaded to hold srr0 and srr1. */
 	unsigned long dar;		/* Fault registers */
-	unsigned long dsisr;
+	unsigned long dsisr;		/* on 4xx/Book-E used for ESR */
 	unsigned long result; 		/* Result of a system call */
 };
 
diff -Nru a/include/asm-v850/bitops.h b/include/asm-v850/bitops.h
--- a/include/asm-v850/bitops.h	Sat Apr 12 15:37:38 2003
+++ b/include/asm-v850/bitops.h	Tue May 27 02:53:02 2003
@@ -1,8 +1,8 @@
 /*
  * include/asm-v850/bitops.h -- Bit operations
  *
- *  Copyright (C) 2001,02  NEC Corporation
- *  Copyright (C) 2001,02  Miles Bader <miles@gnu.org>
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
  *  Copyright (C) 1992  Linus Torvalds.
  *
  * This file is subject to the terms and conditions of the GNU General
@@ -133,7 +133,7 @@
                 "m" (*((const char *)(addr) + ((nr) >> 3))));		\
      __test_bit_res;							\
   })
-extern __inline__ int __test_bit (int nr, void *addr)
+extern __inline__ int __test_bit (int nr, const void *addr)
 {
 	int res;
 	__asm__ ("tst1 %1, [%2]; setf nz, %0"
diff -Nru a/include/asm-v850/nb85e_cache.h b/include/asm-v850/nb85e_cache.h
--- a/include/asm-v850/nb85e_cache.h	Sat Apr 12 16:21:01 2003
+++ b/include/asm-v850/nb85e_cache.h	Tue May 27 00:09:43 2003
@@ -35,7 +35,7 @@
 #define L1_CACHE_BYTES				NB85E_CACHE_LINE_SIZE
 
 
-#ifndef __ASSEMBLY__
+#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
 
 /* Set caching params via the BHC and DCC registers.  */
 void nb85e_cache_enable (u16 bhc, u16 dcc);
@@ -73,6 +73,6 @@
 #define flush_icache_user_range	nb85e_cache_flush_icache_user_range
 #define flush_cache_sigtramp	nb85e_cache_flush_sigtramp
 
-#endif /* !__ASSEMBLY__ */
+#endif /* __KERNEL__ && !__ASSEMBLY__ */
 
 #endif /* __V850_NB85E_CACHE_H__ */
diff -Nru a/include/asm-v850/sim.h b/include/asm-v850/sim.h
--- a/include/asm-v850/sim.h	Tue Feb 25 10:44:12 2003
+++ b/include/asm-v850/sim.h	Tue May 27 00:09:43 2003
@@ -1,8 +1,8 @@
 /*
  * include/asm-v850/sim.h -- Machine-dependent defs for GDB v850e simulator
  *
- *  Copyright (C) 2001,02  NEC Corporation
- *  Copyright (C) 2001,02  Miles Bader <miles@gnu.org>
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
  *
  * This file is subject to the terms and conditions of the GNU General
  * Public License.  See the file COPYING in the main directory of this
diff -Nru a/include/linux/bio.h b/include/linux/bio.h
--- a/include/linux/bio.h	Sun May 25 09:19:53 2003
+++ b/include/linux/bio.h	Mon May 26 18:53:44 2003
@@ -222,6 +222,7 @@
 };
 extern struct bio_pair *bio_split(struct bio *bi, mempool_t *pool,
 				  int first_sectors);
+extern mempool_t *bio_split_pool;
 extern void bio_pair_release(struct bio_pair *dbio);
 
 extern struct bio *bio_alloc(int, int);
diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h	Thu May  8 02:30:11 2003
+++ b/include/linux/blkdev.h	Tue May 27 13:15:31 2003
@@ -179,7 +179,8 @@
 	unsigned long *tag_map;		/* bit map of free/busy tags */
 	struct list_head busy_list;	/* fifo list of busy tags */
 	int busy;			/* current depth */
-	int max_depth;
+	int max_depth;			/* what we will send to device */
+	int real_max_depth;		/* what the array can hold */
 };
 
 struct request_queue
@@ -452,6 +453,7 @@
 extern void blk_queue_end_tag(request_queue_t *, struct request *);
 extern int blk_queue_init_tags(request_queue_t *, int);
 extern void blk_queue_free_tags(request_queue_t *);
+extern int blk_queue_resize_tags(request_queue_t *, int);
 extern void blk_queue_invalidate_tags(request_queue_t *);
 extern void blk_congestion_wait(int rw, long timeout);
 
diff -Nru a/include/linux/cyclades.h b/include/linux/cyclades.h
--- a/include/linux/cyclades.h	Fri Mar  7 23:24:39 2003
+++ b/include/linux/cyclades.h	Mon May 26 15:29:19 2003
@@ -588,8 +588,6 @@
 	int                     breakon;
 	int                     breakoff;
 	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
 	unsigned char 		*xmit_buf;
 	int			xmit_head;
 	int			xmit_tail;
@@ -599,7 +597,6 @@
 	unsigned long		jiffies[3];
 	unsigned long		rflush_count;
 	struct termios		normal_termios;
-	struct termios		callout_termios;
 	struct cyclades_monitor	mon;
 	struct cyclades_idle_stats	idle_stats;
 	struct cyclades_icount	icount;
diff -Nru a/include/linux/generic_serial.h b/include/linux/generic_serial.h
--- a/include/linux/generic_serial.h	Tue Jun 25 13:50:38 2002
+++ b/include/linux/generic_serial.h	Mon May 26 15:29:12 2003
@@ -37,11 +37,8 @@
   /*  struct semaphore        port_write_sem; */
   int                     flags;
   struct termios          normal_termios;
-  struct termios          callout_termios;
   wait_queue_head_t       open_wait;
   wait_queue_head_t       close_wait;
-  long                    session;
-  long                    pgrp;
   int                     count;
   int                     blocked_open;
   struct tty_struct       *tty;
@@ -67,8 +64,6 @@
 
 
 #define GS_TYPE_NORMAL   1
-#define GS_TYPE_CALLOUT  2
-
 
 #define GS_DEBUG_FLUSH   0x00000001
 #define GS_DEBUG_BTR     0x00000002
diff -Nru a/include/linux/hayesesp.h b/include/linux/hayesesp.h
--- a/include/linux/hayesesp.h	Tue Oct  1 09:43:11 2002
+++ b/include/linux/hayesesp.h	Mon May 26 15:29:18 2003
@@ -96,8 +96,6 @@
 	int			line;
 	int			count;	    /* # of fd on device */
 	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
 	unsigned char 		*xmit_buf;
 	int			xmit_head;
 	int			xmit_tail;
@@ -105,7 +103,6 @@
 	struct work_struct	tqueue;
 	struct work_struct	tqueue_hangup;
 	struct termios		normal_termios;
-	struct termios		callout_termios;
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
 	wait_queue_head_t	delta_msr_wait;
diff -Nru a/include/linux/isdn.h b/include/linux/isdn.h
--- a/include/linux/isdn.h	Sun Apr 20 16:21:19 2003
+++ b/include/linux/isdn.h	Mon May 26 15:29:27 2003
@@ -250,8 +250,6 @@
 #define ISDN_ASYNC_SPLIT_TERMIOS      0x0008 /* Sep. termios for dialin/out  */
 #define ISDN_SERIAL_XMIT_SIZE           1024 /* Default bufsize for write    */
 #define ISDN_SERIAL_XMIT_MAX            4000 /* Maximum bufsize for write    */
-#define ISDN_SERIAL_TYPE_NORMAL            1
-#define ISDN_SERIAL_TYPE_CALLOUT           2
 
 #ifdef CONFIG_ISDN_AUDIO
 /* For using sk_buffs with audio we need some private variables
@@ -301,8 +299,6 @@
   int			line;
   int			count;		 /* # of fd on device              */
   int			blocked_open;	 /* # of blocked opens             */
-  long			session;	 /* Session of opening process     */
-  long			pgrp;		 /* pgrp of opening process        */
   int                   online;          /* 1 = B-Channel is up, drop data */
 					 /* 2 = B-Channel is up, deliver d.*/
   int                   dialing;         /* Dial in progress or ATA        */
@@ -348,7 +344,6 @@
   struct timer_list     connect_timer;   /* waiting for CONNECT            */
   struct timer_list     read_timer;      /* read incoming data             */
   struct termios	normal_termios;  /* For saving termios structs     */
-  struct termios	callout_termios;
   wait_queue_head_t	open_wait, close_wait;
   struct semaphore      write_sem;
 } modem_info;
diff -Nru a/include/linux/isicom.h b/include/linux/isicom.h
--- a/include/linux/isicom.h	Tue Oct  1 09:43:06 2002
+++ b/include/linux/isicom.h	Mon May 26 15:29:13 2003
@@ -148,8 +148,6 @@
 	unsigned short		channel;
 	unsigned short		status;
 	unsigned short		closing_wait;
-	long 			session;
-	long			pgrp;
 	struct isi_board	* card;
 	struct tty_struct 	* tty;
 	wait_queue_head_t	close_wait;
@@ -161,7 +159,6 @@
 	int			xmit_tail;
 	int			xmit_cnt;
 	struct termios 		normal_termios;
-	struct termios		callout_termios;
 };
 
 
diff -Nru a/include/linux/istallion.h b/include/linux/istallion.h
--- a/include/linux/istallion.h	Tue Oct  1 09:42:53 2002
+++ b/include/linux/istallion.h	Mon May 26 15:29:11 2003
@@ -66,8 +66,6 @@
 	int			rc;
 	int			argsize;
 	void			*argp;
-	long			session;
-	long			pgrp;
 	unsigned int		rxmarkmsk;
 	struct tty_struct	*tty;
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
@@ -81,7 +79,6 @@
 #endif
 	struct work_struct	tqhangup;
 	struct termios		normaltermios;
-	struct termios		callouttermios;
 	asysigs_t		asig;
 	unsigned long		addr;
 	unsigned long		rxoffset;
diff -Nru a/include/linux/jffs2.h b/include/linux/jffs2.h
--- a/include/linux/jffs2.h	Tue Nov 12 08:11:58 2002
+++ b/include/linux/jffs2.h	Wed May 28 08:01:07 2003
@@ -8,19 +8,23 @@
  * For licensing information, see the file 'LICENCE' in the 
  * jffs2 directory.
  *
- * $Id: jffs2.h,v 1.25 2002/08/20 21:37:27 dwmw2 Exp $
+ * $Id: jffs2.h,v 1.30 2003/02/15 00:15:22 dwmw2 Exp $
  *
  */
 
 #ifndef __LINUX_JFFS2_H__
 #define __LINUX_JFFS2_H__
 
+/* You must include something which defines the C99 uintXX_t types. 
+   We don't do it from here because this file is used in too many
+   different environments. */
+
 #define JFFS2_SUPER_MAGIC 0x72b6
 
 /* Values we may expect to find in the 'magic' field */
 #define JFFS2_OLD_MAGIC_BITMASK 0x1984
 #define JFFS2_MAGIC_BITMASK 0x1985
-#define KSAMTIB_CIGAM_2SFFJ 0x5981 /* For detecting wrong-endian fs */
+#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */
 #define JFFS2_EMPTY_BITMASK 0xffff
 #define JFFS2_DIRTY_BITMASK 0x0000
 
@@ -76,29 +80,42 @@
 } __attribute__((packed))  jint32_t;
 
 typedef struct {
+	uint32_t m;
+} __attribute__((packed))  jmode_t;
+
+typedef struct {
 	uint16_t v16;
 } __attribute__((packed)) jint16_t;
 
 #define JFFS2_NATIVE_ENDIAN
 
+/* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from
+   whatever OS we're actually running on here too. */
+
 #if defined(JFFS2_NATIVE_ENDIAN)
 #define cpu_to_je16(x) ((jint16_t){x})
 #define cpu_to_je32(x) ((jint32_t){x})
+#define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)})
 
 #define je16_to_cpu(x) ((x).v16)
 #define je32_to_cpu(x) ((x).v32)
+#define jemode_to_cpu(x) (jffs2_to_os_mode((x).m))
 #elif defined(JFFS2_BIG_ENDIAN)
 #define cpu_to_je16(x) ((jint16_t){cpu_to_be16(x)})
 #define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)})
+#define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))})
 
 #define je16_to_cpu(x) (be16_to_cpu(x.v16))
 #define je32_to_cpu(x) (be32_to_cpu(x.v32))
+#define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m)))
 #elif defined(JFFS2_LITTLE_ENDIAN)
 #define cpu_to_je16(x) ((jint16_t){cpu_to_le16(x)})
 #define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)})
+#define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))})
 
 #define je16_to_cpu(x) (le16_to_cpu(x.v16))
 #define je32_to_cpu(x) (le32_to_cpu(x.v32))
+#define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m)))
 #else 
 #error wibble
 #endif
@@ -144,7 +161,7 @@
 	jint32_t hdr_crc;
 	jint32_t ino;        /* Inode number.  */
 	jint32_t version;    /* Version number.  */
-	jint32_t mode;       /* The file's type or mode.  */
+	jmode_t mode;       /* The file's type or mode.  */
 	jint16_t uid;        /* The file's owner.  */
 	jint16_t gid;        /* The file's group.  */
 	jint32_t isize;      /* Total resultant size of this inode (used for truncations)  */
@@ -159,7 +176,7 @@
 	jint16_t flags;	     /* See JFFS2_INO_FLAG_* */
 	jint32_t data_crc;   /* CRC for the (compressed) data.  */
 	jint32_t node_crc;   /* CRC for the raw inode (excluding data)  */
-//	uint8_t data[dsize];
+	uint8_t data[0];
 } __attribute__((packed));
 
 union jffs2_node_union {
diff -Nru a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h
--- a/include/linux/jffs2_fs_sb.h	Tue Nov 12 08:11:59 2002
+++ b/include/linux/jffs2_fs_sb.h	Wed May 28 08:01:07 2003
@@ -1,4 +1,4 @@
-/* $Id: jffs2_fs_sb.h,v 1.35 2002/11/12 09:42:18 dwmw2 Exp $ */
+/* $Id: jffs2_fs_sb.h,v 1.37 2003/01/17 16:04:44 dwmw2 Exp $ */
 
 #ifndef _JFFS2_FS_SB
 #define _JFFS2_FS_SB
@@ -8,6 +8,8 @@
 #include <linux/workqueue.h>
 #include <linux/completion.h>
 #include <asm/semaphore.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
 #include <linux/list.h>
 
 #define JFFS2_SB_FLAG_RO 1
@@ -73,6 +75,7 @@
 						   against erase completion handler */
 	wait_queue_head_t erase_wait;		/* For waiting for erases to complete */
 
+	wait_queue_head_t inocache_wq;
 	struct jffs2_inode_cache **inocache_list;
 	spinlock_t inocache_lock;
 	
diff -Nru a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
--- a/include/linux/msdos_fs.h	Mon May 12 21:23:11 2003
+++ b/include/linux/msdos_fs.h	Tue May 27 07:32:54 2003
@@ -27,8 +27,6 @@
 
 #define MSDOS_SUPER_MAGIC 0x4d44 /* MD */
 
-#define FAT_CACHE    8 /* FAT cache size */
-
 #define ATTR_NONE    0 /* no attribute bits */
 #define ATTR_RO      1  /* read-only */
 #define ATTR_HIDDEN  2  /* hidden */
@@ -178,7 +176,7 @@
 struct vfat_slot_info {
 	int long_slots;		       /* number of long slots in filename */
 	loff_t longname_offset;	       /* dir offset for longname start */
-	int ino;		       /* ino for the file */
+	loff_t i_pos;		       /* on-disk position of directory entry */
 };
 
 /* Convert attribute bits and a mask to the UNIX mode. */
@@ -204,14 +202,6 @@
 	return container_of(inode, struct msdos_inode_info, vfs_inode);
 }
 
-struct fat_cache {
-	struct super_block *sb; /* fs in question.  NULL means unused */
-	int start_cluster; /* first cluster of the chain. */
-	int file_cluster; /* cluster number in the file. */
-	int disk_cluster; /* cluster number on disk. */
-	struct fat_cache *next; /* next cache entry */
-};
-
 static inline void fat16_towchar(wchar_t *dst, const __u8 *src, size_t len)
 {
 #ifdef __BIG_ENDIAN
@@ -241,13 +231,12 @@
 /* fat/cache.c */
 extern int fat_access(struct super_block *sb, int nr, int new_value);
 extern int __fat_access(struct super_block *sb, int nr, int new_value);
-extern int fat_bmap(struct inode *inode, int sector);
-extern void fat_cache_init(void);
+extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys);
+extern void fat_cache_init(struct super_block *sb);
 extern void fat_cache_lookup(struct inode *inode, int cluster, int *f_clu,
 			     int *d_clu);
 extern void fat_cache_add(struct inode *inode, int f_clu, int d_clu);
 extern void fat_cache_inval_inode(struct inode *inode);
-extern void fat_cache_inval_dev(struct super_block *sb);
 extern int fat_free(struct inode *inode, int skip);
 
 /* fat/dir.c */
@@ -259,7 +248,7 @@
 			 unsigned int cmd, unsigned long arg);
 extern int fat_dir_empty(struct inode *dir);
 extern int fat_add_entries(struct inode *dir, int slots, struct buffer_head **bh,
-			   struct msdos_dir_entry **de, int *ino);
+			struct msdos_dir_entry **de, loff_t *i_pos);
 extern int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat);
 
 /* fat/file.c */
@@ -271,11 +260,11 @@
 
 /* fat/inode.c */
 extern void fat_hash_init(void);
-extern void fat_attach(struct inode *inode, int i_pos);
+extern void fat_attach(struct inode *inode, loff_t i_pos);
 extern void fat_detach(struct inode *inode);
-extern struct inode *fat_iget(struct super_block *sb, int i_pos);
+extern struct inode *fat_iget(struct super_block *sb, loff_t i_pos);
 extern struct inode *fat_build_inode(struct super_block *sb,
-				     struct msdos_dir_entry *de, int ino, int *res);
+			struct msdos_dir_entry *de, loff_t i_pos, int *res);
 extern void fat_delete_inode(struct inode *inode);
 extern void fat_clear_inode(struct inode *inode);
 extern void fat_put_super(struct super_block *sb);
@@ -295,26 +284,27 @@
 extern int date_dos2unix(unsigned short time, unsigned short date);
 extern void fat_date_unix2dos(int unix_date, unsigned short *time,
 			      unsigned short *date);
-extern int fat__get_entry(struct inode *dir, loff_t *pos, struct buffer_head **bh,
-			  struct msdos_dir_entry **de, int *ino);
+extern int fat__get_entry(struct inode *dir, loff_t *pos,
+			  struct buffer_head **bh,
+			  struct msdos_dir_entry **de, loff_t *i_pos);
 static __inline__ int fat_get_entry(struct inode *dir, loff_t *pos,
 				    struct buffer_head **bh,
-				    struct msdos_dir_entry **de, int *ino)
+				    struct msdos_dir_entry **de, loff_t *i_pos)
 {
 	/* Fast stuff first */
 	if (*bh && *de &&
 	    (*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) {
 		*pos += sizeof(struct msdos_dir_entry);
 		(*de)++;
-		(*ino)++;
+		(*i_pos)++;
 		return 0;
 	}
-	return fat__get_entry(dir,pos,bh,de,ino);
+	return fat__get_entry(dir, pos, bh, de, i_pos);
 }
 extern int fat_subdirs(struct inode *dir);
 extern int fat_scan(struct inode *dir, const char *name,
 		    struct buffer_head **res_bh,
-		    struct msdos_dir_entry **res_de, int *ino);
+		    struct msdos_dir_entry **res_de, loff_t *i_pos);
 
 /* msdos/namei.c  - these are for Umsdos */
 extern struct dentry *msdos_lookup(struct inode *dir, struct dentry *);
diff -Nru a/include/linux/msdos_fs_i.h b/include/linux/msdos_fs_i.h
--- a/include/linux/msdos_fs_i.h	Thu Jul 18 17:18:06 2002
+++ b/include/linux/msdos_fs_i.h	Tue May 27 07:32:57 2003
@@ -8,12 +8,16 @@
  */
 
 struct msdos_inode_info {
+	/* cache of lastest accessed cluster */
+	int file_cluster;	/* cluster number in the file. */
+	int disk_cluster;	/* cluster number on disk. */
+
 	loff_t mmu_private;
 	int i_start;	/* first cluster or 0 */
 	int i_logstart;	/* logical first cluster */
 	int i_attrs;	/* unused attribute bits */
 	int i_ctime_ms;	/* unused change time in milliseconds */
-	int i_location;	/* on-disk position of directory entry or 0 */
+	loff_t i_pos;	/* on-disk position of directory entry or 0 */
 	struct list_head i_fat_hash;	/* hash by i_location */
 	struct inode vfs_inode;
 };
diff -Nru a/include/linux/msdos_fs_sb.h b/include/linux/msdos_fs_sb.h
--- a/include/linux/msdos_fs_sb.h	Sat Nov 30 14:12:40 2002
+++ b/include/linux/msdos_fs_sb.h	Tue May 27 07:32:54 2003
@@ -26,6 +26,15 @@
 		 nocase:1;	  /* Does this need case conversion? 0=need case conversion*/
 };
 
+#define FAT_CACHE_NR	8 /* number of FAT cache */
+
+struct fat_cache {
+	int start_cluster; /* first cluster of the chain. */
+	int file_cluster; /* cluster number in the file. */
+	int disk_cluster; /* cluster number on disk. */
+	struct fat_cache *next; /* next cache entry */
+};
+
 struct msdos_sb_info {
 	unsigned short cluster_size; /* sectors/cluster */
 	unsigned short cluster_bits; /* sectors/cluster */
@@ -47,6 +56,9 @@
 	void *dir_ops;		     /* Opaque; default directory operations */
 	int dir_per_block;	     /* dir entries per block */
 	int dir_per_block_bits;	     /* log2(dir_per_block) */
+
+	spinlock_t cache_lock;
+	struct fat_cache cache_array[FAT_CACHE_NR], *cache;
 };
 
 #endif
diff -Nru a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/mtd/blktrans.h	Wed May 28 08:01:26 2003
@@ -0,0 +1,75 @@
+/*
+ * $Id: blktrans.h,v 1.4 2003/05/21 01:01:32 dwmw2 Exp $
+ *
+ * (C) 2003 David Woodhouse <dwmw2@infradead.org>
+ *
+ * Interface to Linux block layer for MTD 'translation layers'.
+ *
+ */
+
+#ifndef __MTD_TRANS_H__
+#define __MTD_TRANS_H__
+
+#include <asm/semaphore.h>
+
+struct mtd_info;
+struct mtd_blktrans_ops;
+struct file;
+struct inode;
+
+struct mtd_blktrans_dev {
+	struct mtd_blktrans_ops *tr;
+	struct list_head list;
+	struct mtd_info *mtd;
+	struct semaphore sem;
+	int devnum;
+	int blksize;
+	unsigned long size;
+	int readonly;
+	void *blkcore_priv; /* gendisk in 2.5, devfs_handle in 2.4 */
+};
+
+struct blkcore_priv; /* Differs for 2.4 and 2.5 kernels; private */
+
+struct mtd_blktrans_ops {
+	char *name;
+	int major;
+	int part_bits;
+
+	/* Access functions */
+	int (*readsect)(struct mtd_blktrans_dev *dev,
+		    unsigned long block, char *buffer);
+	int (*writesect)(struct mtd_blktrans_dev *dev,
+		     unsigned long block, char *buffer);
+
+	/* HDIO_GETGEO and HDIO_GETGEO_BIG are the only non-private
+	   ioctls which are expected to be passed through */
+	int (*ioctl)(struct mtd_blktrans_dev *dev,
+		     struct inode * inode, struct file * file, 
+		     unsigned int cmd, unsigned long arg);
+
+	/* Called with mtd_table_mutex held; no race with add/remove */
+	int (*open)(struct mtd_blktrans_dev *dev, 
+		 struct inode *i, struct file *f);
+	int (*release)(struct mtd_blktrans_dev *dev,
+		    struct inode *i, struct file *f);
+
+	/* Called on {de,}registration and on subsequent addition/removal
+	   of devices, with mtd_table_mutex held. */
+	void (*add_mtd)(struct mtd_blktrans_ops *tr, struct mtd_info *mtd);
+	void (*remove_dev)(struct mtd_blktrans_dev *dev);
+
+	struct list_head devs;
+	struct list_head list;
+	struct module *owner;
+
+	struct mtd_blkcore_priv *blkcore_priv;
+};
+
+extern int register_mtd_blktrans(struct mtd_blktrans_ops *tr);
+extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr);
+extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
+extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
+				 
+
+#endif /* __MTD_TRANS_H__ */
diff -Nru a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h
--- a/include/linux/mtd/cfi.h	Tue Feb  5 07:26:32 2002
+++ b/include/linux/mtd/cfi.h	Wed May 28 08:56:02 2003
@@ -1,13 +1,14 @@
 
 /* Common Flash Interface structures 
  * See http://support.intel.com/design/flash/technote/index.htm
- * $Id: cfi.h,v 1.25 2001/09/04 07:06:21 dwmw2 Exp $
+ * $Id: cfi.h,v 1.35 2003/05/28 15:37:32 dwmw2 Exp $
  */
 
 #ifndef __MTD_CFI_H__
 #define __MTD_CFI_H__
 
 #include <linux/config.h>
+#include <linux/version.h>
 #include <linux/delay.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
@@ -18,13 +19,16 @@
  * You can optimize the code size and performance by defining only 
  * the geometry(ies) available on your hardware.
  * CFIDEV_INTERLEAVE_n, where  represents the interleave (number of chips to fill the bus width)
- * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2 or 4 bytes)
+ * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2, 4 or 8 bytes)
  *
  * By default, all (known) geometries are supported.
  */
 
 #ifndef CONFIG_MTD_CFI_GEOMETRY
 
+/* The default case - support all but 64-bit, which has
+   a performance penalty */
+
 #define CFIDEV_INTERLEAVE_1 (1)
 #define CFIDEV_INTERLEAVE_2 (2)
 #define CFIDEV_INTERLEAVE_4 (4)
@@ -33,8 +37,12 @@
 #define CFIDEV_BUSWIDTH_2 (2)
 #define CFIDEV_BUSWIDTH_4 (4)
 
+typedef __u32 cfi_word;
+
 #else
 
+/* Explicitly configured buswidth/interleave support */
+
 #ifdef CONFIG_MTD_CFI_I1
 #define CFIDEV_INTERLEAVE_1 (1)
 #endif
@@ -44,6 +52,9 @@
 #ifdef CONFIG_MTD_CFI_I4
 #define CFIDEV_INTERLEAVE_4 (4)
 #endif
+#ifdef CONFIG_MTD_CFI_I8
+#define CFIDEV_INTERLEAVE_8 (8)
+#endif
 
 #ifdef CONFIG_MTD_CFI_B1
 #define CFIDEV_BUSWIDTH_1 (1)
@@ -54,6 +65,27 @@
 #ifdef CONFIG_MTD_CFI_B4
 #define CFIDEV_BUSWIDTH_4 (4)
 #endif
+#ifdef CONFIG_MTD_CFI_B8
+#define CFIDEV_BUSWIDTH_8 (8)
+#endif
+
+/* pick the largest necessary */
+#ifdef CONFIG_MTD_CFI_B8
+typedef __u64 cfi_word;
+
+/* This only works if asm/io.h is included first */
+#ifndef __raw_readll
+#define __raw_readll(addr)	(*(volatile __u64 *)(addr))
+#endif
+#ifndef __raw_writell
+#define __raw_writell(v, addr)	(*(volatile __u64 *)(addr) = (v))
+#endif
+#define CFI_WORD_64
+#else  /* CONFIG_MTD_CFI_B8 */
+/* All others can use 32-bits. It's probably more efficient than
+   the smaller types anyway */
+typedef __u32 cfi_word;
+#endif /* CONFIG_MTD_CFI_B8 */
 
 #endif
 
@@ -61,12 +93,15 @@
  * The following macros are used to select the code to execute:
  *   cfi_buswidth_is_*()
  *   cfi_interleave_is_*()
- *   [where * is either 1, 2 or 4]
+ *   [where * is either 1, 2, 4, or 8]
  * Those macros should be used with 'if' statements.  If only one of few
  * geometry arrangements are selected, they expand to constants thus allowing
  * the compiler (most of them being 0) to optimize away all the unneeded code,
  * while still validating the syntax (which is not possible with embedded 
  * #if ... #endif constructs).
+ * The exception to this is the 64-bit versions, which need an extension
+ * to the cfi_word type, and cause compiler warnings about shifts being
+ * out of range.
  */
 
 #ifdef CFIDEV_INTERLEAVE_1
@@ -105,6 +140,18 @@
 # define cfi_interleave_is_4() (0)
 #endif
 
+#ifdef CFIDEV_INTERLEAVE_8
+# ifdef CFIDEV_INTERLEAVE
+#  undef CFIDEV_INTERLEAVE
+#  define CFIDEV_INTERLEAVE (cfi->interleave)
+# else
+#  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_8
+# endif
+# define cfi_interleave_is_8() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_8)
+#else
+# define cfi_interleave_is_8() (0)
+#endif
+
 #ifndef CFIDEV_INTERLEAVE
 #error You must define at least one interleave to support!
 #endif
@@ -145,6 +192,18 @@
 # define cfi_buswidth_is_4() (0)
 #endif
 
+#ifdef CFIDEV_BUSWIDTH_8
+# ifdef CFIDEV_BUSWIDTH
+#  undef CFIDEV_BUSWIDTH
+#  define CFIDEV_BUSWIDTH (map->buswidth)
+# else
+#  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_8
+# endif
+# define cfi_buswidth_is_8() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_8)
+#else
+# define cfi_buswidth_is_8() (0)
+#endif
+
 #ifndef CFIDEV_BUSWIDTH
 #error You must define at least one bus width to support!
 #endif
@@ -156,6 +215,7 @@
 #define CFI_DEVICETYPE_X8  (8 / 8)
 #define CFI_DEVICETYPE_X16 (16 / 8)
 #define CFI_DEVICETYPE_X32 (32 / 8)
+#define CFI_DEVICETYPE_X64 (64 / 8)
 
 /* NB: We keep these structures in memory in HOST byteorder, except
  * where individually noted.
@@ -206,6 +266,10 @@
   __u16 BlkStatusRegMask;
   __u8  VccOptimal;
   __u8  VppOptimal;
+  __u8  NumProtectionFields;
+  __u16 ProtRegAddr;
+  __u8  FactProtRegSize;
+  __u8  UserProtRegSize;
 } __attribute__((packed));
 
 struct cfi_pri_query {
@@ -229,8 +293,8 @@
 #define P_ID_RESERVED 65535
 
 
-#define CFI_MODE_CFI	0
-#define CFI_MODE_JEDEC	1
+#define CFI_MODE_CFI	1
+#define CFI_MODE_JEDEC	0
 
 struct cfi_private {
 	__u16 cmdset;
@@ -264,9 +328,9 @@
 /*
  * Transforms the CFI command for the given geometry (bus width & interleave.
  */
-static inline __u32 cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
+static inline cfi_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
 {
-	__u32 val = 0;
+	cfi_word val = 0;
 
 	if (cfi_buswidth_is_1()) {
 		/* 1 x8 device */
@@ -291,6 +355,27 @@
 			val = (cmd << 16) | cmd;
 			val = cpu_to_cfi32((val << 8) | val);
 		}
+#ifdef CFI_WORD_64
+	} else if (cfi_buswidth_is_8()) {
+		if (cfi_interleave_is_1()) {
+			/* 1 x64 device in x64 mode */
+			val = cpu_to_cfi64(cmd);
+		} else if (cfi_interleave_is_2()) {
+			/* 2 x32 device in x32 mode */
+			val = cmd;
+			val = cpu_to_cfi64((val << 32) | val);
+		} else if (cfi_interleave_is_4()) {
+			/* 4 (x16, x32 or x64) devices in x16 mode */
+			val = (cmd << 16) | cmd;
+			val = cpu_to_cfi64((val << 32) | val);
+		} else if (cfi_interleave_is_8()) {
+			/* 8 (x8, x16 or x32) devices in x8 mode */
+			val = (cmd << 8) | cmd;
+			val = (val << 16) | val;
+			val = (val << 32) | val;
+			val = cpu_to_cfi64(val);
+		}
+#endif /* CFI_WORD_64 */
 	}
 	return val;
 }
@@ -300,14 +385,16 @@
  * Read a value according to the bus width.
  */
 
-static inline __u32 cfi_read(struct map_info *map, __u32 addr)
+static inline cfi_word cfi_read(struct map_info *map, __u32 addr)
 {
 	if (cfi_buswidth_is_1()) {
-		return map->read8(map, addr);
+		return map_read8(map, addr);
 	} else if (cfi_buswidth_is_2()) {
-		return map->read16(map, addr);
+		return map_read16(map, addr);
 	} else if (cfi_buswidth_is_4()) {
-		return map->read32(map, addr);
+		return map_read32(map, addr);
+	} else if (cfi_buswidth_is_8()) {
+		return map_read64(map, addr);
 	} else {
 		return 0;
 	}
@@ -317,14 +404,16 @@
  * Write a value according to the bus width.
  */
 
-static inline void cfi_write(struct map_info *map, __u32 val, __u32 addr)
+static inline void cfi_write(struct map_info *map, cfi_word val, __u32 addr)
 {
 	if (cfi_buswidth_is_1()) {
-		map->write8(map, val, addr);
+		map_write8(map, val, addr);
 	} else if (cfi_buswidth_is_2()) {
-		map->write16(map, val, addr);
+		map_write16(map, val, addr);
 	} else if (cfi_buswidth_is_4()) {
-		map->write32(map, val, addr);
+		map_write32(map, val, addr);
+	} else if (cfi_buswidth_is_8()) {
+		map_write64(map, val, addr);
 	}
 }
 
@@ -337,9 +426,9 @@
  */
 static inline __u32 cfi_send_gen_cmd(u_char cmd, __u32 cmd_addr, __u32 base,
 				struct map_info *map, struct cfi_private *cfi,
-				int type, __u32 *prev_val)
+				int type, cfi_word *prev_val)
 {
-	__u32 val;
+	cfi_word val;
 	__u32 addr = base + cfi_build_cmd_addr(cmd_addr, CFIDEV_INTERLEAVE, type);
 
 	val = cfi_build_cmd(cmd, map, cfi);
@@ -355,11 +444,13 @@
 static inline __u8 cfi_read_query(struct map_info *map, __u32 addr)
 {
 	if (cfi_buswidth_is_1()) {
-		return map->read8(map, addr);
+		return map_read8(map, addr);
 	} else if (cfi_buswidth_is_2()) {
-		return cfi16_to_cpu(map->read16(map, addr));
+		return cfi16_to_cpu(map_read16(map, addr));
 	} else if (cfi_buswidth_is_4()) {
-		return cfi32_to_cpu(map->read32(map, addr));
+		return cfi32_to_cpu(map_read32(map, addr));
+	} else if (cfi_buswidth_is_8()) {
+		return cfi64_to_cpu(map_read64(map, addr));
 	} else {
 		return 0;
 	}
@@ -368,17 +459,17 @@
 static inline void cfi_udelay(int us)
 {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-	if (need_resched()) {
-		unsigned long t = us * HZ / 1000000;
-		if (t < 1)
-			t = 1;
+	unsigned long t = us * HZ / 1000000;
+	if (t) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(t);
+		return;
 	}
-	else
 #endif
-		udelay(us);
+	udelay(us);
+	cond_resched();
 }
+
 static inline void cfi_spin_lock(spinlock_t *mutex)
 {
 	spin_lock_bh(mutex);
@@ -388,6 +479,5 @@
 {
 	spin_unlock_bh(mutex);
 }
-
 
 #endif /* __MTD_CFI_H__ */
diff -Nru a/include/linux/mtd/cfi_endian.h b/include/linux/mtd/cfi_endian.h
--- a/include/linux/mtd/cfi_endian.h	Mon Feb  4 23:49:34 2002
+++ b/include/linux/mtd/cfi_endian.h	Wed May 28 08:01:07 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: cfi_endian.h,v 1.10 2001/06/18 11:00:46 abz Exp $
+ * $Id: cfi_endian.h,v 1.11 2002/01/30 23:20:48 awozniak Exp $
  *
  */
 
@@ -30,22 +30,28 @@
 #define cfi8_to_cpu(x) (x)
 #define cpu_to_cfi16(x) cpu_to_le16(x)
 #define cpu_to_cfi32(x) cpu_to_le32(x)
+#define cpu_to_cfi64(x) cpu_to_le64(x)
 #define cfi16_to_cpu(x) le16_to_cpu(x)
 #define cfi32_to_cpu(x) le32_to_cpu(x)
+#define cfi64_to_cpu(x) le64_to_cpu(x)
 #elif defined (CFI_BIG_ENDIAN)
 #define cpu_to_cfi8(x) (x)
 #define cfi8_to_cpu(x) (x)
 #define cpu_to_cfi16(x) cpu_to_be16(x)
 #define cpu_to_cfi32(x) cpu_to_be32(x)
+#define cpu_to_cfi64(x) cpu_to_be64(x)
 #define cfi16_to_cpu(x) be16_to_cpu(x)
 #define cfi32_to_cpu(x) be32_to_cpu(x)
+#define cfi64_to_cpu(x) be64_to_cpu(x)
 #elif defined (CFI_HOST_ENDIAN)
 #define cpu_to_cfi8(x) (x)
 #define cfi8_to_cpu(x) (x)
 #define cpu_to_cfi16(x) (x)
 #define cpu_to_cfi32(x) (x)
+#define cpu_to_cfi64(x) (x)
 #define cfi16_to_cpu(x) (x)
 #define cfi32_to_cpu(x) (x)
+#define cfi64_to_cpu(x) (x)
 #else
 #error No CFI endianness defined
 #endif
diff -Nru a/include/linux/mtd/compatmac.h b/include/linux/mtd/compatmac.h
--- a/include/linux/mtd/compatmac.h	Thu Apr  3 15:03:46 2003
+++ b/include/linux/mtd/compatmac.h	Wed May 28 08:01:07 2003
@@ -1,201 +1,10 @@
 
-/*
- * mtd/include/compatmac.h
- *
- * $Id: compatmac.h,v 1.4 2000/07/03 10:01:38 dwmw2 Exp $
- *
- * Extensions and omissions from the normal 'linux/compatmac.h'
- * files. hopefully this will end up empty as the 'real' one 
- * becomes fully-featured.
- */
-
-
-/* First, include the parts which the kernel is good enough to provide 
- * to us 
- */
-   
 #ifndef __LINUX_MTD_COMPATMAC_H__
 #define __LINUX_MTD_COMPATMAC_H__
 
-#include <linux/types.h> /* used later in this header */
-#include <linux/module.h>
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-#include <linux/vmalloc.h>
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,0,0)
-#  error "This kernel is too old: not supported by this file"
-#endif
-
-/* Modularization issues */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,18)
-#  define __USE_OLD_SYMTAB__
-#  define EXPORT_NO_SYMBOLS register_symtab(NULL);
-#  define REGISTER_SYMTAB(tab) register_symtab(tab)
-#else
-#  define REGISTER_SYMTAB(tab) /* nothing */
-#endif
-
-#ifdef __USE_OLD_SYMTAB__
-#  define __MODULE_STRING(s)         /* nothing */
-#  define MODULE_PARM(v,t)           /* nothing */
-#  define MODULE_PARM_DESC(v,t)      /* nothing */
-#  define MODULE_AUTHOR(n)           /* nothing */
-#  define MODULE_DESCRIPTION(d)      /* nothing */
-#  define MODULE_SUPPORTED_DEVICE(n) /* nothing */
-#endif
-
-/*
- * "select" changed in 2.1.23. The implementation is twin, but this
- * header is new
- */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,22)
-#  include <linux/poll.h>
-#else
-#  define __USE_OLD_SELECT__
-#endif
-
-/* Other change in the fops are solved using pseudo-types */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-#  define lseek_t      long long
-#  define lseek_off_t  long long
-#else
-#  define lseek_t      int
-#  define lseek_off_t  off_t
-#endif
-
-/* changed the prototype of read/write */
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) || defined(__alpha__)
-# define count_t unsigned long
-# define read_write_t long
-#else
-# define count_t int
-# define read_write_t int
-#endif
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,31)
-# define release_t void
-#  define release_return(x) return
-#else
-#  define release_t int
-#  define release_return(x) return (x)
-#endif
-
-#if LINUX_VERSION_CODE < 0x20300
-#define __exit
-#endif
-#if LINUX_VERSION_CODE < 0x20200
-#define __init
-#else
-#include <linux/init.h>
-#endif
-
-#if LINUX_VERSION_CODE < 0x20300
-#define init_MUTEX(x) do {*(x) = MUTEX;} while (0)
-#define RQFUNC_ARG void
-#define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0)
-#else
-#define RQFUNC_ARG request_queue_t *q
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
-#define __MOD_INC_USE_COUNT(mod)                                        \
-        (atomic_inc(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED|MOD_USED_ONCE)
-#define __MOD_DEC_USE_COUNT(mod)                                        \
-        (atomic_dec(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED)
-#endif
-
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-
-#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL
-#define init_waitqueue_head init_waitqueue
-
-static inline int try_inc_mod_count(struct module *mod)
-{
-	if (mod)
-		__MOD_INC_USE_COUNT(mod);
-	return 1;
-}
-#endif
-
-
-/* Yes, I'm aware that it's a fairly ugly hack.
-   Until the __constant_* macros appear in Linus' own kernels, this is
-   the way it has to be done.
- DW 19/1/00
- */
-
-#include <asm/byteorder.h>
-
-#ifndef __constant_cpu_to_le16
-
-#ifdef __BIG_ENDIAN
-#define __constant_cpu_to_le64(x) ___swab64((x))
-#define __constant_le64_to_cpu(x) ___swab64((x))
-#define __constant_cpu_to_le32(x) ___swab32((x))
-#define __constant_le32_to_cpu(x) ___swab32((x))
-#define __constant_cpu_to_le16(x) ___swab16((x))
-#define __constant_le16_to_cpu(x) ___swab16((x))
-#define __constant_cpu_to_be64(x) ((__u64)(x))
-#define __constant_be64_to_cpu(x) ((__u64)(x))
-#define __constant_cpu_to_be32(x) ((__u32)(x))
-#define __constant_be32_to_cpu(x) ((__u32)(x))
-#define __constant_cpu_to_be16(x) ((__u16)(x))
-#define __constant_be16_to_cpu(x) ((__u16)(x))
-#else
-#ifdef __LITTLE_ENDIAN
-#define __constant_cpu_to_le64(x) ((__u64)(x))
-#define __constant_le64_to_cpu(x) ((__u64)(x))
-#define __constant_cpu_to_le32(x) ((__u32)(x))
-#define __constant_le32_to_cpu(x) ((__u32)(x))
-#define __constant_cpu_to_le16(x) ((__u16)(x))
-#define __constant_le16_to_cpu(x) ((__u16)(x))
-#define __constant_cpu_to_be64(x) ___swab64((x))
-#define __constant_be64_to_cpu(x) ___swab64((x))
-#define __constant_cpu_to_be32(x) ___swab32((x))
-#define __constant_be32_to_cpu(x) ___swab32((x))
-#define __constant_cpu_to_be16(x) ___swab16((x))
-#define __constant_be16_to_cpu(x) ___swab16((x))
-#else
-#error No (recognised) endianness defined (unless it,s PDP)
-#endif /* __LITTLE_ENDIAN */
-#endif /* __BIG_ENDIAN */
-
-#endif /* ifndef __constant_cpu_to_le16 */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-  #define mod_init_t int  __init
-  #define mod_exit_t void  
-#else
-  #define mod_init_t static int __init
-  #define mod_exit_t static void __exit
-#endif
-
-#ifndef THIS_MODULE
-#ifdef MODULE
-#define THIS_MODULE (&__this_module)
-#else
-#define THIS_MODULE (NULL)
-#endif
-#endif
-
-#if LINUX_VERSION_CODE < 0x20300
-#include <linux/interrupt.h>
-#define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);} while(0)
-#define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();} while(0)
-#else
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#endif
+/* Nothing to see here. We write 2.5-compatible code and this
+   file makes it all OK in older kernels, but it's empty in _current_
+   kernels. Include guard just to make GCC ignore it in future inclusions
+   anyway... */
 
 #endif /* __LINUX_MTD_COMPATMAC_H__ */
-
-
diff -Nru a/include/linux/mtd/doc2000.h b/include/linux/mtd/doc2000.h
--- a/include/linux/mtd/doc2000.h	Mon Feb  4 23:49:34 2002
+++ b/include/linux/mtd/doc2000.h	Wed May 28 08:01:07 2003
@@ -2,7 +2,7 @@
 /* Linux driver for Disk-On-Chip 2000       */
 /* (c) 1999 Machine Vision Holdings, Inc.   */
 /* Author: David Woodhouse <dwmw2@mvhi.com> */
-/* $Id: doc2000.h,v 1.15 2001/09/19 00:22:15 dwmw2 Exp $ */
+/* $Id: doc2000.h,v 1.16 2003/05/23 11:29:33 dwmw2 Exp $ */
 
 #ifndef __MTD_DOC2000_H__
 #define __MTD_DOC2000_H__
@@ -38,6 +38,35 @@
 #define DoC_Mil_CDSN_IO 	0x0800
 #define DoC_2k_CDSN_IO 		0x1800
 
+#define DoC_Mplus_NOP			0x1002
+#define DoC_Mplus_AliasResolution	0x1004
+#define DoC_Mplus_DOCControl		0x1006
+#define DoC_Mplus_AccessStatus		0x1008
+#define DoC_Mplus_DeviceSelect		0x1008
+#define DoC_Mplus_Configuration		0x100a
+#define DoC_Mplus_OutputControl		0x1002
+#define DoC_Mplus_FlashControl		0x1020
+#define DoC_Mplus_FlashSelect 		0x1022
+#define DoC_Mplus_FlashCmd		0x1024
+#define DoC_Mplus_FlashAddress		0x1026
+#define DoC_Mplus_FlashData0		0x1028
+#define DoC_Mplus_FlashData1		0x1029
+#define DoC_Mplus_ReadPipeInit		0x102a
+#define DoC_Mplus_LastDataRead		0x102c
+#define DoC_Mplus_LastDataRead1		0x102d
+#define DoC_Mplus_WritePipeTerm 	0x102e
+#define DoC_Mplus_ECCSyndrome0		0x1040
+#define DoC_Mplus_ECCSyndrome1		0x1041
+#define DoC_Mplus_ECCSyndrome2		0x1042
+#define DoC_Mplus_ECCSyndrome3		0x1043
+#define DoC_Mplus_ECCSyndrome4		0x1044
+#define DoC_Mplus_ECCSyndrome5		0x1045
+#define DoC_Mplus_ECCConf 		0x1046
+#define DoC_Mplus_Toggle		0x1046
+#define DoC_Mplus_DownloadStatus	0x1074
+#define DoC_Mplus_CtrlConfirm		0x1076
+#define DoC_Mplus_Power			0x1fff
+
 /* How to access the device? 
  * On ARM, it'll be mmap'd directly with 32-bit wide accesses. 
  * On PPC, it's mmap'd and 16-bit wide.
@@ -71,13 +100,20 @@
 #define DOC_MODE_RESERVED1 	2
 #define DOC_MODE_RESERVED2 	3
 
-#define DOC_MODE_MDWREN 	4
 #define DOC_MODE_CLR_ERR 	0x80
+#define	DOC_MODE_RST_LAT	0x10
+#define	DOC_MODE_BDECT		0x08
+#define DOC_MODE_MDWREN 	0x04
 
 #define DOC_ChipID_Doc2k 	0x20
 #define DOC_ChipID_DocMil 	0x30
+#define DOC_ChipID_DocMilPlus32	0x40
+#define DOC_ChipID_DocMilPlus16	0x41
 
 #define CDSN_CTRL_FR_B 		0x80
+#define CDSN_CTRL_FR_B0		0x40
+#define CDSN_CTRL_FR_B1		0x80
+
 #define CDSN_CTRL_ECC_IO 	0x20
 #define CDSN_CTRL_FLASH_IO 	0x10
 #define CDSN_CTRL_WP 		0x08
@@ -93,6 +129,10 @@
 #define DOC_ECC_RESV 		0x02
 #define DOC_ECC_IGNORE		0x01
 
+#define DOC_FLASH_CE		0x80
+#define DOC_FLASH_WP		0x40
+#define DOC_FLASH_BANK		0x02
+
 /* We have to also set the reserved bit 1 for enable */
 #define DOC_ECC_EN (DOC_ECC__EN | DOC_ECC_RESV)
 #define DOC_ECC_DIS (DOC_ECC_RESV)
@@ -110,6 +150,9 @@
 #define MAX_FLOORS_MIL 4
 #define MAX_CHIPS_MIL 1
 
+#define MAX_FLOORS_MPLUS 1
+#define MAX_CHIPS_MPLUS 1
+
 #define ADDR_COLUMN 1
 #define ADDR_PAGE 2
 #define ADDR_COLUMN_PAGE 3
@@ -126,6 +169,7 @@
 	int chipshift;
 	char page256;
 	char pageadrlen;
+	char interleave; /* Internal interleaving - Millennium Plus style */
 	unsigned long erasesize;
 	
 	int curfloor;
diff -Nru a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h
--- a/include/linux/mtd/flashchip.h	Mon Feb  4 23:41:05 2002
+++ b/include/linux/mtd/flashchip.h	Wed May 28 08:01:07 2003
@@ -6,7 +6,7 @@
  *
  * (C) 2000 Red Hat. GPLd.
  *
- * $Id: flashchip.h,v 1.7 2001/01/18 03:52:36 nico Exp $
+ * $Id: flashchip.h,v 1.9 2003/04/30 11:15:22 dwmw2 Exp $
  *
  */
 
@@ -36,6 +36,7 @@
 	FL_UNLOADING,
 	FL_LOCKING,
 	FL_UNLOCKING,
+	FL_POINT,
 	FL_UNKNOWN
 } flstate_t;
 
@@ -54,8 +55,13 @@
 	   a given offset, and we'll want to add the per-chip length field
 	   back in.
 	*/
+	int ref_point_counter;
 	flstate_t state;
 	flstate_t oldstate;
+
+	int write_suspended:1;
+	int erase_suspended:1;
+
 	spinlock_t *mutex;
 	spinlock_t _spinlock; /* We do it like this because sometimes they'll be shared. */
 	wait_queue_head_t wq; /* Wait on here when we're waiting for the chip
diff -Nru a/include/linux/mtd/inftl.h b/include/linux/mtd/inftl.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/mtd/inftl.h	Wed May 28 08:01:27 2003
@@ -0,0 +1,129 @@
+/*
+ *	inftl.h -- defines to support the Inverse NAND Flash Translation Layer
+ *
+ *	(C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
+ *
+ *	$Id: inftl.h,v 1.3 2003/05/23 11:35:34 dwmw2 Exp $
+ */
+
+#ifndef __MTD_INFTL_H__
+#define __MTD_INFTL_H__
+
+#include <linux/mtd/blktrans.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nftl.h>
+
+#define	OSAK_VERSION	0x5120
+#define	PERCENTUSED	98
+
+#define	SECTORSIZE	512
+
+#ifndef INFTL_MAJOR
+#define INFTL_MAJOR 93 /* FIXME */
+#endif
+#define INFTL_PARTN_BITS 4
+
+/* Block Control Information */
+
+struct inftl_bci {
+	__u8 ECCsig[6];
+	__u8 Status;
+	__u8 Status1;
+} __attribute__((packed));
+
+struct inftl_unithead1 {
+	__u16 virtualUnitNo;
+	__u16 prevUnitNo;
+	__u8 ANAC;
+	__u8 NACs;
+	__u8 parityPerField;
+	__u8 discarded;
+} __attribute__((packed));
+
+struct inftl_unithead2 {
+	__u8 parityPerField;
+	__u8 ANAC;
+	__u16 prevUnitNo;
+	__u16 virtualUnitNo;
+	__u8 NACs;
+	__u8 discarded;
+} __attribute__((packed));
+
+struct inftl_unittail {
+	__u8 Reserved[4];
+	__u16 EraseMark;
+	__u16 EraseMark1;
+} __attribute__((packed));
+
+union inftl_uci {
+	struct inftl_unithead1 a;
+	struct inftl_unithead2 b;
+	struct inftl_unittail c;
+};
+
+struct inftl_oob {
+	struct inftl_bci b;
+	union inftl_uci u;
+};
+
+
+/* INFTL Media Header */
+
+struct INFTLPartition {
+	__u32 virtualUnits;
+	__u32 firstUnit;
+	__u32 lastUnit;
+	__u32 flags;
+	__u32 spareUnits;
+	__u32 Reserved0;
+	__u32 Reserved1;
+} __attribute__((packed));
+
+struct INFTLMediaHeader {
+	char bootRecordID[8];
+	__u32 NoOfBootImageBlocks;
+	__u32 NoOfBinaryPartitions;
+	__u32 NoOfBDTLPartitions;
+	__u32 BlockMultiplierBits;
+	__u32 FormatFlags;
+	__u32 OsakVersion;
+	__u32 PercentUsed;
+	struct INFTLPartition Partitions[4];
+} __attribute__((packed));
+
+/* Partition flag types */
+#define	INFTL_BINARY	0x20000000
+#define	INFTL_BDTL	0x40000000
+#define	INFTL_LAST	0x80000000
+
+
+#ifdef __KERNEL__
+
+struct INFTLrecord {
+	struct mtd_blktrans_dev mbd;
+	__u16 MediaUnit, SpareMediaUnit;
+	__u32 EraseSize;
+	struct INFTLMediaHeader MediaHdr;
+	int usecount;
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned short cylinders;
+	__u16 numvunits;
+	__u16 firstEUN;
+	__u16 lastEUN;
+	__u16 numfreeEUNs;
+	__u16 LastFreeEUN; 		/* To speed up finding a free EUN */
+	int head,sect,cyl;
+	__u16 *PUtable;	 		/* Physical Unit Table  */
+	__u16 *VUtable; 		/* Virtual Unit Table */
+        unsigned int nb_blocks;		/* number of physical blocks */
+        unsigned int nb_boot_blocks;	/* number of blocks used by the bios */
+        struct erase_info instr;
+};
+
+int INFTL_mount(struct INFTLrecord *s);
+int INFTL_formatblock(struct INFTLrecord *s, int block);
+
+#endif /* __KERNEL__ */
+
+#endif /* __MTD_INFTL_H__ */
diff -Nru a/include/linux/mtd/jedec.h b/include/linux/mtd/jedec.h
--- a/include/linux/mtd/jedec.h	Mon Feb  4 23:55:11 2002
+++ b/include/linux/mtd/jedec.h	Wed May 28 08:01:07 2003
@@ -7,14 +7,13 @@
  *
  * See the AMD flash databook for information on how to operate the interface.
  *
- * $Id: jedec.h,v 1.2 2001/11/06 14:37:36 dwmw2 Exp $
+ * $Id: jedec.h,v 1.3 2003/05/21 11:51:01 dwmw2 Exp $
  */
 
 #ifndef __LINUX_MTD_JEDEC_H__
 #define __LINUX_MTD_JEDEC_H__
 
 #include <linux/types.h>
-#include <linux/mtd/map.h>
 
 #define MAX_JEDEC_CHIPS 16
 
diff -Nru a/include/linux/mtd/map.h b/include/linux/mtd/map.h
--- a/include/linux/mtd/map.h	Sun Dec 29 19:07:35 2002
+++ b/include/linux/mtd/map.h	Wed May 28 08:01:07 2003
@@ -1,14 +1,15 @@
 
 /* Overhauled routines for dealing with different mmap regions of flash */
-/* $Id: map.h,v 1.25 2001/09/09 15:04:17 dwmw2 Exp $ */
+/* $Id: map.h,v 1.34 2003/05/28 12:42:22 dwmw2 Exp $ */
 
 #ifndef __LINUX_MTD_MAP_H__
 #define __LINUX_MTD_MAP_H__
 
 #include <linux/config.h>
 #include <linux/types.h>
-#include <linux/mtd/mtd.h>
-#include <linux/slab.h>
+#include <linux/list.h>
+#include <asm/system.h>
+#include <asm/io.h>
 
 /* The map stuff is very simple. You fill in your struct map_info with
    a handful of routines for accessing the device, making sure they handle
@@ -29,34 +30,44 @@
 struct map_info {
 	char *name;
 	unsigned long size;
+	unsigned long phys;
+#define NO_XIP (-1UL)
+
+	unsigned long virt;
+	void *cached;
+
 	int buswidth; /* in octets */
-	__u8 (*read8)(struct map_info *, unsigned long);
-	__u16 (*read16)(struct map_info *, unsigned long);
-	__u32 (*read32)(struct map_info *, unsigned long);  
+
+#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
+	u8 (*read8)(struct map_info *, unsigned long);
+	u16 (*read16)(struct map_info *, unsigned long);
+	u32 (*read32)(struct map_info *, unsigned long);  
+	u64 (*read64)(struct map_info *, unsigned long);  
 	/* If it returned a 'long' I'd call it readl.
 	 * It doesn't.
 	 * I won't.
 	 * dwmw2 */
 	
 	void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t);
-	void (*write8)(struct map_info *, __u8, unsigned long);
-	void (*write16)(struct map_info *, __u16, unsigned long);
-	void (*write32)(struct map_info *, __u32, unsigned long);
+	void (*write8)(struct map_info *, u8, unsigned long);
+	void (*write16)(struct map_info *, u16, unsigned long);
+	void (*write32)(struct map_info *, u32, unsigned long);
+	void (*write64)(struct map_info *, u64, unsigned long);
 	void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t);
 
+	/* We can perhaps put in 'point' and 'unpoint' methods, if we really
+	   want to enable XIP for non-linear mappings. Not yet though. */
+#endif
+	/* set_vpp() must handle being reentered -- enable, enable, disable 
+	   must leave it enabled. */
 	void (*set_vpp)(struct map_info *, int);
-	/* We put these two here rather than a single void *map_priv, 
-	   because we want mappers to be able to have quickly-accessible
-	   cache for the 'currently-mapped page' without the _extra_
-	   redirection that would be necessary. If you need more than
-	   two longs, turn the second into a pointer. dwmw2 */
+
 	unsigned long map_priv_1;
 	unsigned long map_priv_2;
 	void *fldrv_priv;
 	struct mtd_chip_driver *fldrv;
 };
 
-
 struct mtd_chip_driver {
 	struct mtd_info *(*probe)(struct map_info *map);
 	void (*destroy)(struct mtd_info *);
@@ -68,24 +79,94 @@
 void register_mtd_chip_driver(struct mtd_chip_driver *);
 void unregister_mtd_chip_driver(struct mtd_chip_driver *);
 
-struct mtd_info *do_map_probe(char *name, struct map_info *map);
+struct mtd_info *do_map_probe(const char *name, struct map_info *map);
+void map_destroy(struct mtd_info *mtd);
 
+#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0)
+#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0)
+
+#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
+#define map_read8(map, ofs) (map)->read8(map, ofs)
+#define map_read16(map, ofs) (map)->read16(map, ofs)
+#define map_read32(map, ofs) (map)->read32(map, ofs)
+#define map_read64(map, ofs) (map)->read64(map, ofs)
+#define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len)
+#define map_write8(map, datum, ofs) (map)->write8(map, datum, ofs)
+#define map_write16(map, datum, ofs) (map)->write16(map, datum, ofs)
+#define map_write32(map, datum, ofs) (map)->write32(map, datum, ofs)
+#define map_write64(map, datum, ofs) (map)->write64(map, datum, ofs)
+#define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len)
 
-/*
- * Destroy an MTD device which was created for a map device.
- * Make sure the MTD device is already unregistered before calling this
- */
-static inline void map_destroy(struct mtd_info *mtd)
+extern void simple_map_init(struct map_info *);
+#define map_is_linear(map) (map->phys != NO_XIP)
+
+#else
+static inline u8 map_read8(struct map_info *map, unsigned long ofs)
 {
-	struct map_info *map = mtd->priv;
+	return __raw_readb(map->virt + ofs);
+}
 
-	if (map->fldrv->destroy)
-		map->fldrv->destroy(mtd);
-	module_put(map->fldrv->module);
-	kfree(mtd);
+static inline u16 map_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->virt + ofs);
 }
 
-#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0)
-#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0)
+static inline u32 map_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->virt + ofs);
+}
+
+static inline u64 map_read64(struct map_info *map, unsigned long ofs)
+{
+#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
+	BUG();
+	return 0;
+#else
+	return __raw_readll(map->virt + ofs);
+#endif
+}
+
+static inline void map_write8(struct map_info *map, u8 datum, unsigned long ofs)
+{
+	__raw_writeb(datum, map->virt + ofs);
+	mb();
+}
+
+static inline void map_write16(struct map_info *map, u16 datum, unsigned long ofs)
+{
+	__raw_writew(datum, map->virt + ofs);
+	mb();
+}
+
+static inline void map_write32(struct map_info *map, u32 datum, unsigned long ofs)
+{
+	__raw_writel(datum, map->virt + ofs);
+	mb();
+}
+
+static inline void map_write64(struct map_info *map, u64 datum, unsigned long ofs)
+{
+#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
+	BUG();
+#else
+	__raw_writell(datum, map->virt + ofs);
+	mb();
+#endif /* CFI_B8 */
+}
+
+static inline void map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->virt + from, len);
+}
+
+static inline void map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->virt + to, from, len);
+}
+
+#define simple_map_init(map) do { } while (0)
+#define map_is_linear(map) (1)
+
+#endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */
 
 #endif /* __LINUX_MTD_MAP_H__ */
diff -Nru a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
--- a/include/linux/mtd/mtd.h	Sun May 25 23:19:25 2003
+++ b/include/linux/mtd/mtd.h	Wed May 28 08:01:07 2003
@@ -1,5 +1,5 @@
 
-/* $Id: mtd.h,v 1.33 2001/06/09 00:08:59 dwmw2 Exp $ */
+/* $Id: mtd.h,v 1.45 2003/05/20 21:56:40 dwmw2 Exp $ */
 
 #ifndef __MTD_MTD_H__
 #define __MTD_MTD_H__
@@ -9,7 +9,6 @@
 #include <linux/config.h>
 #include <linux/version.h>
 #include <linux/types.h>
-#include <linux/mtd/compatmac.h>
 #include <linux/module.h>
 #include <linux/uio.h>
 
@@ -26,7 +25,6 @@
 	unsigned char *ptr;
 };
 
-
 #define MTD_CHAR_MAJOR 90
 #define MTD_BLOCK_MAJOR 31
 #define MAX_MTD_DEVICES 16
@@ -93,16 +91,23 @@
 #define MEMUNLOCK               _IOW('M', 6, struct erase_info_user)
 #define MEMGETREGIONCOUNT	_IOR('M', 7, int)
 #define MEMGETREGIONINFO	_IOWR('M', 8, struct region_info_user)
+#define MEMSETOOBSEL		_IOW('M', 9, struct nand_oobinfo)
+
+struct nand_oobinfo {
+	int	useecc;
+	int	eccpos[6];	
+};
+
 
 #ifndef __KERNEL__
 
 typedef struct mtd_info_user mtd_info_t;
 typedef struct erase_info_user erase_info_t;
 typedef struct region_info_user region_info_t;
+typedef struct nand_oobinfo nand_oobinfo_t;
 
 	/* User-space ioctl definitions */
 
-
 #else /* __KERNEL__ */
 
 
@@ -147,11 +152,15 @@
 	u_int32_t oobsize;   // Amount of OOB data per block (e.g. 16)
 	u_int32_t ecctype;
 	u_int32_t eccsize;
+	
 
 	// Kernel-only stuff starts here.
 	char *name;
 	int index;
 
+	// oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO)
+	struct nand_oobinfo oobinfo;
+
 	/* Data for variable erase regions. If numeraseregions is zero,
 	 * it means that the whole device has erasesize as given above. 
 	 */
@@ -161,32 +170,47 @@
 	/* This really shouldn't be here. It can go away in 2.5 */
 	u_int32_t bank_size;
 
-	struct module *module;
 	int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
 
 	/* This stuff for eXecute-In-Place */
 	int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
 
 	/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
-	void (*unpoint) (struct mtd_info *mtd, u_char * addr);
+	void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len);
 
 
 	int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
 	int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
 
-	int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf);
-	int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf);
+	int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
+	int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
 
 	int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
 	int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
 
+	/* 
+	 * Methods to access the protection register area, present in some 
+	 * flash devices. The user data is one time programmable but the
+	 * factory data is read only. 
+	 */
+	int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+
+	int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+
+	/* This function is not yet implemented */
+	int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+
 	/* iovec-based read/write methods. We need these especially for NAND flash,
 	   with its limited number of write cycles per erase.
 	   NB: The 'count' parameter is the number of _vectors_, each of 
 	   which contains an (ofs, len) tuple.
 	*/
 	int (*readv) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen);
+	int (*readv_ecc) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, 
+		size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
 	int (*writev) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen);
+	int (*writev_ecc) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, 
+		size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
 
 	/* Sync */
 	void (*sync) (struct mtd_info *mtd);
@@ -200,6 +224,9 @@
 	void (*resume) (struct mtd_info *mtd);
 
 	void *priv;
+
+	struct module *owner;
+	int usecount;
 };
 
 
@@ -208,35 +235,27 @@
 extern int add_mtd_device(struct mtd_info *mtd);
 extern int del_mtd_device (struct mtd_info *mtd);
 
-extern struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num);
+extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num);
+
+extern void put_mtd_device(struct mtd_info *mtd);
 
-static inline struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
-{
-	struct mtd_info *ret;
-	
-	ret = __get_mtd_device(mtd, num);
-	if (ret && !try_module_get(ret->module))
-		return NULL;
-	return ret;
-}
-
-static inline void put_mtd_device(struct mtd_info *mtd)
-{
-	module_put(mtd->module);
-}
 
 struct mtd_notifier {
 	void (*add)(struct mtd_info *mtd);
 	void (*remove)(struct mtd_info *mtd);
-	struct mtd_notifier *next;
+	struct list_head list;
 };
 
 
 extern void register_mtd_user (struct mtd_notifier *new);
 extern int unregister_mtd_user (struct mtd_notifier *old);
 
+int default_mtd_writev(struct mtd_info *mtd, const struct iovec *vecs,
+		       unsigned long count, loff_t to, size_t *retlen);
+
+int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs,
+		      unsigned long count, loff_t from, size_t *retlen);
 
-#ifndef MTDC
 #define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args)
 #define MTD_POINT(mtd, a,b,c,d) (*(mtd->point))(mtd, a,b,c, (u_char **)(d))
 #define MTD_UNPOINT(mtd, arg) (*(mtd->unpoint))(mtd, (u_char *)arg)
@@ -249,7 +268,6 @@
 #define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args)
 #define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args)
 #define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd);  } while (0) 
-#endif /* MTDC */
 
 /*
  * Debugging macro and defines
@@ -266,7 +284,8 @@
 			printk(KERN_INFO args);		\
 	} while(0)
 #else /* CONFIG_MTD_DEBUG */
-#define DEBUG(n, args...)
+#define DEBUG(n, args...) do { } while(0)
+
 #endif /* CONFIG_MTD_DEBUG */
 
 #endif /* __KERNEL__ */
diff -Nru a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
--- a/include/linux/mtd/nand.h	Tue Feb  5 09:39:41 2002
+++ b/include/linux/mtd/nand.h	Wed May 28 08:01:07 2003
@@ -2,9 +2,10 @@
  *  linux/include/linux/mtd/nand.h
  *
  *  Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com>
- *                     Steven J. Hill <sjhill@cotw.com>
+ *                     Steven J. Hill <sjhill@realitydiluted.com>
+ *		       Thomas Gleixner <tglx@linutronix.de>
  *
- * $Id: nand.h,v 1.8 2000/10/30 17:16:17 sjhill Exp $
+ * $Id: nand.h,v 1.25 2003/05/21 15:15:02 dwmw2 Exp $
  *
  * 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
@@ -23,19 +24,51 @@
  *			bat later if I did something naughty.
  *   10-11-2000 SJH     Added private NAND flash structure for driver
  *   10-24-2000 SJH     Added prototype for 'nand_scan' function
+ *   10-29-2001 TG	changed nand_chip structure to support 
+ *			hardwarespecific function for accessing control lines
+ *   02-21-2002 TG	added support for different read/write adress and
+ *			ready/busy line access function
+ *   02-26-2002 TG	added chip_delay to nand_chip structure to optimize
+ *			command delay times for different chips
+ *   04-28-2002 TG	OOB config defines moved from nand.c to avoid duplicate
+ *			defines in jffs2/wbuf.c
+ *   08-07-2002 TG	forced bad block location to byte 5 of OOB, even if
+ *			CONFIG_MTD_NAND_ECC_JFFS2 is not set
+ *   08-10-2002 TG	extensions to nand_chip structure to support HW-ECC
+ *
+ *   08-29-2002 tglx 	nand_chip structure: data_poi for selecting 
+ *			internal / fs-driver buffer
+ *			support for 6byte/512byte hardware ECC
+ *			read_ecc, write_ecc extended for different oob-layout
+ *			oob layout selections: NAND_NONE_OOB, NAND_JFFS2_OOB,
+ *			NAND_YAFFS_OOB
+ *  11-25-2002 tglx	Added Manufacturer code FUJITSU, NATIONAL
+ *			Split manufacturer and device ID structures 
  */
 #ifndef __LINUX_MTD_NAND_H
 #define __LINUX_MTD_NAND_H
 
 #include <linux/config.h>
-#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
 
+struct mtd_info;
 /*
  * Searches for a NAND device
  */
 extern int nand_scan (struct mtd_info *mtd);
 
 /*
+ * Constants for hardware specific CLE/ALE/NCE function
+*/
+#define NAND_CTL_SETNCE 	1
+#define NAND_CTL_CLRNCE		2
+#define NAND_CTL_SETCLE		3
+#define NAND_CTL_CLRCLE		4
+#define NAND_CTL_SETALE		5
+#define NAND_CTL_CLRALE		6
+
+/*
  * Standard NAND flash commands
  */
 #define NAND_CMD_READ0		0
@@ -49,6 +82,29 @@
 #define NAND_CMD_ERASE2		0xd0
 #define NAND_CMD_RESET		0xff
 
+/* 
+ * Constants for ECC_MODES
+ *
+ * NONE:	No ECC
+ * SOFT:	Software ECC 3 byte ECC per 256 Byte data
+ * HW3_256:	Hardware ECC 3 byte ECC per 256 Byte data
+ * HW3_512:	Hardware ECC 3 byte ECC per 512 Byte data
+ *
+ *
+*/
+#define NAND_ECC_NONE		0
+#define NAND_ECC_SOFT		1
+#define NAND_ECC_HW3_256	2
+#define NAND_ECC_HW3_512	3
+#define NAND_ECC_HW6_512	4
+#define NAND_ECC_DISKONCHIP	5
+
+/*
+ * Constants for Hardware ECC
+*/
+#define NAND_ECC_READ		0
+#define NAND_ECC_WRITE		1
+	
 /*
  * Enumeration for NAND flash chip state
  */
@@ -60,20 +116,33 @@
 	FL_SYNCING
 } nand_state_t;
 
+
 /*
  * NAND Private Flash Chip Data
  *
  * Structure overview:
  *
- *  IO_ADDR - address to access the 8 I/O lines to the flash device
+ *  IO_ADDR_R - address to read the 8 I/O lines of the flash device 
+ *
+ *  IO_ADDR_W - address to write the 8 I/O lines of the flash device 
+ *
+ *  hwcontrol - hardwarespecific function for accesing control-lines
  *
- *  CTRL_ADDR - address where ALE, CLE and CE control bits are accessed
+ *  dev_ready - hardwarespecific function for accesing device ready/busy line
  *
- *  CLE - location in control word for Command Latch Enable bit
+ *  waitfunc - hardwarespecific function for wait on ready
  *
- *  ALE - location in control word for Address Latch Enable bit
+ *  calculate_ecc - function for ecc calculation or readback from ecc hardware
  *
- *  NCE - location in control word for nChip Enable bit
+ *  correct_data - function for ecc correction, matching to ecc generator (sw/hw)
+ *
+ *  enable_hwecc - function to enable (reset) hardware ecc generator
+ *
+ *  eccmod - mode of ecc: see constants
+ *
+ *  eccsize - databytes used per ecc-calculation
+ *
+ *  chip_delay - chip dependent delay for transfering data from array to read regs (tR)
  *
  *  chip_lock - spinlock used to protect access to this structure
  *
@@ -85,27 +154,30 @@
  *
  *  data_buf - data buffer passed to/from MTD user modules
  *
- *  ecc_code_buf - used only for holding calculated or read ECCs for
- *                 a page read or written when ECC is in use
+ *  data_cache - data cache for redundant page access and shadow for
+ *		 ECC failure
  *
- *  reserved - padding to make structure fall on word boundary if
- *             when ECC is in use
+ *  cache_page - number of last valid page in page_cache 
  */
 struct nand_chip {
-	unsigned long IO_ADDR;
-	unsigned long CTRL_ADDR;
-	unsigned int CLE;
-	unsigned int ALE;
-	unsigned int NCE;
-	spinlock_t chip_lock;
+	unsigned long 	IO_ADDR_R;
+	unsigned long 	IO_ADDR_W;
+	void 		(*hwcontrol)(int cmd);
+	int  		(*dev_ready)(void);
+	void 		(*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
+	int 		(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
+	void		(*calculate_ecc)(const u_char *dat, u_char *ecc_code);
+	int 		(*correct_data)(u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+	void		(*enable_hwecc)(int mode);
+	int		eccmode;
+	int		eccsize;
+	int 		chip_delay;
+	spinlock_t 	chip_lock;
 	wait_queue_head_t wq;
-	nand_state_t state;
-	int page_shift;
-	u_char *data_buf;
-#ifdef CONFIG_MTD_NAND_ECC
-	u_char ecc_code_buf[6];
-	u_char reserved[2];
-#endif
+	nand_state_t 	state;
+	int 		page_shift;
+	u_char 		*data_buf;
+	u_char		*data_poi;
 };
 
 /*
@@ -113,17 +185,17 @@
  */
 #define NAND_MFR_TOSHIBA	0x98
 #define NAND_MFR_SAMSUNG	0xec
+#define NAND_MFR_FUJITSU	0x04
+#define NAND_MFR_NATIONAL	0x8f
 
 /*
  * NAND Flash Device ID Structure
  *
  * Structure overview:
  *
- *  name - Complete name of device
- *
- *  manufacture_id - manufacturer ID code of device.
+ *  name - Identify the device type
  *
- *  model_id - model ID code of device.
+ *  id -  device ID code
  *
  *  chipshift - total number of address bits for the device which
  *              is used to calculate address offsets and the total
@@ -143,12 +215,30 @@
  */
 struct nand_flash_dev {
 	char * name;
-	int manufacture_id;
-	int model_id;
+	int id;
 	int chipshift;
-	char page256;
-	char pageadrlen;
 	unsigned long erasesize;
+	char page256;
 };
+
+/*
+ * NAND Flash Manufacturer ID Structure
+ *
+ *  name - Manufacturer name
+ *
+ *  id - manufacturer ID code of device.
+*/
+struct nand_manufacturers {
+	int id;
+	char * name;
+};
+
+extern struct nand_flash_dev nand_flash_ids[];
+extern struct nand_manufacturers nand_manuf_ids[];
+
+/*
+* Constants for oob configuration
+*/
+#define NAND_BADBLOCK_POS		5
 
 #endif /* __LINUX_MTD_NAND_H */
diff -Nru a/include/linux/mtd/nand_ecc.h b/include/linux/mtd/nand_ecc.h
--- a/include/linux/mtd/nand_ecc.h	Tue Feb  5 10:38:55 2002
+++ b/include/linux/mtd/nand_ecc.h	Wed May 28 08:01:07 2003
@@ -1,9 +1,9 @@
 /*
  *  drivers/mtd/nand_ecc.h
  *
- *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
  *
- * $Id: nand_ecc.h,v 1.1 2000/10/12 00:57:15 sjhill Exp $
+ * $Id: nand_ecc.h,v 1.2 2003/02/20 13:34:20 sjhill Exp $
  *
  * 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/include/linux/mtd/nand_ids.h b/include/linux/mtd/nand_ids.h
--- a/include/linux/mtd/nand_ids.h	Tue Feb  5 09:39:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,52 +0,0 @@
-/*
- *  linux/include/linux/mtd/nand_ids.h
- *
- *  Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com>
- *                     Steven J. Hill <sjhill@cotw.com>
- *
- * $Id: nand_ids.h,v 1.1 2000/10/13 16:16:26 mdeans Exp $
- *
- * 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.
- *
- *  Info:
- *   Contains standard defines and IDs for NAND flash devices
- *
- *  Changelog:
- *   01-31-2000 DMW     Created
- *   09-18-2000 SJH     Moved structure out of the Disk-On-Chip drivers
- *			so it can be used by other NAND flash device
- *			drivers. I also changed the copyright since none
- *			of the original contents of this file are specific
- *			to DoC devices. David can whack me with a baseball
- *			bat later if I did something naughty.
- *   10-11-2000 SJH     Added private NAND flash structure for driver
- *   2000-10-13 BE      Moved out of 'nand.h' - avoids duplication.
- */
-
-#ifndef __LINUX_MTD_NAND_IDS_H
-#define __LINUX_MTD_NAND_IDS_H
-
-static struct nand_flash_dev nand_flash_ids[] = {
-	{"Toshiba TC5816BDC",     NAND_MFR_TOSHIBA, 0x64, 21, 1, 2, 0x1000},
-	{"Toshiba TC5832DC",      NAND_MFR_TOSHIBA, 0x6b, 22, 0, 2, 0x2000},
-	{"Toshiba TH58V128DC",    NAND_MFR_TOSHIBA, 0x73, 24, 0, 2, 0x4000},
-	{"Toshiba TC58256FT/DC",  NAND_MFR_TOSHIBA, 0x75, 25, 0, 2, 0x4000},
-	{"Toshiba TH58512FT",     NAND_MFR_TOSHIBA, 0x76, 26, 0, 3, 0x4000},
-	{"Toshiba TC58V32DC",     NAND_MFR_TOSHIBA, 0xe5, 22, 0, 2, 0x2000},
-	{"Toshiba TC58V64AFT/DC", NAND_MFR_TOSHIBA, 0xe6, 23, 0, 2, 0x2000},
-	{"Toshiba TC58V16BDC",    NAND_MFR_TOSHIBA, 0xea, 21, 1, 2, 0x1000},
-	{"Samsung KM29N16000",    NAND_MFR_SAMSUNG, 0x64, 21, 1, 2, 0x1000},
-	{"Samsung unknown 4Mb",   NAND_MFR_SAMSUNG, 0x6b, 22, 0, 2, 0x2000},
-	{"Samsung KM29U128T",     NAND_MFR_SAMSUNG, 0x73, 24, 0, 2, 0x4000},
-	{"Samsung KM29U256T",     NAND_MFR_SAMSUNG, 0x75, 25, 0, 2, 0x4000},
-	{"Samsung unknown 64Mb",  NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000},
-	{"Samsung KM29W32000",    NAND_MFR_SAMSUNG, 0xe3, 22, 0, 2, 0x2000},
-	{"Samsung unknown 4Mb",   NAND_MFR_SAMSUNG, 0xe5, 22, 0, 2, 0x2000},
-	{"Samsung KM29U64000",    NAND_MFR_SAMSUNG, 0xe6, 23, 0, 2, 0x2000},
-	{"Samsung KM29W16000",    NAND_MFR_SAMSUNG, 0xea, 21, 1, 2, 0x1000},
-	{NULL,}
-};
-
-#endif /* __LINUX_MTD_NAND_IDS_H */
diff -Nru a/include/linux/mtd/nftl.h b/include/linux/mtd/nftl.h
--- a/include/linux/mtd/nftl.h	Thu Aug  8 10:37:09 2002
+++ b/include/linux/mtd/nftl.h	Wed May 28 08:01:08 2003
@@ -1,15 +1,14 @@
-
-/* Defines for NAND Flash Translation Layer  */
-/* (c) 1999 Machine Vision Holdings, Inc.    */
-/* Author: David Woodhouse <dwmw2@mvhi.com>  */
-/* $Id: nftl.h,v 1.10 2000/12/29 00:25:38 dwmw2 Exp $ */
+/*
+ * $Id: nftl.h,v 1.13 2003/05/23 11:25:02 dwmw2 Exp $
+ *
+ * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
+ */
 
 #ifndef __MTD_NFTL_H__
 #define __MTD_NFTL_H__
 
-#ifndef __BOOT__
 #include <linux/mtd/mtd.h>
-#endif
+#include <linux/mtd/blktrans.h>
 
 /* Block Control Information */
 
@@ -84,8 +83,7 @@
 #define BLOCK_RESERVED     0xfffc /* bios block or bad block */
 
 struct NFTLrecord {
-	struct mtd_info *mtd;
-	struct semaphore mutex;
+	struct mtd_blktrans_dev mbd;
 	__u16 MediaUnit, SpareMediaUnit;
 	__u32 EraseSize;
 	struct NFTLMediaHeader MediaHdr;
@@ -97,14 +95,12 @@
 	__u16 lastEUN;                  /* should be suppressed */
 	__u16 numfreeEUNs;
 	__u16 LastFreeEUN; 		/* To speed up finding a free EUN */
-	__u32 long nr_sects;
 	int head,sect,cyl;
 	__u16 *EUNtable; 		/* [numvunits]: First EUN for each virtual unit  */
 	__u16 *ReplUnitTable; 		/* [numEUNs]: ReplUnitNumber for each */
         unsigned int nb_blocks;		/* number of physical blocks */
         unsigned int nb_boot_blocks;	/* number of blocks used by the bios */
         struct erase_info instr;
-	struct gendisk *disk;
 };
 
 int NFTL_mount(struct NFTLrecord *s);
@@ -115,7 +111,7 @@
 #endif
 
 #define MAX_NFTLS 16
-#define MAX_SECTORS_PER_UNIT 32
+#define MAX_SECTORS_PER_UNIT 64
 #define NFTL_PARTN_BITS 4
 
 #endif /* __KERNEL__ */
diff -Nru a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
--- a/include/linux/mtd/partitions.h	Mon Feb  4 23:41:05 2002
+++ b/include/linux/mtd/partitions.h	Wed May 28 08:01:08 2003
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: partitions.h,v 1.6 2001/03/17 17:10:21 dwmw2 Exp $
+ * $Id: partitions.h,v 1.14 2003/05/20 21:56:29 dwmw2 Exp $
  */
 
 #ifndef MTD_PARTITIONS_H
@@ -26,29 +26,51 @@
  * 	will extend to the end of the master MTD device.
  * offset: absolute starting position within the master MTD device; if 
  * 	defined as MTDPART_OFS_APPEND, the partition will start where the 
- * 	previous one ended.
+ * 	previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block.
  * mask_flags: contains flags that have to be masked (removed) from the 
  * 	master MTD flag set for the corresponding MTD partition.
  * 	For example, to force a read-only partition, simply adding 
  * 	MTD_WRITEABLE to the mask_flags will do the trick.
  *
  * Note: writeable partitions require their size and offset be 
- * erasesize aligned.
+ * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
  */ 
 
 struct mtd_partition {
-	char *name;		/* identifier string */
-	u_int32_t size;		/* partition size */
+	char *name;			/* identifier string */
+	u_int32_t size;			/* partition size */
 	u_int32_t offset;		/* offset within the master MTD space */
-	u_int32_t mask_flags;	/* master MTD flags to mask out for this partition */
+	u_int32_t mask_flags;		/* master MTD flags to mask out for this partition */
+	struct nand_oobinfo *oobsel;	/* out of band layout for this partition (NAND only)*/
+	struct mtd_info **mtdp;		/* pointer to store the MTD object */
 };
 
+#define MTDPART_OFS_NXTBLK	(-2)
 #define MTDPART_OFS_APPEND	(-1)
 #define MTDPART_SIZ_FULL	(0)
 
 
 int add_mtd_partitions(struct mtd_info *, struct mtd_partition *, int);
 int del_mtd_partitions(struct mtd_info *);
+
+/*
+ * Functions dealing with the various ways of partitioning the space
+ */
+
+struct mtd_part_parser {
+	struct list_head list;
+	struct module *owner;
+	const char *name;
+	int (*parse_fn)(struct mtd_info *, struct mtd_partition **, unsigned long);
+};
+
+extern struct mtd_part_parser *get_partition_parser(const char *name);
+extern int register_mtd_parser(struct mtd_part_parser *parser);
+extern int deregister_mtd_parser(struct mtd_part_parser *parser);
+extern int parse_mtd_partitions(struct mtd_info *master, const char **types, 
+				struct mtd_partition **pparts, unsigned long origin);
+
+#define put_partition_parser(p) do { module_put((p)->owner); } while(0)
 
 #endif
 
diff -Nru a/include/linux/mtd/pmc551.h b/include/linux/mtd/pmc551.h
--- a/include/linux/mtd/pmc551.h	Mon Feb  4 23:49:34 2002
+++ b/include/linux/mtd/pmc551.h	Wed May 28 08:01:08 2003
@@ -1,5 +1,5 @@
 /*
- * $Id: pmc551.h,v 1.4 2001/06/12 16:19:38 major Exp $
+ * $Id: pmc551.h,v 1.5 2003/01/24 16:49:53 dwmw2 Exp $
  *
  * PMC551 PCI Mezzanine Ram Device
  *
@@ -17,7 +17,7 @@
 
 #include <linux/mtd/mtd.h>
 
-#define PMC551_VERSION "$Id: pmc551.h,v 1.4 2001/06/12 16:19:38 major Exp $\n"\
+#define PMC551_VERSION "$Id: pmc551.h,v 1.5 2003/01/24 16:49:53 dwmw2 Exp $\n"\
        "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n"
 
 /*
@@ -36,7 +36,7 @@
  * Function Prototypes
  */
 static int pmc551_erase(struct mtd_info *, struct erase_info *);
-static void pmc551_unpoint(struct mtd_info *, u_char *);
+static void pmc551_unpoint(struct mtd_info *, u_char *, loff_t, size_t);
 static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
 static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);        
diff -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h
--- a/include/linux/netdevice.h	Sun May 25 19:21:31 2003
+++ b/include/linux/netdevice.h	Thu May 29 20:14:56 2003
@@ -147,8 +147,6 @@
 
 #ifdef __KERNEL__
 
-extern const char *if_port_text[];
-
 #include <linux/cache.h>
 #include <linux/skbuff.h>
 
diff -Nru a/include/linux/pci.h b/include/linux/pci.h
--- a/include/linux/pci.h	Thu May 22 07:16:04 2003
+++ b/include/linux/pci.h	Thu May 29 22:42:44 2003
@@ -390,6 +390,11 @@
 					   or supports 64-bit transfers.  */
 	struct list_head pools;		/* pci_pools tied to this device */
 
+	u64		consistent_dma_mask;/* Like dma_mask, but for
+					       pci_alloc_consistent mappings as
+					       not all hardware supports
+					       64 bit addresses for consistent
+					       allocations such descriptors. */
 	u32             current_state;  /* Current operating state. In ACPI-speak,
 					   this is D0-D3, D0 being fully functional,
 					   and D3 being off. */
@@ -623,6 +628,7 @@
 void pci_clear_mwi(struct pci_dev *dev);
 int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
 int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask);
+int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask);
 int pci_assign_resource(struct pci_dev *dev, int i);
 
 /* Power management related routines */
diff -Nru a/include/linux/proc_fs.h b/include/linux/proc_fs.h
--- a/include/linux/proc_fs.h	Sun May 25 14:07:28 2003
+++ b/include/linux/proc_fs.h	Thu May 29 22:42:36 2003
@@ -187,6 +187,9 @@
 	get_info_t *get_info) {return NULL;}
 static inline void proc_net_remove(const char *name) {}
 
+static inline struct dentry *proc_pid_unhash(struct task_struct *p) { return NULL; }
+static inline void proc_pid_flush(struct dentry *proc_dentry) { }
+
 static inline struct proc_dir_entry *create_proc_entry(const char *name,
 	mode_t mode, struct proc_dir_entry *parent) { return NULL; }
 
@@ -211,6 +214,14 @@
 static inline void proc_tty_unregister_driver(struct tty_driver *driver) {};
 
 extern struct proc_dir_entry proc_root;
+
+static inline void kclist_add(struct kcore_list *new, void *addr, size_t size)
+{
+}
+static inline struct kcore_list * kclist_del(void *addr)
+{
+	return NULL;
+}
 
 #endif /* CONFIG_PROC_FS */
 
diff -Nru a/include/linux/raid/linear.h b/include/linux/raid/linear.h
--- a/include/linux/raid/linear.h	Wed Aug 21 16:07:28 2002
+++ b/include/linux/raid/linear.h	Mon May 26 19:01:35 2003
@@ -19,9 +19,9 @@
 struct linear_private_data
 {
 	struct linear_hash	*hash_table;
-	dev_info_t		disks[MD_SB_DISKS];
 	dev_info_t		*smallest;
 	int			nr_zones;
+	dev_info_t		disks[0];
 };
 
 
diff -Nru a/include/linux/raid/md.h b/include/linux/raid/md.h
--- a/include/linux/raid/md.h	Wed May  7 21:18:43 2003
+++ b/include/linux/raid/md.h	Mon May 26 19:01:37 2003
@@ -40,6 +40,7 @@
 #include <linux/reboot.h>
 #include <linux/vmalloc.h>
 #include <linux/blkpg.h>
+#include <linux/bio.h>
 
 /*
  * 'md_p.h' holds the 'physical' layout of RAID devices
@@ -61,21 +62,6 @@
 #define MD_MINOR_VERSION                90
 #define MD_PATCHLEVEL_VERSION           0
 
-/*
- * 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)
-{
-	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);
 extern mdk_thread_t * md_register_thread (void (*run) (mddev_t *mddev),
diff -Nru a/include/linux/raid/multipath.h b/include/linux/raid/multipath.h
--- a/include/linux/raid/multipath.h	Tue Mar 11 18:15:04 2003
+++ b/include/linux/raid/multipath.h	Mon May 26 18:58:25 2003
@@ -2,7 +2,6 @@
 #define _MULTIPATH_H
 
 #include <linux/raid/md.h>
-#include <linux/bio.h>
 
 struct multipath_info {
 	mdk_rdev_t	*rdev;
@@ -10,7 +9,7 @@
 
 struct multipath_private_data {
 	mddev_t			*mddev;
-	struct multipath_info	multipaths[MD_SB_DISKS];
+	struct multipath_info	*multipaths;
 	int			raid_disks;
 	int			working_disks;
 	spinlock_t		device_lock;
diff -Nru a/include/linux/raid/raid0.h b/include/linux/raid/raid0.h
--- a/include/linux/raid/raid0.h	Tue Oct  8 11:40:47 2002
+++ b/include/linux/raid/raid0.h	Mon May 26 18:58:28 2003
@@ -8,22 +8,19 @@
 	sector_t zone_offset;	/* Zone offset in md_dev */
 	sector_t dev_offset;	/* Zone offset in real dev */
 	sector_t size;		/* Zone size */
-	int nb_dev;			/* # of devices attached to the zone */
-	mdk_rdev_t *dev[MD_SB_DISKS]; /* Devices attached to the zone */
-};
-
-struct raid0_hash
-{
-	struct strip_zone *zone0, *zone1;
+	int nb_dev;		/* # of devices attached to the zone */
+	mdk_rdev_t **dev;	/* Devices attached to the zone */
 };
 
 struct raid0_private_data
 {
-	struct raid0_hash *hash_table; /* Dynamically allocated */
-	struct strip_zone *strip_zone; /* This one too */
+	struct strip_zone **hash_table; /* Table of indexes into strip_zone */
+	struct strip_zone *strip_zone;
+	mdk_rdev_t **devlist; /* lists of rdevs, pointed to by strip_zone->dev */
 	int nr_strip_zones;
-	struct strip_zone *smallest;
-	int nr_zones;
+
+	sector_t hash_spacing;
+	int preshift;			/* shift this before divide by hash_spacing */
 };
 
 typedef struct raid0_private_data raid0_conf_t;
diff -Nru a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h
--- a/include/linux/raid/raid1.h	Tue Mar 11 18:15:04 2003
+++ b/include/linux/raid/raid1.h	Mon May 26 19:01:34 2003
@@ -14,7 +14,7 @@
 
 struct r1_private_data_s {
 	mddev_t			*mddev;
-	mirror_info_t		mirrors[MD_SB_DISKS];
+	mirror_info_t		*mirrors;
 	int			raid_disks;
 	int			working_disks;
 	int			last_used;
@@ -67,13 +67,14 @@
 	 */
 	struct bio		*read_bio;
 	int			read_disk;
-	/*
-	 * if the IO is in WRITE direction, then multiple bios are used:
-	 */
-	struct bio		*write_bios[MD_SB_DISKS];
 
 	r1bio_t			*next_r1; /* next for retry or in free list */
 	struct list_head	retry_list;
+	/*
+	 * if the IO is in WRITE direction, then multiple bios are used.
+	 * We choose the number when they are allocated.
+	 */
+	struct bio		*write_bios[0];
 };
 
 /* bits for r1bio.state */
diff -Nru a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h
--- a/include/linux/raid/raid5.h	Tue Mar 11 18:15:04 2003
+++ b/include/linux/raid/raid5.h	Mon May 26 18:58:27 2003
@@ -3,7 +3,6 @@
 
 #include <linux/raid/md.h>
 #include <linux/raid/xor.h>
-#include <linux/bio.h>
 
 /*
  *
@@ -203,7 +202,6 @@
 struct raid5_private_data {
 	struct stripe_head	**stripe_hashtbl;
 	mddev_t			*mddev;
-	struct disk_info	disks[MD_SB_DISKS];
 	struct disk_info	*spare;
 	int			chunk_size, level, algorithm;
 	int			raid_disks, working_disks, failed_disks;
@@ -225,6 +223,7 @@
 							 * waiting for 25% to be free
 							 */        
 	spinlock_t		device_lock;
+	struct disk_info	disks[0];
 };
 
 typedef struct raid5_private_data raid5_conf_t;
diff -Nru a/include/linux/serial167.h b/include/linux/serial167.h
--- a/include/linux/serial167.h	Tue Oct  1 09:43:02 2002
+++ b/include/linux/serial167.h	Mon May 26 15:29:15 2003
@@ -43,8 +43,6 @@
 	int                     x_char; /* to be pushed out ASAP */
 	int                     x_break;
 	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
 	unsigned char 		*xmit_buf;
 	int			xmit_head;
 	int			xmit_tail;
@@ -53,7 +51,6 @@
         int                     default_timeout;
 	struct work_struct	tqueue;
 	struct termios		normal_termios;
-	struct termios		callout_termios;
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
         struct cyclades_monitor mon;
diff -Nru a/include/linux/serialP.h b/include/linux/serialP.h
--- a/include/linux/serialP.h	Sun Oct 13 03:55:56 2002
+++ b/include/linux/serialP.h	Mon May 26 15:29:28 2003
@@ -50,7 +50,6 @@
 	unsigned short	closing_wait; /* time to wait before closing */
 	struct async_icount	icount;	
 	struct termios		normal_termios;
-	struct termios		callout_termios;
 	int	io_type;
 	struct async_struct *info;
 	struct pci_dev	*dev;
@@ -80,8 +79,6 @@
 	unsigned long		last_active;
 	int			line;
 	int			blocked_open; /* # of blocked opens */
-	long			session; /* Session of opening process */
-	long			pgrp; /* pgrp of opening process */
  	struct circ_buf		xmit;
  	spinlock_t		xmit_lock;
 	u8			*iomem_base;
diff -Nru a/include/linux/stallion.h b/include/linux/stallion.h
--- a/include/linux/stallion.h	Tue Oct  1 09:43:14 2002
+++ b/include/linux/stallion.h	Mon May 26 15:29:09 2003
@@ -84,8 +84,6 @@
 	int			refcount;
 	int			openwaitcnt;
 	int			brklen;
-	long			session;
-	long			pgrp;
 	unsigned int		sigs;
 	unsigned int		rxignoremsk;
 	unsigned int		rxmarkmsk;
@@ -103,7 +101,6 @@
 	wait_queue_head_t	close_wait;
 #endif
 	struct termios		normaltermios;
-	struct termios		callouttermios;
 	struct work_struct	tqueue;
 	comstats_t		stats;
 	stlrq_t			tx;
diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h
--- a/include/linux/sysctl.h	Mon May 12 11:25:49 2003
+++ b/include/linux/sysctl.h	Thu May 29 03:12:27 2003
@@ -307,7 +307,8 @@
 	NET_IPV4_ICMP_RATEMASK=90,
 	NET_TCP_TW_REUSE=91,
 	NET_TCP_FRTO=92,
-	NET_TCP_LOW_LATENCY=93
+	NET_TCP_LOW_LATENCY=93,
+	NET_IPV4_IPFRAG_SECRET_INTERVAL=94,
 };
 
 enum {
@@ -365,7 +366,11 @@
 	NET_IPV6_NEIGH=17,
 	NET_IPV6_ROUTE=18,
 	NET_IPV6_ICMP=19,
-	NET_IPV6_BINDV6ONLY=20
+	NET_IPV6_BINDV6ONLY=20,
+	NET_IPV6_IP6FRAG_HIGH_THRESH=21,
+	NET_IPV6_IP6FRAG_LOW_THRESH=22,
+	NET_IPV6_IP6FRAG_TIME=23,
+	NET_IPV6_IP6FRAG_SECRET_INTERVAL=24
 };
 
 enum {
diff -Nru a/include/linux/wanrouter.h b/include/linux/wanrouter.h
--- a/include/linux/wanrouter.h	Thu May 15 14:42:07 2003
+++ b/include/linux/wanrouter.h	Mon May 26 19:28:24 2003
@@ -534,7 +534,8 @@
 
 
 /* Public Data */
-extern struct wan_device *router_devlist;	/* list of registered devices */
+/* list of registered devices */
+extern struct wan_device *wanrouter_router_devlist;
 
 #endif	/* __KERNEL__ */
 #endif	/* _ROUTER_H */
diff -Nru a/include/net/ipv6.h b/include/net/ipv6.h
--- a/include/net/ipv6.h	Thu May 22 18:38:15 2003
+++ b/include/net/ipv6.h	Thu May 29 03:12:27 2003
@@ -406,6 +406,14 @@
 extern int inet6_ioctl(struct socket *sock, unsigned int cmd, 
 		       unsigned long arg);
 
+/*
+ * reassembly.c
+ */
+extern int sysctl_ip6frag_high_thresh;
+extern int sysctl_ip6frag_low_thresh;
+extern int sysctl_ip6frag_time;
+extern int sysctl_ip6frag_secret_interval;
+
 #endif /* __KERNEL__ */
 #endif /* _NET_IPV6_H */
 
diff -Nru a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h
--- a/include/net/irda/ircomm_tty.h	Fri Oct 11 10:31:47 2002
+++ b/include/net/irda/ircomm_tty.h	Mon May 26 15:29:08 2003
@@ -93,7 +93,6 @@
 	void *ckey;
 
 	struct termios	  normal_termios;
-	struct termios	  callout_termios;
 
 	wait_queue_head_t open_wait;
 	wait_queue_head_t close_wait;
@@ -103,8 +102,6 @@
         unsigned short    close_delay;
         unsigned short    closing_wait; /* time to wait before closing */
 
-	long session;           /* Session of opening process */
-	long pgrp;		/* pgrp of opening process */
 	int  open_count;
 	int  blocked_open;	/* # of blocked opens */
 
diff -Nru a/include/net/sock.h b/include/net/sock.h
--- a/include/net/sock.h	Thu May 22 00:57:34 2003
+++ b/include/net/sock.h	Wed May 28 01:07:02 2003
@@ -59,17 +59,6 @@
  * the other protocols.
  */
 
-/* Sock flags */
-enum {
-	SOCK_DEAD,
-	SOCK_DONE,
-	SOCK_URGINLINE,
-	SOCK_KEEPOPEN,
-	SOCK_LINGER,
-	SOCK_DESTROY,
-	SOCK_BROADCAST,
-};
-
 /* Define this to get the sk->debug debugging facility. */
 #define SOCK_DEBUGGING
 #ifdef SOCK_DEBUGGING
@@ -248,6 +237,32 @@
 	void                    (*destruct)(struct sock *sk);
 };
 
+/* Sock flags */
+enum sock_flags {
+	SOCK_DEAD,
+	SOCK_DONE,
+	SOCK_URGINLINE,
+	SOCK_KEEPOPEN,
+	SOCK_LINGER,
+	SOCK_DESTROY,
+	SOCK_BROADCAST,
+};
+
+static inline void sock_set_flag(struct sock *sk, enum sock_flags flag)
+{
+	__set_bit(flag, &sk->flags);
+}
+
+static inline void sock_reset_flag(struct sock *sk, enum sock_flags flag)
+{
+	__clear_bit(flag, &sk->flags);
+}
+
+static inline int sock_flag(struct sock *sk, enum sock_flags flag)
+{
+	return test_bit(flag, &sk->flags);
+}
+
 /* The per-socket spinlock must be held here. */
 #define sk_add_backlog(__sk, __skb)			\
 do {	if((__sk)->backlog.tail == NULL) {		\
@@ -639,7 +654,7 @@
 static inline void sock_orphan(struct sock *sk)
 {
 	write_lock_bh(&sk->callback_lock);
-	__set_bit(SOCK_DEAD, &sk->flags);
+	sock_set_flag(sk, SOCK_DEAD);
 	sk->socket = NULL;
 	sk->sleep = NULL;
 	write_unlock_bh(&sk->callback_lock);
@@ -803,7 +818,7 @@
 	skb->dev = NULL;
 	skb_set_owner_r(skb, sk);
 	skb_queue_tail(&sk->receive_queue, skb);
-	if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (!sock_flag(sk, SOCK_DEAD))
 		sk->data_ready(sk,skb->len);
 out:
 	return err;
@@ -818,7 +833,7 @@
 		return -ENOMEM;
 	skb_set_owner_r(skb, sk);
 	skb_queue_tail(&sk->error_queue,skb);
-	if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (!sock_flag(sk, SOCK_DEAD))
 		sk->data_ready(sk,skb->len);
 	return 0;
 }
@@ -936,9 +951,9 @@
 static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool)
 {
 	if (valbool)
-		__set_bit(bit, &sk->flags);
+		sock_set_flag(sk, bit);
 	else
-		__clear_bit(bit, &sk->flags);
+		sock_reset_flag(sk, bit);
 }
 
 extern __u32 sysctl_wmem_max;
diff -Nru a/include/net/tcp.h b/include/net/tcp.h
--- a/include/net/tcp.h	Sun May 25 19:42:46 2003
+++ b/include/net/tcp.h	Thu May 29 02:52:41 2003
@@ -208,6 +208,8 @@
 #endif
 };
 
+#define tcptw_sk(__sk)	((struct tcp_tw_bucket *)(__sk))
+
 extern kmem_cache_t *tcp_timewait_cachep;
 
 static inline void tcp_tw_put(struct tcp_tw_bucket *tw)
@@ -246,7 +248,11 @@
 #endif /* __BIG_ENDIAN */
 #define TCP_IPV4_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
 	(((*((__u64 *)&(inet_sk(__sk)->daddr)))== (__cookie))	&&	\
-	 ((*((__u32 *)&(inet_sk(__sk)->dport)))== (__ports))   &&	\
+	 ((*((__u32 *)&(inet_sk(__sk)->dport)))== (__ports))	&&	\
+	 (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif))))
+#define TCP_IPV4_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
+	(((*((__u64 *)&(tcptw_sk(__sk)->daddr)))== (__cookie))	&&	\
+	 ((*((__u32 *)&(tcptw_sk(__sk)->dport)))== (__ports))	&&	\
 	 (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif))))
 #else /* 32-bit arch */
 #define TCP_V4_ADDR_COOKIE(__name, __saddr, __daddr)
@@ -255,6 +261,11 @@
 	 (inet_sk(__sk)->rcv_saddr		== (__daddr))	&&	\
 	 ((*((__u32 *)&(inet_sk(__sk)->dport)))== (__ports))	&&	\
 	 (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif))))
+#define TCP_IPV4_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
+	((tcptw_sk(__sk)->daddr			== (__saddr))	&&	\
+	 (tcptw_sk(__sk)->rcv_saddr		== (__daddr))	&&	\
+	 ((*((__u32 *)&(tcptw_sk(__sk)->dport)))== (__ports))	&&	\
+	 (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif))))
 #endif /* 64-bit arch */
 
 #define TCP_IPV6_MATCH(__sk, __saddr, __daddr, __ports, __dif)	   \
@@ -1426,7 +1437,7 @@
 
 	sk->shutdown = SHUTDOWN_MASK;
 
-	if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (!sock_flag(sk, SOCK_DEAD))
 		sk->state_change(sk);
 	else
 		tcp_destroy_sock(sk);
diff -Nru a/include/pcmcia/ds.h b/include/pcmcia/ds.h
--- a/include/pcmcia/ds.h	Sat Apr 26 09:16:27 2003
+++ b/include/pcmcia/ds.h	Sun May 18 13:57:40 2003
@@ -156,12 +156,6 @@
 int pcmcia_register_driver(struct pcmcia_driver *driver);
 void pcmcia_unregister_driver(struct pcmcia_driver *driver);
 
-/* legacy driver registration interface.  don't use in new code */
-int register_pccard_driver(dev_info_t *dev_info,
-			   dev_link_t *(*attach)(void),
-			   void (*detach)(dev_link_t *));
-int unregister_pccard_driver(dev_info_t *dev_info);
-
 /* error reporting */
 void cs_error(client_handle_t handle, int func, int ret);
 
diff -Nru a/kernel/compat.c b/kernel/compat.c
--- a/kernel/compat.c	Sun May 25 20:30:23 2003
+++ b/kernel/compat.c	Wed May 28 19:29:06 2003
@@ -368,8 +368,7 @@
 		ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
 		set_fs (old_fs);
 
-		if (!ret)
-		{
+		if (ret > 0) {
 			if (put_compat_rusage(ru, &r)) 
 				return -EFAULT;
 			if (stat_addr && put_user(status, stat_addr))
diff -Nru a/kernel/sched.c b/kernel/sched.c
--- a/kernel/sched.c	Sun May 25 17:00:00 2003
+++ b/kernel/sched.c	Tue May 27 04:05:34 2003
@@ -501,7 +501,7 @@
 			}
 			success = 1;
 		}
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	       	else
 			if (unlikely(kick) && task_running(rq, p) && (p->thread_info->cpu != smp_processor_id()))
 				smp_send_reschedule(p->thread_info->cpu);
diff -Nru a/lib/zlib_deflate/deflate.c b/lib/zlib_deflate/deflate.c
--- a/lib/zlib_deflate/deflate.c	Tue Feb  5 16:18:47 2002
+++ b/lib/zlib_deflate/deflate.c	Wed May 28 05:04:08 2003
@@ -164,11 +164,12 @@
     memset((charf *)s->head, 0, (unsigned)(s->hash_size-1)*sizeof(*s->head));
 
 /* ========================================================================= */
-int zlib_deflateInit_(strm, level, version, stream_size)
-    z_streamp strm;
-    int level;
-    const char *version;
-    int stream_size;
+int zlib_deflateInit_(
+	z_streamp strm,
+	int level,
+	const char *version,
+	int stream_size
+)
 {
     return zlib_deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS,
 			      DEF_MEM_LEVEL,
@@ -177,16 +178,16 @@
 }
 
 /* ========================================================================= */
-int zlib_deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
-		       version, stream_size)
-    z_streamp strm;
-    int  level;
-    int  method;
-    int  windowBits;
-    int  memLevel;
-    int  strategy;
-    const char *version;
-    int stream_size;
+int zlib_deflateInit2_(
+	z_streamp strm,
+	int  level,
+	int  method,
+	int  windowBits,
+	int  memLevel,
+	int  strategy,
+	const char *version,
+	int stream_size
+)
 {
     deflate_state *s;
     int noheader = 0;
diff -Nru a/lib/zlib_deflate/deftree.c b/lib/zlib_deflate/deftree.c
--- a/lib/zlib_deflate/deftree.c	Tue Feb  5 16:18:47 2002
+++ b/lib/zlib_deflate/deftree.c	Wed May 28 06:43:35 2003
@@ -176,10 +176,11 @@
 #ifdef DEBUG_ZLIB
 local void send_bits      OF((deflate_state *s, int value, int length));
 
-local void send_bits(s, value, length)
-    deflate_state *s;
-    int value;  /* value to send */
-    int length; /* number of bits */
+local void send_bits(
+	deflate_state *s,
+	int value,  /* value to send */
+	int length  /* number of bits */
+)
 {
     Tracevv((stderr," l %2d v %4x ", length, value));
     Assert(length > 0 && length <= 15, "invalid length");
@@ -369,10 +370,11 @@
  * when the heap property is re-established (each father smaller than its
  * two sons).
  */
-local void pqdownheap(s, tree, k)
-    deflate_state *s;
-    ct_data *tree;  /* the tree to restore */
-    int k;               /* node to move down */
+local void pqdownheap(
+	deflate_state *s,
+	ct_data *tree,  /* the tree to restore */
+	int k		/* node to move down */
+)
 {
     int v = s->heap[k];
     int j = k << 1;  /* left son of k */
@@ -404,9 +406,10 @@
  *     The length opt_len is updated; static_len is also updated if stree is
  *     not null.
  */
-local void gen_bitlen(s, desc)
-    deflate_state *s;
-    tree_desc *desc;    /* the tree descriptor */
+local void gen_bitlen(
+	deflate_state *s,
+	tree_desc *desc    /* the tree descriptor */
+)
 {
     ct_data *tree        = desc->dyn_tree;
     int max_code         = desc->max_code;
@@ -491,10 +494,11 @@
  * OUT assertion: the field code is set for all tree elements of non
  *     zero code length.
  */
-local void gen_codes (tree, max_code, bl_count)
-    ct_data *tree;             /* the tree to decorate */
-    int max_code;              /* largest code with non zero frequency */
-    ushf *bl_count;            /* number of codes at each bit length */
+local void gen_codes(
+	ct_data *tree,             /* the tree to decorate */
+	int max_code,              /* largest code with non zero frequency */
+	ushf *bl_count             /* number of codes at each bit length */
+)
 {
     ush next_code[MAX_BITS+1]; /* next code value for each bit length */
     ush code = 0;              /* running code value */
@@ -533,9 +537,10 @@
  *     and corresponding code. The length opt_len is updated; static_len is
  *     also updated if stree is not null. The field max_code is set.
  */
-local void build_tree(s, desc)
-    deflate_state *s;
-    tree_desc *desc; /* the tree descriptor */
+local void build_tree(
+	deflate_state *s,
+	tree_desc *desc	 /* the tree descriptor */
+)
 {
     ct_data *tree         = desc->dyn_tree;
     const ct_data *stree  = desc->stat_desc->static_tree;
@@ -620,10 +625,11 @@
  * Scan a literal or distance tree to determine the frequencies of the codes
  * in the bit length tree.
  */
-local void scan_tree (s, tree, max_code)
-    deflate_state *s;
-    ct_data *tree;   /* the tree to be scanned */
-    int max_code;    /* and its largest code of non zero frequency */
+local void scan_tree(
+	deflate_state *s,
+	ct_data *tree,   /* the tree to be scanned */
+	int max_code     /* and its largest code of non zero frequency */
+)
 {
     int n;                     /* iterates over all tree elements */
     int prevlen = -1;          /* last emitted length */
@@ -665,10 +671,11 @@
  * Send a literal or distance tree in compressed form, using the codes in
  * bl_tree.
  */
-local void send_tree (s, tree, max_code)
-    deflate_state *s;
-    ct_data *tree; /* the tree to be scanned */
-    int max_code;       /* and its largest code of non zero frequency */
+local void send_tree(
+	deflate_state *s,
+	ct_data *tree, /* the tree to be scanned */
+	int max_code   /* and its largest code of non zero frequency */
+)
 {
     int n;                     /* iterates over all tree elements */
     int prevlen = -1;          /* last emitted length */
@@ -716,8 +723,9 @@
  * Construct the Huffman tree for the bit lengths and return the index in
  * bl_order of the last bit length code to send.
  */
-local int build_bl_tree(s)
-    deflate_state *s;
+local int build_bl_tree(
+	deflate_state *s
+)
 {
     int max_blindex;  /* index of last bit length code of non zero freq */
 
@@ -751,9 +759,12 @@
  * lengths of the bit length codes, the literal tree and the distance tree.
  * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
  */
-local void send_all_trees(s, lcodes, dcodes, blcodes)
-    deflate_state *s;
-    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+local void send_all_trees(
+	deflate_state *s,
+	int lcodes,  /* number of codes for each tree */
+	int dcodes,  /* number of codes for each tree */
+	int blcodes  /* number of codes for each tree */
+)
 {
     int rank;                    /* index in bl_order */
 
@@ -780,11 +791,12 @@
 /* ===========================================================================
  * Send a stored block
  */
-void zlib_tr_stored_block(s, buf, stored_len, eof)
-    deflate_state *s;
-    charf *buf;       /* input block */
-    ulg stored_len;   /* length of input block */
-    int eof;          /* true if this is the last block for a file */
+void zlib_tr_stored_block(
+	deflate_state *s,
+	charf *buf,       /* input block */
+	ulg stored_len,   /* length of input block */
+	int eof           /* true if this is the last block for a file */
+)
 {
     send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
     s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
@@ -795,8 +807,9 @@
 
 /* Send just the `stored block' type code without any length bytes or data.
  */
-void zlib_tr_stored_type_only(s)
-    deflate_state *s;
+void zlib_tr_stored_type_only(
+	deflate_state *s
+)
 {
     send_bits(s, (STORED_BLOCK << 1), 3);
     bi_windup(s);
@@ -815,8 +828,9 @@
  * To simplify the code, we assume the worst case of last real code encoded
  * on one bit only.
  */
-void zlib_tr_align(s)
-    deflate_state *s;
+void zlib_tr_align(
+	deflate_state *s
+)
 {
     send_bits(s, STATIC_TREES<<1, 3);
     send_code(s, END_BLOCK, static_ltree);
@@ -841,11 +855,12 @@
  * trees or store, and output the encoded block to the zip file. This function
  * returns the total compressed length for the file so far.
  */
-ulg zlib_tr_flush_block(s, buf, stored_len, eof)
-    deflate_state *s;
-    charf *buf;       /* input block, or NULL if too old */
-    ulg stored_len;   /* length of input block */
-    int eof;          /* true if this is the last block for a file */
+ulg zlib_tr_flush_block(
+	deflate_state *s,
+	charf *buf,       /* input block, or NULL if too old */
+	ulg stored_len,   /* length of input block */
+	int eof           /* true if this is the last block for a file */
+)
 {
     ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
     int max_blindex = 0;  /* index of last bit length code of non zero freq */
@@ -953,10 +968,11 @@
  * Save the match info and tally the frequency counts. Return true if
  * the current block must be flushed.
  */
-int zlib_tr_tally (s, dist, lc)
-    deflate_state *s;
-    unsigned dist;  /* distance of matched string */
-    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+int zlib_tr_tally(
+	deflate_state *s,
+	unsigned dist,  /* distance of matched string */
+	unsigned lc     /* match length-MIN_MATCH or unmatched char (if dist==0) */
+)
 {
     s->d_buf[s->last_lit] = (ush)dist;
     s->l_buf[s->last_lit++] = (uch)lc;
@@ -1001,10 +1017,11 @@
 /* ===========================================================================
  * Send the block data compressed using the given Huffman trees
  */
-local void compress_block(s, ltree, dtree)
-    deflate_state *s;
-    ct_data *ltree; /* literal tree */
-    ct_data *dtree; /* distance tree */
+local void compress_block(
+	deflate_state *s,
+	ct_data *ltree, /* literal tree */
+	ct_data *dtree  /* distance tree */
+)
 {
     unsigned dist;      /* distance of matched string */
     int lc;             /* match length or unmatched char (if dist == 0) */
@@ -1054,8 +1071,9 @@
  * IN assertion: the fields freq of dyn_ltree are set and the total of all
  * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
  */
-local void set_data_type(s)
-    deflate_state *s;
+local void set_data_type(
+	deflate_state *s
+)
 {
     int n = 0;
     unsigned ascii_freq = 0;
@@ -1070,11 +1088,12 @@
  * Copy a stored block, storing first the length and its
  * one's complement if requested.
  */
-local void copy_block(s, buf, len, header)
-    deflate_state *s;
-    charf    *buf;    /* the input data */
-    unsigned len;     /* its length */
-    int      header;  /* true if block header must be written */
+local void copy_block(
+	deflate_state *s,
+	charf    *buf,    /* the input data */
+	unsigned len,     /* its length */
+	int      header   /* true if block header must be written */
+)
 {
     bi_windup(s);        /* align on byte boundary */
     s->last_eob_len = 8; /* enough lookahead for inflate */
diff -Nru a/lib/zlib_inflate/infblock.c b/lib/zlib_inflate/infblock.c
--- a/lib/zlib_inflate/infblock.c	Tue Feb  5 16:18:47 2002
+++ b/lib/zlib_inflate/infblock.c	Wed May 28 09:40:59 2003
@@ -65,10 +65,11 @@
  */
 
 
-void zlib_inflate_blocks_reset(s, z, c)
-inflate_blocks_statef *s;
-z_streamp z;
-uLongf *c;
+void zlib_inflate_blocks_reset(
+	inflate_blocks_statef *s,
+	z_streamp z,
+	uLongf *c
+)
 {
   if (c != Z_NULL)
     *c = s->check;
@@ -82,10 +83,11 @@
     z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
 }
 
-inflate_blocks_statef *zlib_inflate_blocks_new(z, c, w)
-z_streamp z;
-check_func c;
-uInt w;
+inflate_blocks_statef *zlib_inflate_blocks_new(
+	z_streamp z,
+	check_func c,
+	uInt w
+)
 {
   inflate_blocks_statef *s;
 
@@ -100,10 +102,11 @@
 }
 
 
-int zlib_inflate_blocks(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
+int zlib_inflate_blocks(
+	inflate_blocks_statef *s,
+	z_streamp z,
+	int r
+)
 {
   uInt t;               /* temporary storage */
   uLong b;              /* bit buffer */
@@ -325,19 +328,21 @@
 }
 
 
-int zlib_inflate_blocks_free(s, z)
-inflate_blocks_statef *s;
-z_streamp z;
+int zlib_inflate_blocks_free(
+	inflate_blocks_statef *s,
+	z_streamp z
+)
 {
   zlib_inflate_blocks_reset(s, z, Z_NULL);
   return Z_OK;
 }
 
 
-void zlib_inflate_set_dictionary(s, d, n)
-inflate_blocks_statef *s;
-const Bytef *d;
-uInt  n;
+void zlib_inflate_set_dictionary(
+	inflate_blocks_statef *s,
+	const Bytef *d,
+	uInt  n
+)
 {
   memcpy(s->window, d, n);
   s->read = s->write = s->window + n;
@@ -348,8 +353,9 @@
  * by Z_SYNC_FLUSH or Z_FULL_FLUSH. 
  * IN assertion: s != Z_NULL
  */
-int zlib_inflate_blocks_sync_point(s)
-inflate_blocks_statef *s;
+int zlib_inflate_blocks_sync_point(
+	inflate_blocks_statef *s
+)
 {
   return s->mode == LENS;
 }
diff -Nru a/lib/zlib_inflate/infcodes.c b/lib/zlib_inflate/infcodes.c
--- a/lib/zlib_inflate/infcodes.c	Tue Feb  5 16:18:47 2002
+++ b/lib/zlib_inflate/infcodes.c	Wed May 28 09:40:59 2003
@@ -14,11 +14,13 @@
 #define exop word.what.Exop
 #define bits word.what.Bits
 
-inflate_codes_statef *zlib_inflate_codes_new(bl, bd, tl, td, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-z_streamp z;
+inflate_codes_statef *zlib_inflate_codes_new(
+	uInt bl,
+	uInt bd,
+	inflate_huft *tl,
+	inflate_huft *td, /* need separate declaration for Borland C++ */
+	z_streamp z
+)
 {
   inflate_codes_statef *c;
 
@@ -34,10 +36,11 @@
 }
 
 
-int zlib_inflate_codes(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
+int zlib_inflate_codes(
+	inflate_blocks_statef *s,
+	z_streamp z,
+	int r
+)
 {
   uInt j;               /* temporary storage */
   inflate_huft *t;      /* temporary pointer */
@@ -197,8 +200,9 @@
 }
 
 
-void zlib_inflate_codes_free(c, z)
-inflate_codes_statef *c;
-z_streamp z;
+void zlib_inflate_codes_free(
+	inflate_codes_statef *c,
+	z_streamp z
+)
 {
 }
diff -Nru a/lib/zlib_inflate/inffast.c b/lib/zlib_inflate/inffast.c
--- a/lib/zlib_inflate/inffast.c	Tue Feb  5 16:18:47 2002
+++ b/lib/zlib_inflate/inffast.c	Wed May 28 09:40:59 2003
@@ -25,12 +25,14 @@
    at least ten.  The ten bytes are six bytes for the longest length/
    distance pair plus four bytes for overloading the bit buffer. */
 
-int zlib_inflate_fast(bl, bd, tl, td, s, z)
-uInt bl, bd;
-inflate_huft *tl;
-inflate_huft *td; /* need separate declaration for Borland C++ */
-inflate_blocks_statef *s;
-z_streamp z;
+int zlib_inflate_fast(
+	uInt bl,
+	uInt bd,
+	inflate_huft *tl,
+	inflate_huft *td, /* need separate declaration for Borland C++ */
+	inflate_blocks_statef *s,
+	z_streamp z
+)
 {
   inflate_huft *t;      /* temporary pointer */
   uInt e;               /* extra bits or operation */
diff -Nru a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c
--- a/lib/zlib_inflate/inflate.c	Mon May 13 07:40:46 2002
+++ b/lib/zlib_inflate/inflate.c	Wed May 28 09:40:59 2003
@@ -14,8 +14,9 @@
 }
 
 
-int ZEXPORT zlib_inflateReset(z)
-z_streamp z;
+int ZEXPORT zlib_inflateReset(
+	z_streamp z
+)
 {
   if (z == Z_NULL || z->state == Z_NULL || z->workspace == Z_NULL)
     return Z_STREAM_ERROR;
@@ -27,8 +28,9 @@
 }
 
 
-int ZEXPORT zlib_inflateEnd(z)
-z_streamp z;
+int ZEXPORT zlib_inflateEnd(
+	z_streamp z
+)
 {
   if (z == Z_NULL || z->state == Z_NULL || z->workspace == Z_NULL)
     return Z_STREAM_ERROR;
@@ -39,11 +41,12 @@
 }
 
 
-int ZEXPORT zlib_inflateInit2_(z, w, version, stream_size)
-z_streamp z;
-int w;
-const char *version;
-int stream_size;
+int ZEXPORT zlib_inflateInit2_(
+	z_streamp z,
+	int w,
+	const char *version,
+	int stream_size
+)
 {
   if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
       stream_size != sizeof(z_stream) || z->workspace == Z_NULL)
@@ -100,10 +103,11 @@
 }
 
 
-int ZEXPORT zlib_inflateInit_(z, version, stream_size)
-z_streamp z;
-const char *version;
-int stream_size;
+int ZEXPORT zlib_inflateInit_(
+	z_streamp z,
+	const char *version,
+	int stream_size
+)
 {
   return zlib_inflateInit2_(z, DEF_WBITS, version, stream_size);
 }
@@ -113,9 +117,10 @@
 #define NEEDBYTE {if(z->avail_in==0)goto empty;r=trv;}
 #define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
 
-int ZEXPORT zlib_inflate(z, f)
-z_streamp z;
-int f;
+int ZEXPORT zlib_inflate(
+	z_streamp z,
+	int f
+)
 {
   int r, trv;
   uInt b;
@@ -245,8 +250,9 @@
 }
 
 
-int ZEXPORT zlib_inflateSync(z)
-z_streamp z;
+int ZEXPORT zlib_inflateSync(
+	z_streamp z
+)
 {
   uInt n;       /* number of bytes to look at */
   Bytef *p;     /* pointer to bytes */
@@ -303,8 +309,9 @@
  * decompressing, PPP checks that at the end of input packet, inflate is
  * waiting for these length bytes.
  */
-int ZEXPORT zlib_inflateSyncPoint(z)
-z_streamp z;
+int ZEXPORT zlib_inflateSyncPoint(
+	z_streamp z
+)
 {
   if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL)
     return Z_STREAM_ERROR;
@@ -373,8 +380,10 @@
  * will have been updated if need be.
  */
 
-int ZEXPORT zlib_inflateIncomp(z)
-z_stream *z;
+int ZEXPORT zlib_inflateIncomp(
+	z_stream *z
+	
+)
 {
     if (z->state->mode != BLOCKS)
 	return Z_DATA_ERROR;
diff -Nru a/lib/zlib_inflate/inftrees.c b/lib/zlib_inflate/inftrees.c
--- a/lib/zlib_inflate/inftrees.c	Tue Feb  5 16:18:47 2002
+++ b/lib/zlib_inflate/inftrees.c	Wed May 28 09:40:59 2003
@@ -87,17 +87,18 @@
 /* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
 #define BMAX 15         /* maximum bit length of any code */
 
-local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
-uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
-uInt n;                 /* number of codes (assumed <= 288) */
-uInt s;                 /* number of simple-valued codes (0..s-1) */
-const uIntf *d;         /* list of base values for non-simple codes */
-const uIntf *e;         /* list of extra bits for non-simple codes */
-inflate_huft * FAR *t;  /* result: starting table */
-uIntf *m;               /* maximum lookup bits, returns actual */
-inflate_huft *hp;       /* space for trees */
-uInt *hn;               /* hufts used in space */
-uIntf *v;               /* working area: values in order of bit length */
+local int huft_build(
+	uIntf *b,               /* code lengths in bits (all assumed <= BMAX) */
+	uInt n,                 /* number of codes (assumed <= 288) */
+	uInt s,                 /* number of simple-valued codes (0..s-1) */
+	const uIntf *d,         /* list of base values for non-simple codes */
+	const uIntf *e,         /* list of extra bits for non-simple codes */
+	inflate_huft * FAR *t,  /* result: starting table */
+	uIntf *m,               /* maximum lookup bits, returns actual */
+	inflate_huft *hp,       /* space for trees */
+	uInt *hn,               /* hufts used in space */
+	uIntf *v                /* working area: values in order of bit length */
+)
 /* Given a list of code lengths and a maximum table size, make a set of
    tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
    if the given code set is incomplete (the tables are still built in this
@@ -288,12 +289,13 @@
 }
 
 
-int zlib_inflate_trees_bits(c, bb, tb, hp, z)
-uIntf *c;               /* 19 code lengths */
-uIntf *bb;              /* bits tree desired/actual depth */
-inflate_huft * FAR *tb; /* bits tree result */
-inflate_huft *hp;       /* space for trees */
-z_streamp z;            /* for messages */
+int zlib_inflate_trees_bits(
+	uIntf *c,               /* 19 code lengths */
+	uIntf *bb,              /* bits tree desired/actual depth */
+	inflate_huft * FAR *tb, /* bits tree result */
+	inflate_huft *hp,       /* space for trees */
+	z_streamp z             /* for messages */
+)
 {
   int r;
   uInt hn = 0;          /* hufts used in space */
@@ -312,16 +314,17 @@
   return r;
 }
 
-int zlib_inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
-uInt nl;                /* number of literal/length codes */
-uInt nd;                /* number of distance codes */
-uIntf *c;               /* that many (total) code lengths */
-uIntf *bl;              /* literal desired/actual bit depth */
-uIntf *bd;              /* distance desired/actual bit depth */
-inflate_huft * FAR *tl; /* literal/length tree result */
-inflate_huft * FAR *td; /* distance tree result */
-inflate_huft *hp;       /* space for trees */
-z_streamp z;            /* for messages */
+int zlib_inflate_trees_dynamic(
+	uInt nl,                /* number of literal/length codes */
+	uInt nd,                /* number of distance codes */
+	uIntf *c,               /* that many (total) code lengths */
+	uIntf *bl,              /* literal desired/actual bit depth */
+	uIntf *bd,              /* distance desired/actual bit depth */
+	inflate_huft * FAR *tl, /* literal/length tree result */
+	inflate_huft * FAR *td, /* distance tree result */
+	inflate_huft *hp,       /* space for trees */
+	z_streamp z             /* for messages */
+)
 {
   int r;
   uInt hn = 0;          /* hufts used in space */
@@ -376,12 +379,13 @@
 #include "inffixed.h"
 
 
-int zlib_inflate_trees_fixed(bl, bd, tl, td, z)
-uIntf *bl;               /* literal desired/actual bit depth */
-uIntf *bd;               /* distance desired/actual bit depth */
-inflate_huft * FAR *tl;  /* literal/length tree result */
-inflate_huft * FAR *td;  /* distance tree result */
-z_streamp z;             /* for memory allocation */
+int zlib_inflate_trees_fixed(
+	uIntf *bl,               /* literal desired/actual bit depth */
+	uIntf *bd,               /* distance desired/actual bit depth */
+	inflate_huft * FAR *tl,  /* literal/length tree result */
+	inflate_huft * FAR *td,  /* distance tree result */
+	z_streamp z              /* for memory allocation */
+)
 {
   *bl = fixed_bl;
   *bd = fixed_bd;
diff -Nru a/lib/zlib_inflate/infutil.c b/lib/zlib_inflate/infutil.c
--- a/lib/zlib_inflate/infutil.c	Tue Feb  5 16:18:47 2002
+++ b/lib/zlib_inflate/infutil.c	Wed May 28 09:40:59 2003
@@ -20,10 +20,11 @@
 
 
 /* copy as much as possible from the sliding window to the output area */
-int zlib_inflate_flush(s, z, r)
-inflate_blocks_statef *s;
-z_streamp z;
-int r;
+int zlib_inflate_flush(
+	inflate_blocks_statef *s,
+	z_streamp z,
+	int r
+)
 {
   uInt n;
   Bytef *p;
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Mon May 12 14:35:19 2003
+++ b/mm/filemap.c	Thu May 29 22:42:47 2003
@@ -1410,7 +1410,7 @@
 	}
 }
 
-static inline int
+static inline size_t
 filemap_copy_from_user(struct page *page, unsigned long offset,
 			const char __user *buf, unsigned bytes)
 {
@@ -1427,44 +1427,48 @@
 		left = __copy_from_user(kaddr + offset, buf, bytes);
 		kunmap(page);
 	}
-	return left;
+	return left ? 0 : bytes;
 }
 
-static int
+static size_t
 __filemap_copy_from_user_iovec(char *vaddr, 
 			const struct iovec *iov, size_t base, size_t bytes)
 {
-	int left = 0;
+	size_t copied = 0;
 
 	while (bytes) {
 		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)))
+		if (__copy_from_user(vaddr, buf, copy))
 			break;
+		copied += copy;
 		bytes -= copy;
 		vaddr += copy;
 		iov++;
 	}
-	return left;
+	return copied;
 }
 
-static inline int
+static inline size_t
 filemap_copy_from_user_iovec(struct page *page, unsigned long offset,
 			const struct iovec *iov, size_t base, size_t bytes)
 {
 	char *kaddr;
-	int left;
+	size_t copied;
 
 	kaddr = kmap_atomic(page, KM_USER0);
-	left = __filemap_copy_from_user_iovec(kaddr + offset, iov, base, bytes);
+	copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
+						base, bytes);
 	kunmap_atomic(kaddr, KM_USER0);
-	if (left != 0) {
+	if (copied != bytes) {
 		kaddr = kmap(page);
-		left = __filemap_copy_from_user_iovec(kaddr + offset, iov, base, bytes);
+		copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
+							base, bytes);
 		kunmap(page);
 	}
-	return left;
+	return copied;
 }
 
 static inline void
@@ -1475,6 +1479,7 @@
 
 	while (bytes) {
 		int copy = min(bytes, iov->iov_len - base);
+
 		bytes -= copy;
 		base += copy;
 		if (iov->iov_len == base) {
@@ -1672,7 +1677,7 @@
 	do {
 		unsigned long index;
 		unsigned long offset;
-		long page_fault;
+		size_t copied;
 
 		offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
 		index = pos >> PAGE_CACHE_SHIFT;
@@ -1707,18 +1712,18 @@
 			break;
 		}
 		if (likely(nr_segs == 1))
-			page_fault = filemap_copy_from_user(page, offset,
+			copied = filemap_copy_from_user(page, offset,
 							buf, bytes);
 		else
-			page_fault = filemap_copy_from_user_iovec(page, offset,
+			copied = filemap_copy_from_user_iovec(page, offset,
 						cur_iov, iov_base, bytes);
 		flush_dcache_page(page);
-		status = a_ops->commit_write(file, page, offset, offset+bytes);
-		if (unlikely(page_fault)) {
-			status = -EFAULT;
-		} else {
+		if (likely(copied > 0)) {
+			status = a_ops->commit_write(file, page, offset,
+						     offset + copied);
+
 			if (!status)
-				status = bytes;
+				status = copied;
 
 			if (status >= 0) {
 				written += status;
@@ -1730,6 +1735,10 @@
 							&iov_base, status);
 			}
 		}
+		if (unlikely(copied != bytes))
+			if (status >= 0)
+				status = -EFAULT;
+
 		if (!PageReferenced(page))
 			SetPageReferenced(page);
 		unlock_page(page);
diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c
--- a/mm/page-writeback.c	Fri May  9 02:51:01 2003
+++ b/mm/page-writeback.c	Thu May 29 22:42:40 2003
@@ -430,11 +430,12 @@
 	int ret = 0;
 	struct writeback_control wbc = {
 		.sync_mode = WB_SYNC_ALL,
+		.nr_to_write = 1,
 	};
 
 	BUG_ON(!PageLocked(page));
 
-	if (wait && PageWriteback(page))
+	if (wait)
 		wait_on_page_writeback(page);
 
 	spin_lock(&mapping->page_lock);
diff -Nru a/net/appletalk/ddp.c b/net/appletalk/ddp.c
--- a/net/appletalk/ddp.c	Mon May 19 23:22:52 2003
+++ b/net/appletalk/ddp.c	Wed May 28 01:07:02 2003
@@ -192,7 +192,7 @@
 	struct sock *sk = (struct sock *)data;
 
 	if (!atomic_read(&sk->wmem_alloc) &&
-	    !atomic_read(&sk->rmem_alloc) && test_bit(SOCK_DEAD, &sk->flags))
+	    !atomic_read(&sk->rmem_alloc) && sock_flag(sk, SOCK_DEAD))
 		sock_put(sk);
 	else {
 		sk->timer.expires = jiffies + SOCK_DESTROY_TIME;
@@ -206,7 +206,7 @@
 	skb_queue_purge(&sk->receive_queue);
 
 	if (!atomic_read(&sk->wmem_alloc) &&
-	    !atomic_read(&sk->rmem_alloc) && test_bit(SOCK_DEAD, &sk->flags))
+	    !atomic_read(&sk->rmem_alloc) && sock_flag(sk, SOCK_DEAD))
 		sock_put(sk);
 	else {
 		init_timer(&sk->timer);
@@ -1006,9 +1006,10 @@
 	struct sock *sk = sock->sk;
 
 	if (sk) {
-		if (!test_bit(SOCK_DEAD, &sk->flags))
+		if (!sock_flag(sk, SOCK_DEAD)) {
 			sk->state_change(sk);
-		__set_bit(SOCK_DEAD, &sk->flags);
+			sock_set_flag(sk, SOCK_DEAD);
+		}
 		sock->sk = NULL;
 		atalk_destroy_socket(sk);
 	}
@@ -1149,7 +1150,7 @@
 		return -EAFNOSUPPORT;
 
 	if (addr->sat_addr.s_node == ATADDR_BCAST &&
-			!test_bit(SOCK_BROADCAST, &sk->flags)) {
+	    !sock_flag(sk, SOCK_BROADCAST)) {
 #if 1	
 		printk(KERN_WARNING "%s is broken and did not set "
 				    "SO_BROADCAST. It will break when 2.2 is "
@@ -1515,7 +1516,7 @@
 
 		/* netatalk doesn't implement this check */
 		if (usat->sat_addr.s_node == ATADDR_BCAST &&
-				!test_bit(SOCK_BROADCAST, &sk->flags)) {
+		    !sock_flag(sk, SOCK_BROADCAST)) {
 			printk(KERN_INFO "SO_BROADCAST: Fix your netatalk as "
 					 "it will break before 2.2\n");
 #if 0
diff -Nru a/net/atm/common.c b/net/atm/common.c
--- a/net/atm/common.c	Sun May 18 18:17:23 2003
+++ b/net/atm/common.c	Thu May 29 03:07:18 2003
@@ -32,21 +32,61 @@
 #include <linux/atmlec.h>
 #include "lec.h"
 #include "lec_arpc.h"
-struct atm_lane_ops atm_lane_ops;
-#endif
-#ifdef CONFIG_ATM_LANE_MODULE
+struct atm_lane_ops *atm_lane_ops;
+static DECLARE_MUTEX(atm_lane_ops_mutex);
+
+void atm_lane_ops_set(struct atm_lane_ops *hook)
+{
+	down(&atm_lane_ops_mutex);
+	atm_lane_ops = hook;
+	up(&atm_lane_ops_mutex);
+}
+
+int try_atm_lane_ops(void)
+{
+	down(&atm_lane_ops_mutex);
+	if (atm_lane_ops && try_module_get(atm_lane_ops->owner)) {
+		up(&atm_lane_ops_mutex);
+		return 1;
+	}
+	up(&atm_lane_ops_mutex);
+	return 0;
+}
+
+#if defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_ATM_MPOA_MODULE)
 EXPORT_SYMBOL(atm_lane_ops);
+EXPORT_SYMBOL(try_atm_lane_ops);
+EXPORT_SYMBOL(atm_lane_ops_set);
+#endif
 #endif
 
 #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
 #include <linux/atmmpc.h>
 #include "mpc.h"
-struct atm_mpoa_ops atm_mpoa_ops;
-#endif
+struct atm_mpoa_ops *atm_mpoa_ops;
+static DECLARE_MUTEX(atm_mpoa_ops_mutex);
+
+void atm_mpoa_ops_set(struct atm_mpoa_ops *hook)
+{
+	down(&atm_mpoa_ops_mutex);
+	atm_mpoa_ops = hook;
+	up(&atm_mpoa_ops_mutex);
+}
+
+int try_atm_mpoa_ops(void)
+{
+	down(&atm_mpoa_ops_mutex);
+	if (atm_mpoa_ops && try_module_get(atm_mpoa_ops->owner)) {
+		up(&atm_mpoa_ops_mutex);
+		return 1;
+	}
+	up(&atm_mpoa_ops_mutex);
+	return 0;
+}
 #ifdef CONFIG_ATM_MPOA_MODULE
 EXPORT_SYMBOL(atm_mpoa_ops);
-#ifndef CONFIG_ATM_LANE_MODULE
-EXPORT_SYMBOL(atm_lane_ops);
+EXPORT_SYMBOL(try_atm_mpoa_ops);
+EXPORT_SYMBOL(atm_mpoa_ops_set);
 #endif
 #endif
 
@@ -728,27 +768,40 @@
 				ret_val = -EPERM;
 				goto done;
 			}
-                        if (atm_lane_ops.lecd_attach == NULL)
-				atm_lane_init();
-                        if (atm_lane_ops.lecd_attach == NULL) { /* try again */
+#if defined(CONFIG_ATM_LANE_MODULE)
+                        if (!atm_lane_ops)
+				request_module("lec");
+#endif
+			if (try_atm_lane_ops()) {
+				error = atm_lane_ops->lecd_attach(vcc, (int) arg);
+				module_put(atm_lane_ops->owner);
+				if (error >= 0)
+					sock->state = SS_CONNECTED;
+				ret_val =  error;
+			} else
 				ret_val = -ENOSYS;
-				goto done;
-			}
-			error = atm_lane_ops.lecd_attach(vcc, (int)arg);
-			if (error >= 0) sock->state = SS_CONNECTED;
-			ret_val =  error;
 			goto done;
                 case ATMLEC_MCAST:
-			if (!capable(CAP_NET_ADMIN))
+			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
-			else
-				ret_val = atm_lane_ops.mcast_attach(vcc, (int)arg);
+				goto done;
+			}
+			if (try_atm_lane_ops()) {
+				ret_val = atm_lane_ops->mcast_attach(vcc, (int) arg);
+				module_put(atm_lane_ops->owner);
+			} else
+				ret_val = -ENOSYS;
 			goto done;
                 case ATMLEC_DATA:
-			if (!capable(CAP_NET_ADMIN))
+			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
-			else
-				ret_val = atm_lane_ops.vcc_attach(vcc, (void*)arg);
+				goto done;
+			}
+			if (try_atm_lane_ops()) {
+				ret_val = atm_lane_ops->vcc_attach(vcc, (void *) arg);
+				module_put(atm_lane_ops->owner);
+			} else
+				ret_val = -ENOSYS;
 			goto done;
 #endif
 #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
@@ -757,21 +810,29 @@
 				ret_val = -EPERM;
 				goto done;
 			}
-			if (atm_mpoa_ops.mpoad_attach == NULL)
-                                atm_mpoa_init();
-			if (atm_mpoa_ops.mpoad_attach == NULL) { /* try again */
+#if defined(CONFIG_ATM_MPOA_MODULE)
+			if (!atm_mpoa_ops)
+                                request_module("mpoa");
+#endif
+			if (try_atm_mpoa_ops()) {
+				error = atm_mpoa_ops->mpoad_attach(vcc, (int) arg);
+				module_put(atm_mpoa_ops->owner);
+				if (error >= 0)
+					sock->state = SS_CONNECTED;
+				ret_val = error;
+			} else
 				ret_val = -ENOSYS;
-				goto done;
-			}
-			error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
-			if (error >= 0) sock->state = SS_CONNECTED;
-			ret_val = error;
 			goto done;
 		case ATMMPC_DATA:
-			if (!capable(CAP_NET_ADMIN)) 
+			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
-			else
-				ret_val = atm_mpoa_ops.vcc_attach(vcc, arg);
+				goto done;
+			}
+			if (try_atm_mpoa_ops()) {
+				ret_val = atm_mpoa_ops->vcc_attach(vcc, arg);
+				module_put(atm_mpoa_ops->owner);
+			} else
+				ret_val = -ENOSYS;
 			goto done;
 #endif
 #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE)
@@ -1155,40 +1216,6 @@
 }
 
 
-/*
- * lane_mpoa_init.c: A couple of helper functions
- * to make modular LANE and MPOA client easier to implement
- */
-
-/*
- * This is how it goes:
- *
- * if xxxx is not compiled as module, call atm_xxxx_init_ops()
- *    from here
- * else call atm_mpoa_init_ops() from init_module() within
- *    the kernel when xxxx module is loaded
- *
- * In either case function pointers in struct atm_xxxx_ops
- * are initialized to their correct values. Either they
- * point to functions in the module or in the kernel
- */
- 
-extern struct atm_mpoa_ops atm_mpoa_ops; /* in common.c */
-extern struct atm_lane_ops atm_lane_ops; /* in common.c */
-
-#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
-void atm_mpoa_init(void)
-{
-#ifndef CONFIG_ATM_MPOA_MODULE /* not module */
-        atm_mpoa_init_ops(&atm_mpoa_ops);
-#else
-	request_module("mpoa");
-#endif
-
-        return;
-}
-#endif
-
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
@@ -1199,18 +1226,8 @@
 EXPORT_SYMBOL(br_fdb_put_hook);
 #endif /* defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE) */
 #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
+#endif /* defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) */
 
-void atm_lane_init(void)
-{
-#ifndef CONFIG_ATM_LANE_MODULE /* not module */
-        atm_lane_init_ops(&atm_lane_ops);
-#else
-	request_module("lec");
-#endif
-
-        return;
-}        
-#endif
 
 static int __init atm_init(void)
 {
diff -Nru a/net/atm/lec.c b/net/atm/lec.c
--- a/net/atm/lec.c	Thu May 15 17:20:17 2003
+++ b/net/atm/lec.c	Thu May 29 03:07:18 2003
@@ -56,8 +56,6 @@
 #define DPRINTK(format,args...)
 #endif
 
-static spinlock_t lec_arp_spinlock = SPIN_LOCK_UNLOCKED;
-
 #define DUMP_PACKETS 0 /* 0 = None,
                         * 1 = 30 first bytes
                         * 2 = Whole packet
@@ -71,9 +69,9 @@
 static int lec_close(struct net_device *dev);
 static struct net_device_stats *lec_get_stats(struct net_device *dev);
 static void lec_init(struct net_device *dev);
-static __inline__ struct lec_arp_table* lec_arp_find(struct lec_priv *priv,
+static inline struct lec_arp_table* lec_arp_find(struct lec_priv *priv,
                                                      unsigned char *mac_addr);
-static __inline__ int lec_arp_remove(struct lec_arp_table **lec_arp_tables,
+static inline int lec_arp_remove(struct lec_priv *priv,
 				     struct lec_arp_table *to_remove);
 /* LANE2 functions */
 static void lane2_associate_ind (struct net_device *dev, u8 *mac_address,
@@ -95,8 +93,18 @@
 static struct net_device *dev_lec[MAX_LEC_ITF];
 
 /* This will be called from proc.c via function pointer */
-struct net_device **get_dev_lec (void) {
-        return &dev_lec[0];
+struct net_device *get_dev_lec(int itf)
+{
+	struct net_device *dev;
+
+	if (itf >= MAX_LEC_ITF)
+		return NULL;
+	rtnl_lock();
+	dev = dev_lec[itf];
+	if (dev)
+		dev_hold(dev);
+	rtnl_unlock();
+	return dev;
 }
 
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
@@ -426,7 +434,7 @@
                 break;
         case l_narp_req: /* LANE2: see 7.1.35 in the lane2 spec */
                 entry = lec_arp_find(priv, mesg->content.normal.mac_addr);
-                lec_arp_remove(priv->lec_arp_tables, entry);
+                lec_arp_remove(priv, entry);
 
                 if (mesg->content.normal.no_source_le_narp)
                         break;
@@ -542,7 +550,7 @@
         }
   
 	printk("%s: Shut down!\n", dev->name);
-        MOD_DEC_USE_COUNT;
+        module_put(THIS_MODULE);
 }
 
 static struct atmdev_ops lecdev_ops = {
@@ -823,41 +831,32 @@
         if (dev_lec[i]->flags & IFF_UP) {
                 netif_start_queue(dev_lec[i]);
         }
-        MOD_INC_USE_COUNT;
+        __module_get(THIS_MODULE);
         return i;
 }
 
-void atm_lane_init_ops(struct atm_lane_ops *ops)
+static struct atm_lane_ops __atm_lane_ops = 
 {
-        ops->lecd_attach = lecd_attach;
-        ops->mcast_attach = lec_mcast_attach;
-        ops->vcc_attach = lec_vcc_attach;
-        ops->get_lecs = get_dev_lec;
-
-        printk("lec.c: " __DATE__ " " __TIME__ " initialized\n");
-
-	return;
-}
+	.lecd_attach =	lecd_attach,
+	.mcast_attach =	lec_mcast_attach,
+	.vcc_attach = 	lec_vcc_attach,
+	.get_lec = 	get_dev_lec,
+	.owner = 	THIS_MODULE
+};
 
 static int __init lane_module_init(void)
 {
-        extern struct atm_lane_ops atm_lane_ops;
-
-        atm_lane_init_ops(&atm_lane_ops);
-
+        atm_lane_ops_set(&__atm_lane_ops);
+        printk("lec.c: " __DATE__ " " __TIME__ " initialized\n");
         return 0;
 }
 
 static void __exit lane_module_cleanup(void)
 {
         int i;
-        extern struct atm_lane_ops atm_lane_ops;
         struct lec_priv *priv;
 
-        atm_lane_ops.lecd_attach = NULL;
-        atm_lane_ops.mcast_attach = NULL;
-        atm_lane_ops.vcc_attach = NULL;
-        atm_lane_ops.get_lecs = NULL;
+        atm_lane_ops_set(NULL);
 
         for (i = 0; i < MAX_LEC_ITF; i++) {
                 if (dev_lec[i] != NULL) {
@@ -867,7 +866,7 @@
                         	unregister_trdev(dev_lec[i]);
                 	else
 #endif
-                        unregister_netdev(dev_lec[i]);
+				unregister_netdev(dev_lec[i]);
                         kfree(dev_lec[i]);
                         dev_lec[i] = NULL;
                 }
@@ -1067,6 +1066,7 @@
         for (i=0;i<LEC_ARP_TABLE_SIZE;i++) {
                 priv->lec_arp_tables[i] = NULL;
         }        
+	spin_lock_init(&priv->lec_arp_lock);
         init_timer(&priv->lec_arp_timer);
         priv->lec_arp_timer.expires = jiffies+LEC_ARP_REFRESH_INTERVAL;
         priv->lec_arp_timer.data = (unsigned long)priv;
@@ -1103,21 +1103,20 @@
  * Insert entry to lec_arp_table
  * LANE2: Add to the end of the list to satisfy 8.1.13
  */
-static __inline__ void 
-lec_arp_add(struct lec_arp_table **lec_arp_tables, 
-            struct lec_arp_table *to_add)
+static inline void 
+lec_arp_add(struct lec_priv *priv, struct lec_arp_table *to_add)
 {
         unsigned long flags;
         unsigned short place;
         struct lec_arp_table *tmp;
 
-        spin_lock_irqsave(&lec_arp_spinlock, flags);
+        spin_lock_irqsave(&priv->lec_arp_lock, flags);
 
         place = HASH(to_add->mac_addr[ETH_ALEN-1]);
-        tmp = lec_arp_tables[place];
+        tmp = priv->lec_arp_tables[place];
         to_add->next = NULL;
         if (tmp == NULL)
-                lec_arp_tables[place] = to_add;
+                priv->lec_arp_tables[place] = to_add;
   
         else {  /* add to the end */
                 while (tmp->next)
@@ -1125,7 +1124,7 @@
                 tmp->next = to_add;
         }
 
-        spin_unlock_irqrestore(&lec_arp_spinlock, flags);
+        spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
 
         DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
                 0xff&to_add->mac_addr[0], 0xff&to_add->mac_addr[1],
@@ -1136,8 +1135,8 @@
 /*
  * Remove entry from lec_arp_table
  */
-static __inline__ int 
-lec_arp_remove(struct lec_arp_table **lec_arp_tables,
+static inline int 
+lec_arp_remove(struct lec_priv *priv,
                struct lec_arp_table *to_remove)
 {
         unsigned long flags;
@@ -1145,22 +1144,22 @@
         struct lec_arp_table *tmp;
         int remove_vcc=1;
 
-        spin_lock_irqsave(&lec_arp_spinlock, flags);
+        spin_lock_irqsave(&priv->lec_arp_lock, flags);
 
         if (!to_remove) {
-                spin_unlock_irqrestore(&lec_arp_spinlock, flags);
+                spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
                 return -1;
         }
         place = HASH(to_remove->mac_addr[ETH_ALEN-1]);
-        tmp = lec_arp_tables[place];
+        tmp = priv->lec_arp_tables[place];
         if (tmp == to_remove) {
-                lec_arp_tables[place] = tmp->next;
+                priv->lec_arp_tables[place] = tmp->next;
         } else {
                 while(tmp && tmp->next != to_remove) {
                         tmp = tmp->next;
                 }
                 if (!tmp) {/* Entry was not found */
-                        spin_unlock_irqrestore(&lec_arp_spinlock, flags);
+                        spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
                         return -1;
                 }
         }
@@ -1174,7 +1173,7 @@
                  * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT
                  */
                 for(place=0;place<LEC_ARP_TABLE_SIZE;place++) {
-                        for(tmp=lec_arp_tables[place];tmp!=NULL;tmp=tmp->next){
+                        for(tmp = priv->lec_arp_tables[place]; tmp != NULL; tmp = tmp->next) {
                                 if (memcmp(tmp->atm_addr, to_remove->atm_addr,
                                            ATM_ESA_LEN)==0) {
                                         remove_vcc=0;
@@ -1187,7 +1186,7 @@
         }
         skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */
 
-        spin_unlock_irqrestore(&lec_arp_spinlock, flags);
+        spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
 
         DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
                 0xff&to_remove->mac_addr[0], 0xff&to_remove->mac_addr[1],
@@ -1383,7 +1382,7 @@
         for (i=0;i<LEC_ARP_TABLE_SIZE;i++) {
                 for(entry =priv->lec_arp_tables[i];entry != NULL; entry=next) {
                         next = entry->next;
-                        lec_arp_remove(priv->lec_arp_tables, entry);
+                        lec_arp_remove(priv, entry);
                         kfree(entry);
                 }
         }
@@ -1423,7 +1422,7 @@
 /* 
  * Find entry by mac_address
  */
-static __inline__ struct lec_arp_table*
+static inline struct lec_arp_table*
 lec_arp_find(struct lec_priv *priv,
              unsigned char *mac_addr)
 {
@@ -1561,8 +1560,6 @@
 lec_arp_check_expire(unsigned long data)
 {
         struct lec_priv *priv = (struct lec_priv *)data;
-        struct lec_arp_table **lec_arp_tables =
-                (struct lec_arp_table **)priv->lec_arp_tables;
         struct lec_arp_table *entry, *next;
         unsigned long now;
         unsigned long time_to_check;
@@ -1578,7 +1575,7 @@
                 lec_arp_get(priv);
                 now = jiffies;
                 for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
-                        for(entry = lec_arp_tables[i];entry != NULL;) {
+                        for(entry = priv->lec_arp_tables[i]; entry != NULL; ) {
                                 if ((entry->flags) & LEC_REMOTE_FLAG && 
                                     priv->topology_change)
                                         time_to_check=priv->forward_delay_time;
@@ -1594,7 +1591,7 @@
                                         /* Remove entry */
                                         DPRINTK("LEC:Entry timed out\n");
                                         next = entry->next;      
-                                        lec_arp_remove(lec_arp_tables, entry);
+                                        lec_arp_remove(priv, entry);
                                         kfree(entry);
                                         entry = next;
                                 } else {
@@ -1687,7 +1684,7 @@
                 if (!entry) {
                         return priv->mcast_vcc;
                 }
-                lec_arp_add(priv->lec_arp_tables, entry);
+                lec_arp_add(priv, entry);
                 /* We want arp-request(s) to be sent */
                 entry->packets_flooded =1;
                 entry->status = ESI_ARP_PENDING;
@@ -1720,7 +1717,7 @@
                         if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)
                             && (permanent || 
                                 !(entry->flags & LEC_PERMANENT_FLAG))) {
-                                lec_arp_remove(priv->lec_arp_tables, entry);
+                                lec_arp_remove(priv, entry);
                                 kfree(entry);
                         }
                         lec_arp_put(priv);
@@ -1786,7 +1783,7 @@
                                 entry->status = ESI_FORWARD_DIRECT;
                                 memcpy(entry->mac_addr, mac_addr, ETH_ALEN);
                                 entry->last_used = jiffies;
-                                lec_arp_add(priv->lec_arp_tables, entry);
+                                lec_arp_add(priv, entry);
                         }
                         if (remoteflag)
                                 entry->flags|=LEC_REMOTE_FLAG;
@@ -1806,7 +1803,7 @@
                         return;
                 }
                 entry->status = ESI_UNKNOWN;
-                lec_arp_add(priv->lec_arp_tables, entry);
+                lec_arp_add(priv, entry);
                 /* Temporary, changes before end of function */
         }
         memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
@@ -2057,7 +2054,7 @@
         to_add->old_push = vcc->push;
         vcc->push = lec_push;
         priv->mcast_vcc = vcc;
-        lec_arp_add(priv->lec_arp_tables, to_add);
+        lec_arp_add(priv, to_add);
         lec_arp_put(priv);
         return 0;
 }
@@ -2075,7 +2072,7 @@
                 for(entry = priv->lec_arp_tables[i];entry; entry=next) {
                         next = entry->next;
                         if (vcc == entry->vcc) {
-                                lec_arp_remove(priv->lec_arp_tables,entry);
+                                lec_arp_remove(priv, entry);
                                 kfree(entry);
                                 if (priv->mcast_vcc == vcc) {
                                         priv->mcast_vcc = NULL;
@@ -2155,23 +2152,23 @@
         lec_arp_get(priv);
         entry = priv->lec_arp_empty_ones;
         if (vcc == entry->vcc) {
-		spin_lock_irqsave(&lec_arp_spinlock, flags);
+		spin_lock_irqsave(&priv->lec_arp_lock, flags);
                 del_timer(&entry->timer);
                 memcpy(entry->mac_addr, src, ETH_ALEN);
                 entry->status = ESI_FORWARD_DIRECT;
                 entry->last_used = jiffies;
                 priv->lec_arp_empty_ones = entry->next;
-                spin_unlock_irqrestore(&lec_arp_spinlock, flags);
+                spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
                 /* We might have got an entry */
                 if ((prev=lec_arp_find(priv,src))) {
-                        lec_arp_remove(priv->lec_arp_tables, prev);
+                        lec_arp_remove(priv, prev);
                         kfree(prev);
                 }
-                lec_arp_add(priv->lec_arp_tables, entry);
+                lec_arp_add(priv, entry);
                 lec_arp_put(priv);
                 return;
         }
-        spin_lock_irqsave(&lec_arp_spinlock, flags);
+        spin_lock_irqsave(&priv->lec_arp_lock, flags);
         prev = entry;
         entry = entry->next;
         while (entry && entry->vcc != vcc) {
@@ -2181,7 +2178,7 @@
         if (!entry) {
                 DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n");
                 lec_arp_put(priv);
-                spin_unlock_irqrestore(&lec_arp_spinlock, flags);
+                spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
                 return;
         }
         del_timer(&entry->timer);
@@ -2189,12 +2186,12 @@
         entry->status = ESI_FORWARD_DIRECT;
         entry->last_used = jiffies;
         prev->next = entry->next;
-        spin_unlock_irqrestore(&lec_arp_spinlock, flags);
+        spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
         if ((prev = lec_arp_find(priv, src))) {
-                lec_arp_remove(priv->lec_arp_tables,prev);
+                lec_arp_remove(priv, prev);
                 kfree(prev);
         }
-        lec_arp_add(priv->lec_arp_tables,entry);
+        lec_arp_add(priv, entry);
         lec_arp_put(priv);  
 }
 MODULE_LICENSE("GPL");
diff -Nru a/net/atm/lec.h b/net/atm/lec.h
--- a/net/atm/lec.h	Mon Mar  3 01:13:42 2003
+++ b/net/atm/lec.h	Thu May 29 03:07:18 2003
@@ -64,7 +64,8 @@
         int (*lecd_attach)(struct atm_vcc *vcc, int arg);
         int (*mcast_attach)(struct atm_vcc *vcc, int arg);
         int (*vcc_attach)(struct atm_vcc *vcc, void *arg);
-        struct net_device **(*get_lecs)(void);
+        struct net_device * (*get_lec)(int itf);
+        struct module *owner;
 };
 
 /*
@@ -102,6 +103,7 @@
            collects all those VCCs. LANEv1 client has only one item in this
            list. These entries are not aged out. */
         atomic_t lec_arp_users;
+        spinlock_t lec_arp_lock;
         struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
         struct atm_vcc *lecd;
         struct timer_list lec_arp_timer;
@@ -148,14 +150,16 @@
 int lecd_attach(struct atm_vcc *vcc, int arg);
 int lec_vcc_attach(struct atm_vcc *vcc, void *arg);
 int lec_mcast_attach(struct atm_vcc *vcc, int arg);
-struct net_device **get_dev_lec(void);
+struct net_device *get_dev_lec(int itf);
 int make_lec(struct atm_vcc *vcc);
 int send_to_lecd(struct lec_priv *priv,
                  atmlec_msg_type type, unsigned char *mac_addr,
                  unsigned char *atm_addr, struct sk_buff *data);
 void lec_push(struct atm_vcc *vcc, struct sk_buff *skb);
 
-void atm_lane_init(void);
-void atm_lane_init_ops(struct atm_lane_ops *ops);
+extern struct atm_lane_ops *atm_lane_ops;
+void atm_lane_ops_set(struct atm_lane_ops *hook);
+int try_atm_lane_ops(void);
+
 #endif /* _LEC_H_ */
 
diff -Nru a/net/atm/mpc.c b/net/atm/mpc.c
--- a/net/atm/mpc.c	Thu May 15 17:20:17 2003
+++ b/net/atm/mpc.c	Thu May 29 03:07:18 2003
@@ -251,12 +251,13 @@
 
 static struct net_device *find_lec_by_itfnum(int itf)
 {
-	extern struct atm_lane_ops atm_lane_ops; /* in common.c */
-	
-	if (atm_lane_ops.get_lecs == NULL)
+	struct net_device *dev;
+	if (!try_atm_lane_ops())
 		return NULL;
 
-	return atm_lane_ops.get_lecs()[itf]; /* FIXME: something better */
+	dev = atm_lane_ops->get_lec(itf);
+	module_put(atm_lane_ops->owner);
+	return dev;
 }
 
 static struct mpoa_client *alloc_mpc(void)
@@ -779,9 +780,10 @@
 
 	if (mpc->dev) { /* check if the lec is LANE2 capable */
 		priv = (struct lec_priv *)mpc->dev->priv;
-		if (priv->lane_version < 2)
+		if (priv->lane_version < 2) {
+			dev_put(mpc->dev);
 			mpc->dev = NULL;
-		else
+		} else
 			priv->lane2_ops->associate_indicator = lane2_assoc_ind;  
 	}
 
@@ -802,7 +804,7 @@
 			send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc);
 	}
 
-	MOD_INC_USE_COUNT;
+	__module_get(THIS_MODULE);
 	return arg;
 }
 
@@ -839,6 +841,7 @@
 		struct lec_priv *priv = (struct lec_priv *)mpc->dev->priv;
 		priv->lane2_ops->associate_indicator = NULL;
 		stop_mpc(mpc);
+		dev_put(mpc->dev);
 	}
 
 	mpc->in_ops->destroy_cache(mpc);
@@ -851,7 +854,7 @@
 	
 	printk("mpoa: (%s) going down\n",
 		(mpc->dev) ? mpc->dev->name : "<unknown>");
-	MOD_DEC_USE_COUNT;
+	module_put(THIS_MODULE);
 
 	return;
 }
@@ -975,6 +978,7 @@
 		}
 		mpc->dev_num = priv->itfnum;
 		mpc->dev = dev;
+		dev_hold(dev);
 		dprintk("mpoa: (%s) was initialized\n", dev->name);
 		break;
 	case NETDEV_UNREGISTER:
@@ -984,6 +988,7 @@
 			break;
 		dprintk("mpoa: device (%s) was deallocated\n", dev->name);
 		stop_mpc(mpc);
+		dev_put(mpc->dev);
 		mpc->dev = NULL;
 		break;
 	case NETDEV_UP:
@@ -1393,13 +1398,18 @@
 	return;
 }
 
-void atm_mpoa_init_ops(struct atm_mpoa_ops *ops)
+static struct atm_mpoa_ops __atm_mpoa_ops = {
+	.mpoad_attach =	atm_mpoa_mpoad_attach,
+	.vcc_attach =	atm_mpoa_vcc_attach,
+	.owner = THIS_MODULE
+};
+
+static __init int atm_mpoa_init(void)
 {
-	ops->mpoad_attach = atm_mpoa_mpoad_attach;
-	ops->vcc_attach = atm_mpoa_vcc_attach;
+	atm_mpoa_ops_set(&__atm_mpoa_ops);
 
 #ifdef CONFIG_PROC_FS
-	if(mpc_proc_init() != 0)
+	if (mpc_proc_init() != 0)
 		printk(KERN_INFO "mpoa: failed to initialize /proc/mpoa\n");
 	else
 		printk(KERN_INFO "mpoa: /proc/mpoa initialized\n");
@@ -1407,22 +1417,11 @@
 
 	printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n");
 
-	return;
-}
-
-#ifdef MODULE
-int init_module(void)
-{
-	extern struct atm_mpoa_ops atm_mpoa_ops;
-
-	atm_mpoa_init_ops(&atm_mpoa_ops);
-
 	return 0;
 }
 
-void cleanup_module(void)
+void __exit atm_mpoa_cleanup(void)
 {
-	extern struct atm_mpoa_ops atm_mpoa_ops;
 	struct mpoa_client *mpc, *tmp;
 	struct atm_mpoa_qos *qos, *nextqos;
 	struct lec_priv *priv;
@@ -1433,8 +1432,7 @@
 
 	del_timer(&mpc_timer);
 	unregister_netdevice_notifier(&mpoa_notifier);
-	atm_mpoa_ops.mpoad_attach = NULL;
-	atm_mpoa_ops.vcc_attach = NULL;
+	atm_mpoa_ops_set(NULL);
 
 	mpc = mpcs;
 	mpcs = NULL;
@@ -1469,5 +1467,8 @@
 
 	return;
 }
-#endif /* MODULE */
+
+module_init(atm_mpoa_init);
+module_exit(atm_mpoa_cleanup);
+
 MODULE_LICENSE("GPL");
diff -Nru a/net/atm/mpc.h b/net/atm/mpc.h
--- a/net/atm/mpc.h	Tue Feb  5 09:40:00 2002
+++ b/net/atm/mpc.h	Thu May 29 03:07:18 2003
@@ -48,11 +48,13 @@
 struct atm_mpoa_ops {
         int (*mpoad_attach)(struct atm_vcc *vcc, int arg);  /* attach mpoa daemon  */
         int (*vcc_attach)(struct atm_vcc *vcc, long arg);   /* attach shortcut vcc */
+	struct module *owner;
 };
 
 /* Boot/module initialization function */
-void atm_mpoa_init(void);
-void atm_mpoa_init_ops(struct atm_mpoa_ops *ops);
+extern struct atm_mpoa_ops *atm_mpoa_ops;
+int try_atm_mpoa_ops(void);
+void atm_mpoa_ops_set(struct atm_mpoa_ops *hook);
 
 /* MPOA QoS operations */
 struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos);
diff -Nru a/net/atm/proc.c b/net/atm/proc.c
--- a/net/atm/proc.c	Tue May 20 20:28:50 2003
+++ b/net/atm/proc.c	Thu May 29 03:07:18 2003
@@ -47,7 +47,6 @@
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 #include "lec.h"
 #include "lec_arpc.h"
-extern struct atm_lane_ops atm_lane_ops; /* in common.c */
 #endif
 
 static ssize_t proc_dev_atm_read(struct file *file,char *buf,size_t count,
@@ -481,57 +480,72 @@
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
 static int atm_lec_info(loff_t pos,char *buf)
 {
+	unsigned long flags;
 	struct lec_priv *priv;
 	struct lec_arp_table *entry;
 	int i, count, d, e;
-	struct net_device **dev_lec;
+	struct net_device *dev;
 
 	if (!pos) {
 		return sprintf(buf,"Itf  MAC          ATM destination"
 		    "                          Status            Flags "
 		    "VPI/VCI Recv VPI/VCI\n");
 	}
-	if (atm_lane_ops.get_lecs == NULL)
+	if (!try_atm_lane_ops())
 		return 0; /* the lane module is not there yet */
-	else
-		dev_lec = atm_lane_ops.get_lecs();
 
 	count = pos;
-	for(d=0;d<MAX_LEC_ITF;d++) {
-		if (!dev_lec[d] || !(priv =
-		    (struct lec_priv *) dev_lec[d]->priv)) continue;
-		for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
-			entry = priv->lec_arp_tables[i];
-			for(;entry;entry=entry->next) {
-				if (--count) continue;
-				e=sprintf(buf,"%s ",
-				    dev_lec[d]->name);
-				lec_info(entry,buf+e);
+	for(d = 0; d < MAX_LEC_ITF; d++) {
+		dev = atm_lane_ops->get_lec(d);
+		if (!dev || !(priv = (struct lec_priv *) dev->priv))
+			continue;
+		spin_lock_irqsave(&priv->lec_arp_lock, flags);
+		for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+			for(entry = priv->lec_arp_tables[i]; entry; entry = entry->next) {
+				if (--count)
+					continue;
+				e = sprintf(buf,"%s ", dev->name);
+				lec_info(entry, buf+e);
+				spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+				dev_put(dev);
+				module_put(atm_lane_ops->owner);
 				return strlen(buf);
 			}
 		}
-		for(entry=priv->lec_arp_empty_ones; entry;
-		    entry=entry->next) {
-			if (--count) continue;
-			e=sprintf(buf,"%s ",dev_lec[d]->name);
+		for(entry = priv->lec_arp_empty_ones; entry; entry = entry->next) {
+			if (--count)
+				continue;
+			e = sprintf(buf,"%s ", dev->name);
 			lec_info(entry, buf+e);
+			spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+			dev_put(dev);
+			module_put(atm_lane_ops->owner);
 			return strlen(buf);
 		}
-		for(entry=priv->lec_no_forward; entry;
-		    entry=entry->next) {
-			if (--count) continue;
-			e=sprintf(buf,"%s ",dev_lec[d]->name);
+		for(entry = priv->lec_no_forward; entry; entry=entry->next) {
+			if (--count)
+				continue;
+			e = sprintf(buf,"%s ", dev->name);
 			lec_info(entry, buf+e);
+			spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+			dev_put(dev);
+			module_put(atm_lane_ops->owner);
 			return strlen(buf);
 		}
-		for(entry=priv->mcast_fwds; entry;
-		    entry=entry->next) {
-			if (--count) continue;
-			e=sprintf(buf,"%s ",dev_lec[d]->name);
+		for(entry = priv->mcast_fwds; entry; entry = entry->next) {
+			if (--count)
+				continue;
+			e = sprintf(buf,"%s ", dev->name);
 			lec_info(entry, buf+e);
+			spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+			dev_put(dev);
+			module_put(atm_lane_ops->owner);
 			return strlen(buf);
 		}
+		spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+		dev_put(dev);
 	}
+	module_put(atm_lane_ops->owner);
 	return 0;
 }
 #endif
diff -Nru a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
--- a/net/ax25/af_ax25.c	Sun May 25 19:36:24 2003
+++ b/net/ax25/af_ax25.c	Wed May 28 01:07:02 2003
@@ -328,7 +328,7 @@
 				ax25_cb *sax25 = ax25_sk(skb->sk);
 
 				/* Queue the unaccepted socket for death */
-				__set_bit(SOCK_DEAD, &skb->sk->flags);
+				sock_set_flag(skb->sk, SOCK_DEAD);
 
 				ax25_start_heartbeat(sax25);
 				sax25->state = AX25_STATE_0;
@@ -981,8 +981,8 @@
 			sk->state                = TCP_CLOSE;
 			sk->shutdown            |= SEND_SHUTDOWN;
 			sk->state_change(sk);
-			__set_bit(SOCK_DEAD, &sk->flags);
-			__set_bit(SOCK_DESTROY, &sk->flags);
+			sock_set_flag(sk, SOCK_DEAD);
+			sock_set_flag(sk, SOCK_DESTROY);
 			break;
 
 		default:
@@ -992,7 +992,7 @@
 		sk->state     = TCP_CLOSE;
 		sk->shutdown |= SEND_SHUTDOWN;
 		sk->state_change(sk);
-		__set_bit(SOCK_DEAD, &sk->flags);
+		sock_set_flag(sk, SOCK_DEAD);
 		ax25_destroy_socket(ax25);
 	}
 
diff -Nru a/net/ax25/ax25_ds_in.c b/net/ax25/ax25_ds_in.c
--- a/net/ax25/ax25_ds_in.c	Mon Mar  3 04:56:53 2003
+++ b/net/ax25/ax25_ds_in.c	Wed May 28 01:07:02 2003
@@ -66,8 +66,11 @@
 		ax25->n2count = 0;
 		if (ax25->sk != NULL) {
 			ax25->sk->state = TCP_ESTABLISHED;
-			/* For WAIT_SABM connections we will produce an accept ready socket here */
-			if (!test_bit(SOCK_DEAD, &ax25->sk->flags))
+			/*
+			 * For WAIT_SABM connections we will produce an accept
+			 * ready socket here
+			 */
+			if (!sock_flag(ax25->sk, SOCK_DEAD))
 				ax25->sk->state_change(ax25->sk);
 		}
 		ax25_dama_on(ax25);
diff -Nru a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c
--- a/net/ax25/ax25_ds_timer.c	Mon Mar  3 04:56:53 2003
+++ b/net/ax25/ax25_ds_timer.c	Wed May 28 01:07:02 2003
@@ -103,7 +103,9 @@
 	case AX25_STATE_0:
 		/* Magic here: If we listen() and a new link dies before it
 		   is accepted() it isn't 'dead' so doesn't get removed. */
-		if (ax25->sk == NULL || test_bit(SOCK_DESTROY, &ax25->sk->flags) || (ax25->sk->state == TCP_LISTEN && test_bit(SOCK_DEAD, &ax25->sk->flags))) {
+		if (!ax25->sk || sock_flag(ax25->sk, SOCK_DESTROY) ||
+		    (ax25->sk->state == TCP_LISTEN &&
+		     sock_flag(ax25->sk, SOCK_DEAD))) {
 			ax25_destroy_socket(ax25);
 			return;
 		}
@@ -157,9 +159,10 @@
 		ax25->sk->state     = TCP_CLOSE;
 		ax25->sk->err       = 0;
 		ax25->sk->shutdown |= SEND_SHUTDOWN;
-		if (!test_bit(SOCK_DEAD, &ax25->sk->flags))
+		if (!sock_flag(ax25->sk, SOCK_DEAD)) {
 			ax25->sk->state_change(ax25->sk);
-		__set_bit(SOCK_DEAD, &ax25->sk->flags);
+			sock_set_flag(ax25->sk, SOCK_DEAD);
+		}
 	}
 }
 
diff -Nru a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c
--- a/net/ax25/ax25_in.c	Mon Mar  3 04:56:53 2003
+++ b/net/ax25/ax25_in.c	Wed May 28 01:07:02 2003
@@ -433,12 +433,11 @@
 	ax25_start_t3timer(ax25);
 	ax25_start_idletimer(ax25);
 
-	if (sk != NULL) {
-		if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (sk) {
+		if (!sock_flag(sk, SOCK_DEAD))
 			sk->data_ready(sk, skb->len);
-	} else {
+	} else
 		kfree_skb(skb);
-	}
 
 	return 0;
 }
diff -Nru a/net/ax25/ax25_std_in.c b/net/ax25/ax25_std_in.c
--- a/net/ax25/ax25_std_in.c	Mon Mar  3 04:56:53 2003
+++ b/net/ax25/ax25_std_in.c	Wed May 28 01:07:02 2003
@@ -75,7 +75,7 @@
 			if (ax25->sk != NULL) {
 				ax25->sk->state = TCP_ESTABLISHED;
 				/* For WAIT_SABM connections we will produce an accept ready socket here */
-				if (!test_bit(SOCK_DEAD, &ax25->sk->flags))
+				if (!sock_flag(ax25->sk, SOCK_DEAD))
 					ax25->sk->state_change(ax25->sk);
 			}
 		}
diff -Nru a/net/ax25/ax25_std_timer.c b/net/ax25/ax25_std_timer.c
--- a/net/ax25/ax25_std_timer.c	Mon Mar  3 04:56:53 2003
+++ b/net/ax25/ax25_std_timer.c	Wed May 28 01:07:02 2003
@@ -37,7 +37,9 @@
 	case AX25_STATE_0:
 		/* Magic here: If we listen() and a new link dies before it
 		   is accepted() it isn't 'dead' so doesn't get removed. */
-		if (ax25->sk == NULL || test_bit(SOCK_DESTROY, &ax25->sk->flags) || (ax25->sk->state == TCP_LISTEN && test_bit(SOCK_DEAD, &ax25->sk->flags))) {
+		if (!ax25->sk || sock_flag(ax25->sk, SOCK_DESTROY) ||
+		    (ax25->sk->state == TCP_LISTEN &&
+		     sock_flag(ax25->sk, SOCK_DEAD))) {
 			ax25_destroy_socket(ax25);
 			return;
 		}
@@ -94,9 +96,10 @@
 		ax25->sk->state     = TCP_CLOSE;
 		ax25->sk->err       = 0;
 		ax25->sk->shutdown |= SEND_SHUTDOWN;
-		if (!test_bit(SOCK_DEAD, &ax25->sk->flags))
+		if (!sock_flag(ax25->sk, SOCK_DEAD)) {
 			ax25->sk->state_change(ax25->sk);
-		__set_bit(SOCK_DEAD, &ax25->sk->flags);
+			sock_set_flag(ax25->sk, SOCK_DEAD);
+		}
 	}
 }
 
diff -Nru a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c
--- a/net/ax25/ax25_subr.c	Mon Mar  3 04:56:53 2003
+++ b/net/ax25/ax25_subr.c	Wed May 28 01:07:02 2003
@@ -285,8 +285,9 @@
 		ax25->sk->state     = TCP_CLOSE;
 		ax25->sk->err       = reason;
 		ax25->sk->shutdown |= SEND_SHUTDOWN;
-		if (!test_bit(SOCK_DEAD, &ax25->sk->flags))
+		if (!sock_flag(ax25->sk, SOCK_DEAD)) {
 			ax25->sk->state_change(ax25->sk);
-		__set_bit(SOCK_DEAD, &ax25->sk->flags);
+			sock_set_flag(ax25->sk, SOCK_DEAD);
+		}
 	}
 }
diff -Nru a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
--- a/net/bluetooth/l2cap.c	Mon May 12 12:47:24 2003
+++ b/net/bluetooth/l2cap.c	Wed May 28 01:07:02 2003
@@ -266,7 +266,7 @@
 
 	/* Kill poor orphan */
 	bt_sock_unlink(&l2cap_sk_list, sk);
-	__set_bit(SOCK_DEAD, &sk->flags);
+	sock_set_flag(sk, SOCK_DEAD);
 	sock_put(sk);
 }
 
diff -Nru a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
--- a/net/bluetooth/rfcomm/sock.c	Mon May 12 12:47:24 2003
+++ b/net/bluetooth/rfcomm/sock.c	Thu May 29 04:07:50 2003
@@ -210,7 +210,7 @@
 
 	/* Kill poor orphan */
 	bt_sock_unlink(&rfcomm_sk_list, sk);
-	__set_bit(SOCK_DEAD, &sk->flags);
+	sock_set_flag(sk, SOCK_DEAD);
 	sock_put(sk);
 }
 
diff -Nru a/net/bluetooth/sco.c b/net/bluetooth/sco.c
--- a/net/bluetooth/sco.c	Mon May 12 12:47:24 2003
+++ b/net/bluetooth/sco.c	Wed May 28 01:07:02 2003
@@ -371,7 +371,7 @@
 
 	/* Kill poor orphan */
 	bt_sock_unlink(&sco_sk_list, sk);
-	__set_bit(SOCK_DEAD, &sk->flags);
+	sock_set_flag(sk, SOCK_DEAD);
 	sock_put(sk);
 }
 
diff -Nru a/net/bridge/br_if.c b/net/bridge/br_if.c
--- a/net/bridge/br_if.c	Sun May 25 19:36:24 2003
+++ b/net/bridge/br_if.c	Thu May 29 20:02:36 2003
@@ -170,11 +170,12 @@
 	struct net_device *dev;
 	int ret = 0;
 
-	dev = dev_get_by_name(name);
+	rtnl_lock();
+	dev = __dev_get_by_name(name);
 	if (dev == NULL) 
-		return -ENXIO; 	/* Could not find device */
+		ret =  -ENXIO; 	/* Could not find device */
 
-	if (!(dev->priv_flags & IFF_EBRIDGE)) {
+	else if (!(dev->priv_flags & IFF_EBRIDGE)) {
 		/* Attempt to delete non bridge device! */
 		ret = -EPERM;
 	}
@@ -186,11 +187,10 @@
 
 	else {
 		del_ifs((struct net_bridge *) dev->priv);
-	
-		unregister_netdev(dev);
+		unregister_netdevice(dev);
 	}
 
-	dev_put(dev);
+	rtnl_unlock();
 	return ret;
 }
 
diff -Nru a/net/bridge/br_input.c b/net/bridge/br_input.c
--- a/net/bridge/br_input.c	Wed May 14 13:59:21 2003
+++ b/net/bridge/br_input.c	Wed May 28 01:47:56 2003
@@ -41,9 +41,6 @@
 
 	indev = skb->dev;
 	skb->dev = &br->dev;
-	skb->pkt_type = PACKET_HOST;
-	skb_push(skb, ETH_HLEN);
-	skb->protocol = eth_type_trans(skb, &br->dev);
 
 	NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
 			br_pass_frame_up_finish);
diff -Nru a/net/core/flow.c b/net/core/flow.c
--- a/net/core/flow.c	Thu May 15 23:24:35 2003
+++ b/net/core/flow.c	Tue May 27 22:06:37 2003
@@ -199,6 +199,8 @@
 				fle->genid = atomic_read(&flow_cache_genid);
 				fle->object = obj;
 				fle->object_ref = obj_ref;
+				if (obj)
+					atomic_inc(fle->object_ref);
 
 				flow_count(cpu)++;
 			}
diff -Nru a/net/core/net-sysfs.c b/net/core/net-sysfs.c
--- a/net/core/net-sysfs.c	Sun May 25 19:21:31 2003
+++ b/net/core/net-sysfs.c	Thu May 29 20:14:56 2003
@@ -16,16 +16,6 @@
 #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 */
@@ -66,20 +56,6 @@
 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;
@@ -175,7 +151,6 @@
 	&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,
@@ -294,7 +269,7 @@
 	class_dev->class = &net_class;
 	class_dev->class_data = net;
 
-	snprintf(class_dev->class_id, BUS_ID_SIZE, net->name);
+	strlcpy(class_dev->class_id, net->name, BUS_ID_SIZE);
 	if ((ret = class_device_register(class_dev)))
 		goto out;
 
@@ -303,17 +278,18 @@
 		    goto out_unreg;
 	}
 
+	
+	net->stats_kobj.parent = NULL;
 	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");
+		strlcpy(k->name, "statistics", KOBJ_NAME_LEN);
 		k->ktype = &netstat_ktype;
 
 		if((ret = kobject_register(k))) 
@@ -331,8 +307,9 @@
 
 void netdev_unregister_sysfs(struct net_device *net)
 {
-	if (net->get_stats)
-		kobject_del(&net->stats_kobj);
+	if (net->stats_kobj.parent) 
+		kobject_unregister(&net->stats_kobj);
+
 	class_device_unregister(&net->class_dev);
 }
 
diff -Nru a/net/core/sock.c b/net/core/sock.c
--- a/net/core/sock.c	Tue May 13 13:42:28 2003
+++ b/net/core/sock.c	Wed May 28 01:07:02 2003
@@ -177,10 +177,9 @@
 	 */
 
 #ifdef SO_DONTLINGER		/* Compatibility item... */
-	switch(optname)
-	{
+	switch (optname) {
 		case SO_DONTLINGER:
-			__clear_bit(SOCK_LINGER, &sk->flags);
+			sock_reset_flag(sk, SOCK_LINGER);
 			return 0;
 	}
 #endif	
@@ -291,16 +290,16 @@
 				ret = -EFAULT;
 				break;
 			}
-			if(ling.l_onoff==0) {
-				__clear_bit(SOCK_LINGER, &sk->flags);
-			} else {
+			if (!ling.l_onoff)
+				sock_reset_flag(sk, SOCK_LINGER);
+			else {
 #if (BITS_PER_LONG == 32)
 				if (ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ)
 					sk->lingertime=MAX_SCHEDULE_TIMEOUT;
 				else
 #endif
 					sk->lingertime=ling.l_linger*HZ;
-				__set_bit(SOCK_LINGER, &sk->flags);
+				sock_set_flag(sk, SOCK_LINGER);
 			}
 			break;
 
@@ -444,7 +443,7 @@
 			break;
 		
 		case SO_BROADCAST:
-			v.val= test_bit(SOCK_BROADCAST, &sk->flags);
+			v.val = !!sock_flag(sk, SOCK_BROADCAST);
 			break;
 
 		case SO_SNDBUF:
@@ -460,7 +459,7 @@
 			break;
 
 		case SO_KEEPALIVE:
-			v.val = test_bit(SOCK_KEEPOPEN, &sk->flags);
+			v.val = !!sock_flag(sk, SOCK_KEEPOPEN);
 			break;
 
 		case SO_TYPE:
@@ -474,7 +473,7 @@
 			break;
 
 		case SO_OOBINLINE:
-			v.val = test_bit(SOCK_URGINLINE, &sk->flags);
+			v.val = !!sock_flag(sk, SOCK_URGINLINE);
 			break;
 	
 		case SO_NO_CHECK:
@@ -486,9 +485,9 @@
 			break;
 		
 		case SO_LINGER:	
-			lv=sizeof(v.ling);
-			v.ling.l_onoff = test_bit(SOCK_LINGER, &sk->flags);
- 			v.ling.l_linger=sk->lingertime/HZ;
+			lv		= sizeof(v.ling);
+			v.ling.l_onoff	= !!sock_flag(sk, SOCK_LINGER);
+ 			v.ling.l_linger	= sk->lingertime / HZ;
 			break;
 					
 		case SO_BSDCOMPAT:
diff -Nru a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
--- a/net/decnet/dn_nsp_in.c	Tue May  6 00:58:43 2003
+++ b/net/decnet/dn_nsp_in.c	Wed May 28 01:07:02 2003
@@ -119,7 +119,7 @@
 			break;
 	}
 
-	if (wakeup && !test_bit(SOCK_DEAD, &sk->flags))
+	if (wakeup && !sock_flag(sk, SOCK_DEAD))
 		sk->state_change(sk);
 }
 
@@ -368,7 +368,7 @@
 			}
 		}
                 dn_nsp_send_link(sk, DN_NOCHANGE, 0);
-                if (!test_bit(SOCK_DEAD, &sk->flags))
+                if (!sock_flag(sk, SOCK_DEAD))
                 	sk->state_change(sk);
         }
 
@@ -429,7 +429,7 @@
 			break;
 	}
 
-	if (!test_bit(SOCK_DEAD, &sk->flags)) {
+	if (!sock_flag(sk, SOCK_DEAD)) {
 		if (sk->socket->state != SS_UNCONNECTED)
 			sk->socket->state = SS_DISCONNECTING;
 		sk->state_change(sk);
@@ -486,7 +486,7 @@
 			scp->state = DN_CN;
 	}
 
-	if (!test_bit(SOCK_DEAD, &sk->flags)) {
+	if (!sock_flag(sk, SOCK_DEAD)) {
 		if (sk->socket->state != SS_UNCONNECTED)
 			sk->socket->state = SS_DISCONNECTING;
 		sk->state_change(sk);
@@ -558,7 +558,7 @@
 			}
 			break;
                 }
-		if (wake_up && !test_bit(SOCK_DEAD, &sk->flags))
+		if (wake_up && !sock_flag(sk, SOCK_DEAD))
 			sk->state_change(sk);
         }
 
@@ -596,7 +596,7 @@
 	 * Therefore the plain read_lock is ok here. -DaveM
 	 */
 	read_lock(&sk->callback_lock);
-        if (!test_bit(SOCK_DEAD, &sk->flags)) {
+        if (!sock_flag(sk, SOCK_DEAD)) {
 		struct socket *sock = sk->socket;
 		wake_up_interruptible(sk->sleep);
 		if (sock && sock->fasync_list &&
@@ -680,7 +680,7 @@
 	if (scp->state == DN_CI) {
 		scp->state = DN_NC;
 		sk->state = TCP_CLOSE;
-		if (!test_bit(SOCK_DEAD, &sk->flags))
+		if (!sock_flag(sk, SOCK_DEAD))
 			sk->state_change(sk);
 	}
 
@@ -882,7 +882,7 @@
 		int other = 1;
 
 		/* both data and ack frames can kick a CC socket into RUN */
-		if ((scp->state == DN_CC) && !test_bit(SOCK_DEAD, &sk->flags)) {
+		if ((scp->state == DN_CC) && !sock_flag(sk, SOCK_DEAD)) {
 			scp->state = DN_RUN;
 			sk->state = TCP_ESTABLISHED;
 			sk->state_change(sk);
diff -Nru a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
--- a/net/decnet/dn_nsp_out.c	Tue May  6 00:58:43 2003
+++ b/net/decnet/dn_nsp_out.c	Wed May 28 01:07:02 2003
@@ -104,7 +104,7 @@
 	}
 
 	sk->err = EHOSTUNREACH;
-	if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (!sock_flag(sk, SOCK_DEAD))
 		sk->state_change(sk);
 }
 
diff -Nru a/net/econet/af_econet.c b/net/econet/af_econet.c
--- a/net/econet/af_econet.c	Wed May  7 13:36:50 2003
+++ b/net/econet/af_econet.c	Wed May 28 01:07:02 2003
@@ -531,7 +531,7 @@
 
 	sock->sk = NULL;
 	sk->socket = NULL;
-	__set_bit(SOCK_DEAD, &sk->flags);
+	sock_set_flag(sk, SOCK_DEAD);
 
 	/* Purge queues */
 
diff -Nru a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
--- a/net/ipv4/af_inet.c	Sun May 25 19:42:46 2003
+++ b/net/ipv4/af_inet.c	Thu May 29 02:52:41 2003
@@ -146,7 +146,7 @@
 		       sk);
 		return;
 	}
-	if (!test_bit(SOCK_DEAD, &sk->flags)) {
+	if (!sock_flag(sk, SOCK_DEAD)) {
 		printk("Attempt to release alive inet socket %p\n", sk);
 		return;
 	}
@@ -456,8 +456,8 @@
 		 * linger..
 		 */
 		timeout = 0;
-		if (test_bit(SOCK_LINGER, &sk->flags) &&
-				!(current->flags & PF_EXITING))
+		if (sock_flag(sk, SOCK_LINGER) &&
+		    !(current->flags & PF_EXITING))
 			timeout = sk->lingertime;
 		sock->sk = NULL;
 		sk->prot->close(sk, timeout);
@@ -1122,6 +1122,7 @@
 }
 
 int ipv4_proc_init(void);
+extern void ipfrag_init(void);
 
 static int __init inet_init(void)
 {
@@ -1224,6 +1225,9 @@
 		printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); ;
 	
 	ipv4_proc_init();
+
+	ipfrag_init();
+
 	return 0;
 }
 
diff -Nru a/net/ipv4/esp.c b/net/ipv4/esp.c
--- a/net/ipv4/esp.c	Thu May 22 19:22:14 2003
+++ b/net/ipv4/esp.c	Mon May 26 16:26:22 2003
@@ -567,7 +567,7 @@
 	.no_policy	=	1,
 };
 
-int __init esp4_init(void)
+static int __init esp4_init(void)
 {
 	struct xfrm_decap_state decap;
 
@@ -578,7 +578,6 @@
 		decap_data_too_small();
 	}
 
-	esp_type.owner = THIS_MODULE;
 	if (xfrm_register_type(&esp_type, AF_INET) < 0) {
 		printk(KERN_INFO "ip esp init: can't add xfrm type\n");
 		return -EAGAIN;
diff -Nru a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
--- a/net/ipv4/ip_fragment.c	Tue Feb 18 20:15:07 2003
+++ b/net/ipv4/ip_fragment.c	Wed May 28 00:31:31 2003
@@ -31,6 +31,8 @@
 #include <linux/ip.h>
 #include <linux/icmp.h>
 #include <linux/netdevice.h>
+#include <linux/jhash.h>
+#include <linux/random.h>
 #include <net/sock.h>
 #include <net/ip.h>
 #include <net/icmp.h>
@@ -97,6 +99,7 @@
 /* Per-bucket lock is easy to add now. */
 static struct ipq *ipq_hash[IPQ_HASHSZ];
 static rwlock_t ipfrag_lock = RW_LOCK_UNLOCKED;
+static u32 ipfrag_hash_rnd;
 static LIST_HEAD(ipq_lru_list);
 int ip_frag_nqueues = 0;
 
@@ -116,21 +119,51 @@
 	write_unlock(&ipfrag_lock);
 }
 
-/*
- * Was:	((((id) >> 1) ^ (saddr) ^ (daddr) ^ (prot)) & (IPQ_HASHSZ - 1))
- *
- * I see, I see evil hand of bigendian mafia. On Intel all the packets hit
- * one hash bucket with this hash function. 8)
- */
-static __inline__ unsigned int ipqhashfn(u16 id, u32 saddr, u32 daddr, u8 prot)
+static unsigned int ipqhashfn(u16 id, u32 saddr, u32 daddr, u8 prot)
 {
-	unsigned int h = saddr ^ daddr;
-
-	h ^= (h>>16)^id;
-	h ^= (h>>8)^prot;
-	return h & (IPQ_HASHSZ - 1);
+	return jhash_3words((u32)id << 16 | prot, saddr, daddr,
+			    ipfrag_hash_rnd) & (IPQ_HASHSZ - 1);
 }
 
+static struct timer_list ipfrag_secret_timer;
+int sysctl_ipfrag_secret_interval = 10 * 60 * HZ;
+
+static void ipfrag_secret_rebuild(unsigned long dummy)
+{
+	unsigned long now = jiffies;
+	int i;
+
+	write_lock(&ipfrag_lock);
+	get_random_bytes(&ipfrag_hash_rnd, sizeof(u32));
+	for (i = 0; i < IPQ_HASHSZ; i++) {
+		struct ipq *q;
+
+		q = ipq_hash[i];
+		while (q) {
+			struct ipq *next = q->next;
+			unsigned int hval = ipqhashfn(q->id, q->saddr,
+						      q->daddr, q->protocol);
+
+			if (hval != i) {
+				/* Unlink. */
+				if (q->next)
+					q->next->pprev = q->pprev;
+				*q->pprev = q->next;
+
+				/* Relink to new hash chain. */
+				if ((q->next = ipq_hash[hval]) != NULL)
+					q->next->pprev = &q->next;
+				ipq_hash[hval] = q;
+				q->pprev = &ipq_hash[hval];
+			}
+
+			q = next;
+		}
+	}
+	write_unlock(&ipfrag_lock);
+
+	mod_timer(&ipfrag_secret_timer, now + sysctl_ipfrag_secret_interval);
+}
 
 atomic_t ip_frag_mem = ATOMIC_INIT(0);	/* Memory used for fragments */
 
@@ -630,4 +663,15 @@
 	IP_INC_STATS_BH(IpReasmFails);
 	kfree_skb(skb);
 	return NULL;
+}
+
+void ipfrag_init(void)
+{
+	ipfrag_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
+				 (jiffies ^ (jiffies >> 6)));
+
+	init_timer(&ipfrag_secret_timer);
+	ipfrag_secret_timer.function = ipfrag_secret_rebuild;
+	ipfrag_secret_timer.expires = jiffies + sysctl_ipfrag_secret_interval;
+	add_timer(&ipfrag_secret_timer);
 }
diff -Nru a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
--- a/net/ipv4/ipcomp.c	Thu May 22 19:22:14 2003
+++ b/net/ipv4/ipcomp.c	Mon May 26 16:26:22 2003
@@ -382,9 +382,9 @@
 	goto out;
 }
 
-static struct xfrm_type ipcomp_type =
-{
+static struct xfrm_type ipcomp_type = {
 	.description	= "IPCOMP4",
+	.owner		= THIS_MODULE,
 	.proto	     	= IPPROTO_COMP,
 	.init_state	= ipcomp_init_state,
 	.destructor	= ipcomp_destroy,
@@ -400,7 +400,6 @@
 
 static int __init ipcomp4_init(void)
 {
-	ipcomp_type.owner = THIS_MODULE;
 	if (xfrm_register_type(&ipcomp_type, AF_INET) < 0) {
 		printk(KERN_INFO "ipcomp init: can't add xfrm type\n");
 		return -EAGAIN;
diff -Nru a/net/ipv4/raw.c b/net/ipv4/raw.c
--- a/net/ipv4/raw.c	Sat May 10 11:46:35 2003
+++ b/net/ipv4/raw.c	Wed May 28 01:07:02 2003
@@ -450,8 +450,7 @@
 		goto done;
 
 	err = -EACCES;
-	if (rt->rt_flags & RTCF_BROADCAST &&
-			!test_bit(SOCK_BROADCAST, &sk->flags))
+	if (rt->rt_flags & RTCF_BROADCAST && !sock_flag(sk, SOCK_BROADCAST))
 		goto done;
 
 	if (msg->msg_flags & MSG_CONFIRM)
diff -Nru a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
--- a/net/ipv4/sysctl_net_ipv4.c	Sat May 17 23:02:40 2003
+++ b/net/ipv4/sysctl_net_ipv4.c	Wed May 28 00:31:31 2003
@@ -27,6 +27,7 @@
 extern int sysctl_ipfrag_low_thresh;
 extern int sysctl_ipfrag_high_thresh; 
 extern int sysctl_ipfrag_time;
+extern int sysctl_ipfrag_secret_interval;
 
 /* From ip_output.c */
 extern int sysctl_ip_dynaddr;
@@ -571,6 +572,15 @@
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec
+	},
+	{
+		.ctl_name	= NET_IPV4_IPFRAG_SECRET_INTERVAL,
+		.procname	= "ipfrag_secret_interval",
+		.data		= &sysctl_ipfrag_secret_interval,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+		.strategy	= &sysctl_jiffies
 	},
 	{ .ctl_name = 0 }
 };
diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c
--- a/net/ipv4/tcp.c	Wed May 14 20:16:59 2003
+++ b/net/ipv4/tcp.c	Wed May 28 01:07:02 2003
@@ -442,7 +442,7 @@
 		if ((tp->rcv_nxt != tp->copied_seq) &&
 		    (tp->urg_seq != tp->copied_seq ||
 		     tp->rcv_nxt != tp->copied_seq + 1 ||
-		     test_bit(SOCK_URGINLINE, &sk->flags) || !tp->urg_data))
+		     sock_flag(sk, SOCK_URGINLINE) || !tp->urg_data))
 			mask |= POLLIN | POLLRDNORM;
 
 		if (!(sk->shutdown & SEND_SHUTDOWN)) {
@@ -498,7 +498,7 @@
 		lock_sock(sk);
 		if ((1 << sk->state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))
 			answ = 0;
-		else if (test_bit(SOCK_URGINLINE, &sk->flags) ||
+		else if (sock_flag(sk, SOCK_URGINLINE) ||
 			 !tp->urg_data ||
 			 before(tp->urg_seq, tp->copied_seq) ||
 			 !before(tp->urg_seq, tp->rcv_nxt)) {
@@ -1254,11 +1254,11 @@
 	struct tcp_opt *tp = tcp_sk(sk);
 
 	/* No URG data to read. */
-	if (test_bit(SOCK_URGINLINE, &sk->flags) || !tp->urg_data ||
-			tp->urg_data == TCP_URG_READ)
+	if (sock_flag(sk, SOCK_URGINLINE) || !tp->urg_data ||
+	    tp->urg_data == TCP_URG_READ)
 		return -EINVAL;	/* Yes this is right ! */
 
-	if (sk->state == TCP_CLOSE && !test_bit(SOCK_DONE, &sk->flags))
+	if (sk->state == TCP_CLOSE && !sock_flag(sk, SOCK_DONE))
 		return -ENOTCONN;
 
 	if (tp->urg_data & TCP_URG_VALID) {
@@ -1586,7 +1586,7 @@
 			    (flags & MSG_PEEK))
 				break;
 		} else {
-			if (test_bit(SOCK_DONE, &sk->flags))
+			if (sock_flag(sk, SOCK_DONE))
 				break;
 
 			if (sk->err) {
@@ -1598,7 +1598,7 @@
 				break;
 
 			if (sk->state == TCP_CLOSE) {
-				if (!test_bit(SOCK_DONE, &sk->flags)) {
+				if (!sock_flag(sk, SOCK_DONE)) {
 					/* This occurs when user tries to read
 					 * from never connected socket.
 					 */
@@ -1711,8 +1711,7 @@
 			u32 urg_offset = tp->urg_seq - *seq;
 			if (urg_offset < used) {
 				if (!urg_offset) {
-					if (!test_bit(SOCK_URGINLINE,
-								&sk->flags)) {
+					if (!sock_flag(sk, SOCK_URGINLINE)) {
 						++*seq;
 						offset++;
 						used--;
@@ -1836,7 +1835,7 @@
 
 /*
  *	Shutdown the sending side of a connection. Much like close except
- *	that we don't receive shut down or set SOCK_DEAD in sk->flags.
+ *	that we don't receive shut down or set_sock_flag(sk, SOCK_DEAD).
  */
 
 void tcp_shutdown(struct sock *sk, int how)
@@ -1901,7 +1900,7 @@
 void tcp_destroy_sock(struct sock *sk)
 {
 	BUG_TRAP(sk->state == TCP_CLOSE);
-	BUG_TRAP(test_bit(SOCK_DEAD, &sk->flags));
+	BUG_TRAP(sock_flag(sk, SOCK_DEAD));
 
 	/* It cannot be in hash table! */
 	BUG_TRAP(!sk->pprev);
@@ -1978,7 +1977,7 @@
 		NET_INC_STATS_USER(TCPAbortOnClose);
 		tcp_set_state(sk, TCP_CLOSE);
 		tcp_send_active_reset(sk, GFP_KERNEL);
-	} else if (test_bit(SOCK_LINGER, &sk->flags) && !sk->lingertime) {
+	} else if (sock_flag(sk, SOCK_LINGER) && !sk->lingertime) {
 		/* Check zero linger _after_ checking for unread data. */
 		sk->prot->disconnect(sk, 0);
 		NET_INC_STATS_USER(TCPAbortOnData);
@@ -2144,7 +2143,7 @@
 		inet_reset_saddr(sk);
 
 	sk->shutdown = 0;
-	__clear_bit(SOCK_DONE, &sk->flags);
+	sock_reset_flag(sk, SOCK_DONE);
 	tp->srtt = 0;
 	if ((tp->write_seq += tp->max_window + 2) == 0)
 		tp->write_seq = 1;
@@ -2343,7 +2342,7 @@
 			err = -EINVAL;
 		else {
 			tp->keepalive_time = val * HZ;
-			if (test_bit(SOCK_KEEPOPEN, &sk->flags) &&
+			if (sock_flag(sk, SOCK_KEEPOPEN) &&
 			    !((1 << sk->state) & (TCPF_CLOSE | TCPF_LISTEN))) {
 				__u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
 				if (tp->keepalive_time > elapsed)
diff -Nru a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
--- a/net/ipv4/tcp_input.c	Mon Apr 28 09:27:57 2003
+++ b/net/ipv4/tcp_input.c	Wed May 28 01:07:02 2003
@@ -2352,7 +2352,7 @@
 			sk->err = ECONNRESET;
 	}
 
-	if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (!sock_flag(sk, SOCK_DEAD))
 		sk->error_report(sk);
 
 	tcp_done(sk);
@@ -2379,7 +2379,7 @@
 	tcp_schedule_ack(tp);
 
 	sk->shutdown |= RCV_SHUTDOWN;
-	__clear_bit(SOCK_DONE, &sk->flags);
+	sock_reset_flag(sk, SOCK_DONE);
 
 	switch(sk->state) {
 		case TCP_SYN_RECV:
@@ -2428,7 +2428,7 @@
 		tcp_sack_reset(tp);
 	tcp_mem_reclaim(sk);
 
-	if (!test_bit(SOCK_DEAD, &sk->flags)) {
+	if (!sock_flag(sk, SOCK_DEAD)) {
 		sk->state_change(sk);
 
 		/* Do not send POLL_HUP for half duplex close. */
@@ -2743,9 +2743,9 @@
 
 		tcp_fast_path_check(sk, tp);
 
-		if (eaten > 0) {
+		if (eaten > 0)
 			__kfree_skb(skb);
-		} else if (!test_bit(SOCK_DEAD, &sk->flags))
+		else if (!sock_flag(sk, SOCK_DEAD))
 			sk->data_ready(sk, 0);
 		return;
 	}
@@ -3247,7 +3247,7 @@
 	 * buggy users.
 	 */
 	if (tp->urg_seq == tp->copied_seq && tp->urg_data &&
-	    !test_bit(SOCK_URGINLINE, &sk->flags) &&
+	    !sock_flag(sk, SOCK_URGINLINE) &&
 	    tp->copied_seq != tp->rcv_nxt) {
 		struct sk_buff *skb = skb_peek(&sk->receive_queue);
 		tp->copied_seq++;
@@ -3284,7 +3284,7 @@
 			if (skb_copy_bits(skb, ptr, &tmp, 1))
 				BUG();
 			tp->urg_data = TCP_URG_VALID | tmp;
-			if (!test_bit(SOCK_DEAD, &sk->flags))
+			if (!sock_flag(sk, SOCK_DEAD))
 				sk->data_ready(sk,0);
 		}
 	}
@@ -3699,7 +3699,7 @@
 		tcp_init_metrics(sk);
 		tcp_init_buffer_space(sk);
 
-		if (test_bit(SOCK_KEEPOPEN, &sk->flags))
+		if (sock_flag(sk, SOCK_KEEPOPEN))
 			tcp_reset_keepalive_timer(sk, keepalive_time_when(tp));
 
 		if (!tp->snd_wscale)
@@ -3714,7 +3714,7 @@
 		mb();
 		tcp_set_state(sk, TCP_ESTABLISHED);
 
-		if(!test_bit(SOCK_DEAD, &sk->flags)) {
+		if (!sock_flag(sk, SOCK_DEAD)) {
 			sk->state_change(sk);
 			sk_wake_async(sk, 0, POLL_OUT);
 		}
@@ -3977,10 +3977,10 @@
 				sk->shutdown |= SEND_SHUTDOWN;
 				dst_confirm(sk->dst_cache);
 
-				if (!test_bit(SOCK_DEAD, &sk->flags)) {
+				if (!sock_flag(sk, SOCK_DEAD))
 					/* Wake up lingering close() */
 					sk->state_change(sk);
-				} else {
+				else {
 					int tmo;
 
 					if (tp->linger2 < 0 ||
diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
--- a/net/ipv4/tcp_ipv4.c	Sun May 25 19:42:46 2003
+++ b/net/ipv4/tcp_ipv4.c	Wed May 28 19:10:55 2003
@@ -509,7 +509,7 @@
 
 	/* Must check for a TIME_WAIT'er before going to listener hash. */
 	for (sk = (head + tcp_ehash_size)->chain; sk; sk = sk->next)
-		if (TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
+		if (TCP_IPV4_TW_MATCH(sk, acookie, saddr, daddr, ports, dif))
 			goto hit;
 out:
 	read_unlock(&head->lock);
@@ -570,7 +570,7 @@
 	     skp = &sk2->next) {
 		tw = (struct tcp_tw_bucket *)sk2;
 
-		if (TCP_IPV4_MATCH(sk2, acookie, saddr, daddr, ports, dif)) {
+		if (TCP_IPV4_TW_MATCH(sk2, acookie, saddr, daddr, ports, dif)) {
 			struct tcp_opt *tp = tcp_sk(sk);
 
 			/* With PAWS, it is safe from the viewpoint
diff -Nru a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
--- a/net/ipv4/tcp_minisocks.c	Thu May 22 23:51:06 2003
+++ b/net/ipv4/tcp_minisocks.c	Wed May 28 01:07:02 2003
@@ -667,7 +667,7 @@
 		newsk->wmem_queued = 0;
 		newsk->forward_alloc = 0;
 
-		__clear_bit(SOCK_DONE, &newsk->flags);
+		sock_reset_flag(newsk, SOCK_DONE);
 		newsk->userlocks = sk->userlocks & ~SOCK_BINDPORT_LOCK;
 		newsk->backlog.head = newsk->backlog.tail = NULL;
 		newsk->callback_lock = RW_LOCK_UNLOCKED;
@@ -752,8 +752,9 @@
 #endif
 		atomic_inc(&tcp_sockets_allocated);
 
-		if (test_bit(SOCK_KEEPOPEN, &newsk->flags))
-			tcp_reset_keepalive_timer(newsk, keepalive_time_when(newtp));
+		if (sock_flag(newsk, SOCK_KEEPOPEN))
+			tcp_reset_keepalive_timer(newsk,
+						  keepalive_time_when(newtp));
 		newsk->socket = NULL;
 		newsk->sleep = NULL;
 		newsk->owner = NULL;
diff -Nru a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
--- a/net/ipv4/tcp_output.c	Tue Apr 29 02:29:48 2003
+++ b/net/ipv4/tcp_output.c	Wed May 28 01:07:02 2003
@@ -1276,7 +1276,7 @@
 	tp->rcv_ssthresh = tp->rcv_wnd;
 
 	sk->err = 0;
-	__clear_bit(SOCK_DONE, &sk->flags);
+	sock_reset_flag(sk, SOCK_DONE);
 	tp->snd_wnd = 0;
 	tcp_init_wl(tp, tp->write_seq, 0);
 	tp->snd_una = tp->write_seq;
diff -Nru a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
--- a/net/ipv4/tcp_timer.c	Mon Mar  3 04:56:53 2003
+++ b/net/ipv4/tcp_timer.c	Wed May 28 01:07:02 2003
@@ -189,7 +189,7 @@
 		}
 
 		retry_until = sysctl_tcp_retries2;
-		if (test_bit(SOCK_DEAD, &sk->flags)) {
+		if (sock_flag(sk, SOCK_DEAD)) {
 			int alive = (tp->rto < TCP_RTO_MAX);
  
 			retry_until = tcp_orphan_retries(sk, alive);
@@ -297,7 +297,7 @@
 	 */
 	max_probes = sysctl_tcp_retries2;
 
-	if (test_bit(SOCK_DEAD, &sk->flags)) {
+	if (sock_flag(sk, SOCK_DEAD)) {
 		int alive = ((tp->rto<<tp->backoff) < TCP_RTO_MAX);
  
 		max_probes = tcp_orphan_retries(sk, alive);
@@ -327,7 +327,7 @@
 
 	BUG_TRAP(!skb_queue_empty(&sk->write_queue));
 
-	if (tp->snd_wnd == 0 && !test_bit(SOCK_DEAD, &sk->flags) &&
+	if (!tp->snd_wnd && !sock_flag(sk, SOCK_DEAD) &&
 	    !((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV))) {
 		/* Receiver dastardly shrinks window. Our retransmits
 		 * become zero probes, but we should not timeout this
@@ -571,7 +571,7 @@
 	if ((1<<sk->state)&(TCPF_CLOSE|TCPF_LISTEN))
 		return;
 
-	if (val && !test_bit(SOCK_KEEPOPEN, &sk->flags))
+	if (val && !sock_flag(sk, SOCK_KEEPOPEN))
 		tcp_reset_keepalive_timer(sk, keepalive_time_when(tcp_sk(sk)));
 	else if (!val)
 		tcp_delete_keepalive_timer(sk);
@@ -597,7 +597,7 @@
 		goto out;
 	}
 
-	if (sk->state == TCP_FIN_WAIT2 && test_bit(SOCK_DEAD, &sk->flags)) {
+	if (sk->state == TCP_FIN_WAIT2 && sock_flag(sk, SOCK_DEAD)) {
 		if (tp->linger2 >= 0) {
 			int tmo = tcp_fin_time(tp) - TCP_TIMEWAIT_LEN;
 
@@ -610,7 +610,7 @@
 		goto death;
 	}
 
-	if (!test_bit(SOCK_KEEPOPEN, &sk->flags) || sk->state == TCP_CLOSE)
+	if (!sock_flag(sk, SOCK_KEEPOPEN) || sk->state == TCP_CLOSE)
 		goto out;
 
 	elapsed = keepalive_time_when(tp);
diff -Nru a/net/ipv4/udp.c b/net/ipv4/udp.c
--- a/net/ipv4/udp.c	Sun May 25 19:40:16 2003
+++ b/net/ipv4/udp.c	Wed May 28 01:07:02 2003
@@ -609,8 +609,8 @@
 			goto out;
 
 		err = -EACCES;
-		if (rt->rt_flags&RTCF_BROADCAST &&
-				!test_bit(SOCK_BROADCAST, &sk->flags))
+		if ((rt->rt_flags & RTCF_BROADCAST) &&
+		    !sock_flag(sk, SOCK_BROADCAST))
 			goto out;
 		if (connected)
 			sk_dst_set(sk, dst_clone(&rt->u.dst));
@@ -891,8 +891,7 @@
 			       inet->sport, usin->sin_port, sk);
 	if (err)
 		return err;
-	if ((rt->rt_flags&RTCF_BROADCAST) &&
-			!test_bit(SOCK_BROADCAST, &sk->flags)) {
+	if ((rt->rt_flags & RTCF_BROADCAST) && !sock_flag(sk, SOCK_BROADCAST)) {
 		ip_rt_put(rt);
 		return -EACCES;
 	}
diff -Nru a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c
--- a/net/ipv4/xfrm4_tunnel.c	Thu May 22 19:22:14 2003
+++ b/net/ipv4/xfrm4_tunnel.c	Mon May 26 16:26:22 2003
@@ -215,6 +215,7 @@
 
 static struct xfrm_type ipip_type = {
 	.description	= "IPIP",
+	.owner		= THIS_MODULE,
 	.proto	     	= IPPROTO_IPIP,
 	.init_state	= ipip_init_state,
 	.destructor	= ipip_destroy,
@@ -229,7 +230,6 @@
 
 static int __init ipip_init(void)
 {
-	ipip_type.owner = THIS_MODULE;
 	if (xfrm_register_type(&ipip_type, AF_INET) < 0) {
 		printk(KERN_INFO "ipip init: can't add xfrm type\n");
 		return -EAGAIN;
diff -Nru a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
--- a/net/ipv6/addrconf.c	Mon May 19 23:49:42 2003
+++ b/net/ipv6/addrconf.c	Mon May 26 16:27:50 2003
@@ -33,6 +33,8 @@
  *	Yuji SEKIYA @USAGI		:	Don't assign a same IPv6
  *						address on a same interface.
  *	YOSHIFUJI Hideaki @USAGI	:	ARCnet support
+ *	YOSHIFUJI Hideaki @USAGI	:	convert /proc/net/if_inet6 to
+ *						seq_file.
  */
 
 #include <linux/config.h>
@@ -76,6 +78,9 @@
 
 #include <asm/uaccess.h>
 
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
 #define IPV6_MAX_ADDRESSES 16
 
 /* Set to 3 to get tracing... */
@@ -2090,57 +2095,141 @@
 }
 
 #ifdef CONFIG_PROC_FS
-static int iface_proc_info(char *buffer, char **start, off_t offset,
-			   int length)
+struct if6_iter_state {
+	int bucket;
+};
+
+static inline struct inet6_ifaddr *if6_get_bucket(struct seq_file *seq, loff_t *pos)
 {
-	struct inet6_ifaddr *ifp;
 	int i;
-	int len = 0;
-	off_t pos=0;
-	off_t begin=0;
+	struct inet6_ifaddr *ifa = NULL;
+	loff_t l = *pos;
+	struct if6_iter_state *state = seq->private;
+
+	for (; state->bucket < IN6_ADDR_HSIZE; ++state->bucket)
+		for (i = 0, ifa = inet6_addr_lst[state->bucket]; ifa; ++i, ifa=ifa->lst_next) {
+			if (l--)
+				continue;
+			*pos = i;
+			goto out;
+		}
+out:
+	return ifa;
+}
 
-	for (i=0; i < IN6_ADDR_HSIZE; i++) {
-		read_lock_bh(&addrconf_hash_lock);
-		for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {
-			int j;
+static void *if6_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	read_lock_bh(&addrconf_hash_lock);
+	return *pos ? if6_get_bucket(seq, pos) : (void *)1;
+}
 
-			for (j=0; j<16; j++) {
-				sprintf(buffer + len, "%02x",
-					ifp->addr.s6_addr[j]);
-				len += 2;
-			}
+static void *if6_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct inet6_ifaddr *ifa;
+	struct if6_iter_state *state;
 
-			len += sprintf(buffer + len,
-				       " %02x %02x %02x %02x %8s\n",
-				       ifp->idev->dev->ifindex,
-				       ifp->prefix_len,
-				       ifp->scope,
-				       ifp->flags,
-				       ifp->idev->dev->name);
-			pos=begin+len;
-			if(pos<offset) {
-				len=0;
-				begin=pos;
-			}
-			if(pos>offset+length) {
-				read_unlock_bh(&addrconf_hash_lock);
-				goto done;
-			}
-		}
-		read_unlock_bh(&addrconf_hash_lock);
+	if (v == (void *)1) {
+		ifa = if6_get_bucket(seq, pos);
+		goto out;
 	}
 
-done:
+	state = seq->private;
+
+	ifa = v;
+	ifa = ifa->lst_next;
+	if (ifa)
+		goto out;
+
+	if (++state->bucket >= IN6_ADDR_HSIZE)
+		goto out;
 
-	*start=buffer+(offset-begin);
-	len-=(offset-begin);
-	if(len>length)
-		len=length;
-	if(len<0)
-		len=0;
-	return len;
+	*pos = 0;
+	ifa = if6_get_bucket(seq, pos);
+out:
+	++*pos;
+	return ifa;
 }
 
+static inline void if6_iface_seq_show(struct seq_file *seq, struct inet6_ifaddr *ifp)
+{
+	seq_printf(seq,
+		   "%04x%04x%04x%04x%04x%04x%04x%04x %02x %02x %02x %02x %8s\n",
+		   NIP6(ifp->addr),
+		   ifp->idev->dev->ifindex,
+		   ifp->prefix_len,
+		   ifp->scope,
+		   ifp->flags,
+		   ifp->idev->dev->name);
+}
+
+static int if6_seq_show(struct seq_file *seq, void *v)
+{
+	if (v == (void *)1)
+		return 0;
+	else
+		if6_iface_seq_show(seq, v);
+	return 0;
+}
+
+static void if6_seq_stop(struct seq_file *seq, void *v)
+{
+	read_unlock_bh(&addrconf_hash_lock);
+}
+
+static struct seq_operations if6_seq_ops = {
+	.start	= if6_seq_start,
+	.next	= if6_seq_next,
+	.show	= if6_seq_show,
+	.stop	= if6_seq_stop,
+};
+
+static int if6_seq_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq;
+	int rc = -ENOMEM;
+	struct if6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+	if (!s)
+		goto out;
+	memset(s, 0, sizeof(*s));
+
+	rc = seq_open(file, &if6_seq_ops);
+	if (rc)
+		goto out_kfree;
+
+	seq = file->private_data;
+	seq->private = s;
+out:
+	return rc;
+out_kfree:
+	kfree(s);
+	goto out;
+}
+
+static struct file_operations if6_fops = {
+	.owner		= THIS_MODULE,
+	.open		= if6_seq_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release_private,
+};
+
+int __init if6_proc_init(void)
+{
+	struct proc_dir_entry *p;
+	int rc = 0;
+
+	p = create_proc_entry("if_inet6", S_IRUGO, proc_net);
+	if (p)
+		p->proc_fops = &if6_fops;
+	else
+		rc = -ENOMEM;
+	return rc;
+}
+void if6_proc_exit(void)
+{
+	proc_net_remove("if_inet6");
+}
 #endif	/* CONFIG_PROC_FS */
 
 /*
@@ -2727,10 +2816,6 @@
 	rtnl_unlock();
 #endif
 
-#ifdef CONFIG_PROC_FS
-	proc_net_create("if_inet6", 0, iface_proc_info);
-#endif
-	
 	addrconf_verify(0);
 	rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;
 #ifdef CONFIG_SYSCTL
diff -Nru a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
--- a/net/ipv6/af_inet6.c	Sun May 25 19:43:48 2003
+++ b/net/ipv6/af_inet6.c	Mon May 26 16:30:59 2003
@@ -75,18 +75,16 @@
 
 #ifdef CONFIG_PROC_FS
 extern int raw6_proc_init(void);
-extern int raw6_proc_exit(void);
-
+extern void raw6_proc_exit(void);
 extern int tcp6_proc_init(void);
 extern void tcp6_proc_exit(void);
-
 extern int udp6_proc_init(void);
 extern void udp6_proc_exit(void);
-
 extern int ipv6_misc_proc_init(void);
-extern int ipv6_misc_proc_exit(void);
-
+extern void ipv6_misc_proc_exit(void);
 extern int anycast6_get_info(char *, char **, off_t, int);
+extern int if6_proc_init(void);
+extern void if6_proc_exit(void);
 #endif
 
 #ifdef CONFIG_SYSCTL
@@ -799,6 +797,8 @@
 
 	if (!proc_net_create("anycast6", 0, anycast6_get_info))
 		goto proc_anycast6_fail;
+	if (if6_proc_init())
+		goto proc_if6_fail;
 #endif
 	ipv6_netdev_notif_init();
 	ipv6_packet_init();
@@ -820,6 +820,8 @@
 	return 0;
 
 #ifdef CONFIG_PROC_FS
+proc_if6_fail:
+	proc_net_remove("anycast6");
 proc_anycast6_fail:
 	ipv6_misc_proc_exit();
 proc_misc6_fail:
@@ -852,11 +854,12 @@
 	/* First of all disallow new sockets creation. */
 	sock_unregister(PF_INET6);
 #ifdef CONFIG_PROC_FS
-	raw6_proc_exit();
-	proc_net_remove("tcp6");
-	proc_net_remove("udp6");
-	ipv6_misc_proc_exit();
-	proc_net_remove("anycast6");
+	if6_proc_exit();
+ 	proc_net_remove("anycast6");
+ 	ipv6_misc_proc_exit();
+ 	udp6_proc_exit();
+ 	tcp6_proc_exit();
+ 	raw6_proc_exit();
 #endif
 	/* Cleanup code parts. */
 	sit_cleanup();
diff -Nru a/net/ipv6/icmp.c b/net/ipv6/icmp.c
--- a/net/ipv6/icmp.c	Thu May 22 18:38:15 2003
+++ b/net/ipv6/icmp.c	Tue May 27 00:20:31 2003
@@ -263,7 +263,7 @@
 void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, 
 		 struct net_device *dev)
 {
-	struct inet6_dev *idev;
+	struct inet6_dev *idev = NULL;
 	struct ipv6hdr *hdr = skb->nh.ipv6h;
 	struct sock *sk = icmpv6_socket->sk;
 	struct ipv6_pinfo *np = inet6_sk(sk);
@@ -384,7 +384,7 @@
 				hlimit, NULL, &fl, (struct rt6_info*)dst, MSG_DONTWAIT);
 	if (err) {
 		ip6_flush_pending_frames(sk);
-		goto out;
+		goto out_put;
 	}
 	err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, len + sizeof(struct icmp6hdr));
 	__skb_push(skb, plen);
@@ -393,6 +393,7 @@
 		ICMP6_INC_STATS_OFFSET_BH(idev, Icmp6OutDestUnreachs, type - ICMPV6_DEST_UNREACH);
 	ICMP6_INC_STATS_BH(idev, Icmp6OutMsgs);
 
+out_put:
 	if (likely(idev != NULL))
 		in6_dev_put(idev);
 out:
@@ -455,13 +456,14 @@
 
 	if (err) {
 		ip6_flush_pending_frames(sk);
-		goto out;
+		goto out_put;
 	}
 	err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, skb->len + sizeof(struct icmp6hdr));
 
         ICMP6_INC_STATS_BH(idev, Icmp6OutEchoReplies);
         ICMP6_INC_STATS_BH(idev, Icmp6OutMsgs);
 
+out_put: 
 	if (likely(idev != NULL))
 		in6_dev_put(idev);
 out: 
diff -Nru a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
--- a/net/ipv6/ndisc.c	Thu May 22 18:38:15 2003
+++ b/net/ipv6/ndisc.c	Wed May 28 01:57:36 2003
@@ -389,9 +389,14 @@
 	return -EINVAL;
 }
 
-static inline void ndisc_rt_init(struct rt6_info *rt, struct net_device *dev,
-			    struct neighbour *neigh)
+static inline struct dst_entry *ndisc_dst_alloc(struct net_device *dev, 
+						struct neighbour *neigh)
 {
+	struct rt6_info *rt = ip6_dst_alloc();
+
+	if (unlikely(rt == NULL))
+		goto out;
+
 	rt->rt6i_dev	  = dev;
 	rt->rt6i_nexthop  = neigh;
 	rt->rt6i_expires  = 0;
@@ -399,6 +404,8 @@
 	rt->rt6i_metric   = 0;
 	rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255;
 	rt->u.dst.output  = ndisc_output;
+out:
+	return (struct dst_entry *)rt;
 }
 
 static inline void ndisc_flow_init(struct flowi *fl, u8 type,
@@ -420,7 +427,6 @@
 	struct inet6_ifaddr *ifp;
 	struct inet6_dev *idev;
 	struct flowi fl;
-	struct rt6_info *rt = NULL;
 	struct dst_entry* dst;
         struct sock *sk = ndisc_socket->sk;
 	struct in6_addr *src_addr;
@@ -431,27 +437,22 @@
 
 	len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
 
-	rt = ip6_dst_alloc();
-	if (!rt) 
-		return;
-
 	/* for anycast or proxy, solicited_addr != src_addr */
 	ifp = ipv6_get_ifaddr(solicited_addr, dev);
  	if (ifp) {
 		src_addr = solicited_addr;
 		in6_ifa_put(ifp);
 	} else {
-		if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr, 0)) {
-			dst_free(dst);
+		if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr, 0))
 			return;
-		}
 		src_addr = &tmpaddr;
 	}
 
 	ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr);
-	ndisc_rt_init(rt, dev, neigh);	
 
-	dst = (struct dst_entry*)rt;
+	dst = ndisc_dst_alloc(dev, neigh);	
+	if (!dst)
+		return;
 
 	err = xfrm_lookup(&dst, &fl, NULL, 0);
 	if (err < 0) {
@@ -518,7 +519,6 @@
 		   struct in6_addr *daddr, struct in6_addr *saddr) 
 {
 	struct flowi fl;
-	struct rt6_info *rt = NULL;
 	struct dst_entry* dst;
 	struct inet6_dev *idev;
         struct sock *sk = ndisc_socket->sk;
@@ -535,14 +535,11 @@
 		saddr = &addr_buf;
 	}
 
-	rt = ip6_dst_alloc();
-	if (!rt) 
-		return;
-
 	ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr);
-	ndisc_rt_init(rt, dev, neigh);	
 
-	dst = (struct dst_entry*)rt;
+	dst = ndisc_dst_alloc(dev, neigh);
+	if (!dst)
+		return;
 	dst_clone(dst);
 
 	err = xfrm_lookup(&dst, &fl, NULL, 0);
@@ -601,7 +598,6 @@
 		   struct in6_addr *daddr)
 {
 	struct flowi fl;
-	struct rt6_info *rt = NULL;
 	struct dst_entry* dst;
 	struct inet6_dev *idev;
 	struct sock *sk = ndisc_socket->sk;
@@ -611,14 +607,11 @@
         int len;
 	int err;
 
-	rt = ip6_dst_alloc();
-	if (!rt) 
-		return;
-
 	ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr);
-	ndisc_rt_init(rt, dev, NULL);
 
-	dst = (struct dst_entry*)rt;
+	dst = ndisc_dst_alloc(dev, NULL);
+	if (!dst)
+		return;
 	dst_clone(dst);
 
 	err = xfrm_lookup(&dst, &fl, NULL, 0);
@@ -1299,12 +1292,6 @@
 	int hlen;
 
 	dev = skb->dev;
-	rt = rt6_lookup(&skb->nh.ipv6h->saddr, NULL, dev->ifindex, 1);
-
-	if (rt == NULL)
-		return;
-
-	dst = (struct dst_entry*)rt;
 
 	if (ipv6_get_lladdr(dev, &saddr_buf)) {
  		ND_PRINTK1("redirect: no link_local addr for dev\n");
@@ -1313,7 +1300,12 @@
 
 	ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr);
 
+	rt = rt6_lookup(&skb->nh.ipv6h->saddr, NULL, dev->ifindex, 1);
+	if (rt == NULL)
+		return;
+	dst = &rt->u.dst;
 	dst_clone(dst);
+
 	err = xfrm_lookup(&dst, &fl, NULL, 0);
 	if (err) {
 		dst_release(dst);
diff -Nru a/net/ipv6/proc.c b/net/ipv6/proc.c
--- a/net/ipv6/proc.c	Thu May 22 19:11:15 2003
+++ b/net/ipv6/proc.c	Mon May 26 16:30:59 2003
@@ -299,11 +299,10 @@
 	goto out;
 }
 
-int ipv6_misc_proc_exit(void)
+void ipv6_misc_proc_exit(void)
 {
 	proc_net_remove("sockstat6");
 	proc_net_remove("dev_snmp6");
 	proc_net_remove("snmp6");
-	return 0;
 }
 
diff -Nru a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
--- a/net/ipv6/reassembly.c	Wed May 14 20:21:58 2003
+++ b/net/ipv6/reassembly.c	Thu May 29 03:12:27 2003
@@ -24,6 +24,9 @@
  *	Alexey Kuznetsov	SMP races, threading, cleanup.
  *	Patrick McHardy		LRU queue of frag heads for evictor.
  *	Mitsuru KANDA @USAGI	Register inet6_protocol{}.
+ *	David Stevens and
+ *	YOSHIFUJI,H. @USAGI	Always remove fragment header to
+ *				calculate ICV correctly.
  */
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -38,6 +41,8 @@
 #include <linux/in6.h>
 #include <linux/ipv6.h>
 #include <linux/icmpv6.h>
+#include <linux/random.h>
+#include <linux/jhash.h>
 
 #include <net/sock.h>
 #include <net/snmp.h>
@@ -49,10 +54,10 @@
 #include <net/ndisc.h>
 #include <net/addrconf.h>
 
-static int sysctl_ip6frag_high_thresh = 256*1024;
-static int sysctl_ip6frag_low_thresh = 192*1024;
+int sysctl_ip6frag_high_thresh = 256*1024;
+int sysctl_ip6frag_low_thresh = 192*1024;
 
-static int sysctl_ip6frag_time = IPV6_FRAG_TIMEOUT;
+int sysctl_ip6frag_time = IPV6_FRAG_TIMEOUT;
 
 struct ip6frag_skb_cb
 {
@@ -99,6 +104,7 @@
 
 static struct frag_queue *ip6_frag_hash[IP6Q_HASHSZ];
 static rwlock_t ip6_frag_lock = RW_LOCK_UNLOCKED;
+static u32 ip6_frag_hash_rnd;
 static LIST_HEAD(ip6_frag_lru_list);
 int ip6_frag_nqueues = 0;
 
@@ -118,16 +124,73 @@
 	write_unlock(&ip6_frag_lock);
 }
 
-static __inline__ unsigned int ip6qhashfn(u32 id, struct in6_addr *saddr,
-					  struct in6_addr *daddr)
+static unsigned int ip6qhashfn(u32 id, struct in6_addr *saddr,
+			       struct in6_addr *daddr)
 {
-	unsigned int h = saddr->s6_addr32[3] ^ daddr->s6_addr32[3] ^ id;
+	u32 a, b, c;
 
-	h ^= (h>>16);
-	h ^= (h>>8);
-	return h & (IP6Q_HASHSZ - 1);
+	a = saddr->s6_addr32[0];
+	b = saddr->s6_addr32[1];
+	c = saddr->s6_addr32[2];
+
+	a += JHASH_GOLDEN_RATIO;
+	b += JHASH_GOLDEN_RATIO;
+	c += ip6_frag_hash_rnd;
+	__jhash_mix(a, b, c);
+
+	a += saddr->s6_addr32[3];
+	b += daddr->s6_addr32[0];
+	c += daddr->s6_addr32[1];
+	__jhash_mix(a, b, c);
+
+	a += daddr->s6_addr32[2];
+	b += daddr->s6_addr32[3];
+	c += id;
+	__jhash_mix(a, b, c);
+
+	return c & (IP6Q_HASHSZ - 1);
 }
 
+static struct timer_list ip6_frag_secret_timer;
+int sysctl_ip6frag_secret_interval = 10 * 60 * HZ;
+
+static void ip6_frag_secret_rebuild(unsigned long dummy)
+{
+	unsigned long now = jiffies;
+	int i;
+
+	write_lock(&ip6_frag_lock);
+	get_random_bytes(&ip6_frag_hash_rnd, sizeof(u32));
+	for (i = 0; i < IP6Q_HASHSZ; i++) {
+		struct frag_queue *q;
+
+		q = ip6_frag_hash[i];
+		while (q) {
+			struct frag_queue *next = q->next;
+			unsigned int hval = ip6qhashfn(q->id,
+						       &q->saddr,
+						       &q->daddr);
+
+			if (hval != i) {
+				/* Unlink. */
+				if (q->next)
+					q->next->pprev = q->pprev;
+				*q->pprev = q->next;
+
+				/* Relink to new hash chain. */
+				if ((q->next = ip6_frag_hash[hval]) != NULL)
+					q->next->pprev = &q->next;
+				ip6_frag_hash[hval] = q;
+				q->pprev = &ip6_frag_hash[hval];
+			}
+
+			q = next;
+		}
+	}
+	write_unlock(&ip6_frag_lock);
+
+	mod_timer(&ip6_frag_secret_timer, now + sysctl_ip6frag_secret_interval);
+}
 
 atomic_t ip6_frag_mem = ATOMIC_INIT(0);
 
@@ -524,7 +587,6 @@
 			  struct net_device *dev)
 {
 	struct sk_buff *fp, *head = fq->fragments;
-	int    remove_fraghdr = 0;
 	int    payload_len;
 	unsigned int nhoff;
 
@@ -537,12 +599,8 @@
 	payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len;
 	nhoff = head->h.raw - head->nh.raw;
 
-	if (payload_len > 65535) {
-		payload_len -= 8;
-		if (payload_len > 65535)
-			goto out_oversize;
-		remove_fraghdr = 1;
-	}
+	if (payload_len > 65535 + 8)
+		goto out_oversize;
 
 	/* Head of list must not be cloned. */
 	if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
@@ -571,18 +629,13 @@
 		atomic_add(clone->truesize, &ip6_frag_mem);
 	}
 
-	/* Normally we do not remove frag header from datagram, but
-	 * we have to do this and to relocate header, when payload
-	 * is > 65535-8. */
-	if (remove_fraghdr) {
-		nhoff = fq->nhoffset;
-		head->nh.raw[nhoff] = head->h.raw[0];
-		memmove(head->head+8, head->head, (head->data-head->head)-8);
-		head->mac.raw += 8;
-		head->nh.raw += 8;
-	} else {
-		((struct frag_hdr*)head->h.raw)->frag_off = 0;
-	}
+	/* We have to remove fragment header from datagram and to relocate
+	 * header in order to calculate ICV correctly. */
+	nhoff = fq->nhoffset;
+	head->nh.raw[nhoff] = head->h.raw[0];
+	memmove(head->head+8, head->head, (head->data-head->head)-8);
+	head->mac.raw += 8;
+	head->nh.raw += 8;
 
 	skb_shinfo(head)->frag_list = head->next;
 	head->h.raw = head->data;
@@ -696,4 +749,12 @@
 {
 	if (inet6_add_protocol(&frag_protocol, IPPROTO_FRAGMENT) < 0)
 		printk(KERN_ERR "ipv6_frag_init: Could not register protocol\n");
+
+	ip6_frag_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
+				   (jiffies ^ (jiffies >> 6)));
+
+	init_timer(&ip6_frag_secret_timer);
+	ip6_frag_secret_timer.function = ip6_frag_secret_rebuild;
+	ip6_frag_secret_timer.expires = jiffies + sysctl_ip6frag_secret_interval;
+	add_timer(&ip6_frag_secret_timer);
 }
diff -Nru a/net/ipv6/route.c b/net/ipv6/route.c
--- a/net/ipv6/route.c	Thu May 22 19:11:15 2003
+++ b/net/ipv6/route.c	Thu May 29 02:46:26 2003
@@ -253,13 +253,15 @@
 				}
 			}
 			for (sprt = rt;
-			     !match && sprt && sprt != rt6_dflt_pointer; 
+			     !match && sprt;
 			     sprt = sprt->u.next) {
 				if (sprt->u.dst.obsolete <= 0 &&
 				    sprt->u.dst.error == 0) {
 					match = sprt;
 					break;
 				}
+				if (sprt == rt6_dflt_pointer)
+					break;
 			}
 		}
 	}
diff -Nru a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
--- a/net/ipv6/sysctl_net_ipv6.c	Tue Feb 11 21:47:02 2003
+++ b/net/ipv6/sysctl_net_ipv6.c	Thu May 29 03:12:27 2003
@@ -42,6 +42,40 @@
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec
 	},
+	{
+		.ctl_name	= NET_IPV6_IP6FRAG_HIGH_THRESH,
+		.procname	= "ip6frag_high_thresh",
+		.data		= &sysctl_ip6frag_high_thresh,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
+	{
+		.ctl_name	= NET_IPV6_IP6FRAG_LOW_THRESH,
+		.procname	= "ip6frag_low_thresh",
+		.data		= &sysctl_ip6frag_low_thresh,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
+	{
+		.ctl_name	= NET_IPV6_IP6FRAG_TIME,
+		.procname	= "ip6frag_time",
+		.data		= &sysctl_ip6frag_time,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+		.strategy	= &sysctl_jiffies,
+	},
+	{
+		.ctl_name	= NET_IPV6_IP6FRAG_SECRET_INTERVAL,
+		.procname	= "ip6frag_secret_interval",
+		.data		= &sysctl_ip6frag_secret_interval,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+		.strategy	= &sysctl_jiffies
+	},
 	{ .ctl_name = 0 }
 };
 
diff -Nru a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
--- a/net/ipv6/tcp_ipv6.c	Sun May 25 19:43:48 2003
+++ b/net/ipv6/tcp_ipv6.c	Tue May 27 22:16:52 2003
@@ -394,9 +394,22 @@
 
 static u32 tcp_v6_synq_hash(struct in6_addr *raddr, u16 rport, u32 rnd)
 {
-	return (jhash_3words(raddr->s6_addr32[0] ^ raddr->s6_addr32[1],
-	                     raddr->s6_addr32[2] ^ raddr->s6_addr32[3],
-	                     (u32) rport, rnd) & (TCP_SYNQ_HSIZE - 1));
+	u32 a, b, c;
+
+	a = raddr->s6_addr32[0];
+	b = raddr->s6_addr32[1];
+	c = raddr->s6_addr32[2];
+
+	a += JHASH_GOLDEN_RATIO;
+	b += JHASH_GOLDEN_RATIO;
+	c += rnd;
+	__jhash_mix(a, b, c);
+
+	a += raddr->s6_addr32[3];
+	b += (u32) rport;
+	__jhash_mix(a, b, c);
+
+	return c & (TCP_SYNQ_HSIZE - 1);
 }
 
 static struct open_request *tcp_v6_search_req(struct tcp_opt *tp,
diff -Nru a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
--- a/net/ipx/af_ipx.c	Fri May 16 11:47:00 2003
+++ b/net/ipx/af_ipx.c	Wed May 28 01:07:02 2003
@@ -1401,10 +1401,10 @@
 	if (!sk)
 		goto out;
 
-	if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (!sock_flag(sk, SOCK_DEAD))
 		sk->state_change(sk);
 
-	__set_bit(SOCK_DEAD, &sk->flags);
+	sock_set_flag(sk, SOCK_DEAD);
 	sock->sk = NULL;
 	ipx_destroy_socket(sk);
 out:
diff -Nru a/net/irda/af_irda.c b/net/irda/af_irda.c
--- a/net/irda/af_irda.c	Mon May 12 09:53:17 2003
+++ b/net/irda/af_irda.c	Wed May 28 01:07:02 2003
@@ -133,13 +133,14 @@
 	}
 
 	/* Prevent race conditions with irda_release() and irda_shutdown() */
-	if ((!test_bit(SOCK_DEAD, &sk->flags)) && (sk->state != TCP_CLOSE)) {
+	if (!sock_flag(sk, SOCK_DEAD) && sk->state != TCP_CLOSE) {
 		sk->state     = TCP_CLOSE;
 		sk->err       = ECONNRESET;
 		sk->shutdown |= SEND_SHUTDOWN;
 
 		sk->state_change(sk);
-                __set_bit(SOCK_DEAD, &sk->flags);	/* Uh-oh... Should use sock_orphan ? */
+		/* Uh-oh... Should use sock_orphan ? */
+                sock_set_flag(sk, SOCK_DEAD);
 
 		/* Close our TSAP.
 		 * If we leave it open, IrLMP put it back into the list of
diff -Nru a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
--- a/net/irda/ircomm/ircomm_tty.c	Sun May 25 19:36:24 2003
+++ b/net/irda/ircomm/ircomm_tty.c	Mon May 26 15:29:08 2003
@@ -248,48 +248,20 @@
 
 	tty = self->tty;
 
-	if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) {
-		/* this is a callout device */
-		/* just verify that normal device is not in use */
-		if (self->flags & ASYNC_NORMAL_ACTIVE)
-			return -EBUSY;
-		if ((self->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (self->flags & ASYNC_SESSION_LOCKOUT) &&
-		    (self->session != current->session))
-			return -EBUSY;
-		if ((self->flags & ASYNC_CALLOUT_ACTIVE) &&
-		    (self->flags & ASYNC_PGRP_LOCKOUT) &&
-		    (self->pgrp != current->pgrp))
-			return -EBUSY;
-		self->flags |= ASYNC_CALLOUT_ACTIVE;
-		return 0;
-	}
-	
 	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 */	
 	if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
 		/* nonblock mode is set or port is not enabled */
-		/* just verify that callout device is not active */
-		if (self->flags & ASYNC_CALLOUT_ACTIVE)
-			return -EBUSY;
 		self->flags |= ASYNC_NORMAL_ACTIVE;
-
 		IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __FUNCTION__ );
 		return 0;
 	}
 
-	if (self->flags & ASYNC_CALLOUT_ACTIVE) {
-		if (self->normal_termios.c_cflag & CLOCAL) {
-			IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __FUNCTION__ );
-			do_clocal = 1;
-		}
-	} else {
-		if (tty->termios->c_cflag & CLOCAL) {
-			IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __FUNCTION__ );
-			do_clocal = 1;
-		}
+	if (tty->termios->c_cflag & CLOCAL) {
+		IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __FUNCTION__ );
+		do_clocal = 1;
 	}
 	
 	/* Wait for carrier detect and the line to become
@@ -315,8 +287,7 @@
 	self->blocked_open++;
 	
 	while (1) {
-		if (!(self->flags & ASYNC_CALLOUT_ACTIVE) &&
- 		    (tty->termios->c_cflag & CBAUD)) {
+		if (tty->termios->c_cflag & CBAUD) {
 			/* Here, we use to lock those two guys, but
 			 * as ircomm_param_request() does it itself,
 			 * I don't see the point (and I see the deadlock).
@@ -339,8 +310,7 @@
 		 * specified, we cannot return before the IrCOMM link is
 		 * ready 
 		 */
- 		if (!(self->flags & ASYNC_CALLOUT_ACTIVE) &&
- 		    !(self->flags & ASYNC_CLOSING) &&
+ 		if (!(self->flags & ASYNC_CLOSING) &&
  		    (do_clocal || (self->settings.dce & IRCOMM_CD)) &&
 		    self->state == IRCOMM_TTY_READY)
 		{
@@ -509,10 +479,6 @@
 
 		return ret;
 	}
-
-	self->session = current->session;
-	self->pgrp = current->pgrp;
-
 	return 0;
 }
 
@@ -605,8 +571,7 @@
 		wake_up_interruptible(&self->open_wait);
 	}
 
-	self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
-			 ASYNC_CLOSING);
+	self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&self->close_wait);
 
 	MOD_DEC_USE_COUNT;
@@ -1054,7 +1019,7 @@
 
 	/* I guess we need to lock here - Jean II */
 	spin_lock_irqsave(&self->spinlock, flags);
-	self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	self->flags &= ~ASYNC_NORMAL_ACTIVE;
 	self->tty = 0;
 	self->open_count = 0;
 	spin_unlock_irqrestore(&self->spinlock, flags);
@@ -1133,9 +1098,7 @@
 
 		if (status & IRCOMM_CD) {
 			wake_up_interruptible(&self->open_wait);
-		} else if (!((self->flags & ASYNC_CALLOUT_ACTIVE) &&
-			   (self->flags & ASYNC_CALLOUT_NOHUP))) 
-		{
+		} else {
 			IRDA_DEBUG(2, 
 				   "%s(), Doing serial hangup..\n", __FUNCTION__ );
 			if (tty)
@@ -1364,8 +1327,6 @@
 		ret += sprintf(buf+ret, "ASYNC_CLOSING|");
 	if (self->flags & ASYNC_NORMAL_ACTIVE)
 		ret += sprintf(buf+ret, "ASYNC_NORMAL_ACTIVE|");
-	if (self->flags & ASYNC_CALLOUT_ACTIVE)
-		ret += sprintf(buf+ret, "ASYNC_CALLOUT_ACTIVE|");
 	if (self->flags)
 		ret--; /* remove the last | */
 	ret += sprintf(buf+ret, "\n");
diff -Nru a/net/key/af_key.c b/net/key/af_key.c
--- a/net/key/af_key.c	Thu May 22 19:07:16 2003
+++ b/net/key/af_key.c	Wed May 28 01:07:02 2003
@@ -52,7 +52,7 @@
 {
 	skb_queue_purge(&sk->receive_queue);
 
-	if (!test_bit(SOCK_DEAD, &sk->flags)) {
+	if (!sock_flag(sk, SOCK_DEAD)) {
 		printk("Attempt to release alive pfkey socket: %p\n", sk);
 		return;
 	}
diff -Nru a/net/llc/llc_conn.c b/net/llc/llc_conn.c
--- a/net/llc/llc_conn.c	Tue Apr 29 22:38:37 2003
+++ b/net/llc/llc_conn.c	Wed May 28 01:07:02 2003
@@ -120,9 +120,9 @@
 			sk->shutdown       = SHUTDOWN_MASK;
 			sk->socket->state  = SS_UNCONNECTED;
 			sk->state          = TCP_CLOSE;
-			if (!test_bit(SOCK_DEAD, &sk->flags)) {
+			if (!sock_flag(sk, SOCK_DEAD)) {
 				sk->state_change(sk);
-				__set_bit(SOCK_DEAD, &sk->flags);
+				sock_set_flag(sk, SOCK_DEAD);
 			}
 		}
 		kfree_skb(skb);
diff -Nru a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
--- a/net/netlink/af_netlink.c	Sun May 25 19:34:11 2003
+++ b/net/netlink/af_netlink.c	Wed May 28 01:07:02 2003
@@ -90,7 +90,7 @@
 {
 	skb_queue_purge(&sk->receive_queue);
 
-	if (!test_bit(SOCK_DEAD, &sk->flags)) {
+	if (!sock_flag(sk, SOCK_DEAD)) {
 		printk("Freeing alive netlink socket %p\n", sk);
 		return;
 	}
@@ -457,8 +457,8 @@
 		add_wait_queue(&nlk->wait, &wait);
 
 		if ((atomic_read(&sk->rmem_alloc) > sk->rcvbuf ||
-		    test_bit(0, &nlk->state)) &&
-		    !test_bit(SOCK_DEAD, &sk->flags))
+		     test_bit(0, &nlk->state)) &&
+		    !sock_flag(sk, SOCK_DEAD))
 			timeo = schedule_timeout(timeo);
 
 		__set_current_state(TASK_RUNNING);
diff -Nru a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
--- a/net/netrom/af_netrom.c	Fri May  2 23:34:04 2003
+++ b/net/netrom/af_netrom.c	Wed May 28 01:07:02 2003
@@ -275,8 +275,9 @@
 	nr_clear_queues(sk);		/* Flush the queues */
 
 	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
-		if (skb->sk != sk) {			/* A pending connection */
-			__set_bit(SOCK_DEAD, &skb->sk->flags);	/* Queue the unaccepted socket for death */
+		if (skb->sk != sk) { /* A pending connection */
+			/* Queue the unaccepted socket for death */
+			sock_set_flag(skb->sk, SOCK_DEAD);
 			nr_start_heartbeat(skb->sk);
 			nr_sk(skb->sk)->state = NR_STATE_0;
 		}
@@ -535,8 +536,8 @@
 		sk->state    = TCP_CLOSE;
 		sk->shutdown |= SEND_SHUTDOWN;
 		sk->state_change(sk);
-		__set_bit(SOCK_DEAD, &sk->flags);
-		__set_bit(SOCK_DESTROY, &sk->flags);
+		sock_set_flag(sk, SOCK_DEAD);
+		sock_set_flag(sk, SOCK_DESTROY);
 		sk->socket   = NULL;
 		break;
 
@@ -950,7 +951,7 @@
 	nr_start_heartbeat(make);
 	nr_start_idletimer(make);
 
-	if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (!sock_flag(sk, SOCK_DEAD))
 		sk->data_ready(sk, skb->len);
 
 	return 1;
diff -Nru a/net/netrom/nr_in.c b/net/netrom/nr_in.c
--- a/net/netrom/nr_in.c	Mon Mar  3 04:56:53 2003
+++ b/net/netrom/nr_in.c	Wed May 28 01:07:02 2003
@@ -90,7 +90,7 @@
 		nr->n2count    = 0;
 		nr->window     = skb->data[20];
 		sk->state      = TCP_ESTABLISHED;
-		if (!test_bit(SOCK_DEAD, &sk->flags))
+		if (!sock_flag(sk, SOCK_DEAD))
 			sk->state_change(sk);
 		break;
 	}
diff -Nru a/net/netrom/nr_subr.c b/net/netrom/nr_subr.c
--- a/net/netrom/nr_subr.c	Mon Mar  3 04:56:53 2003
+++ b/net/netrom/nr_subr.c	Wed May 28 01:07:02 2003
@@ -276,8 +276,8 @@
 	sk->err       = reason;
 	sk->shutdown |= SEND_SHUTDOWN;
 
-	if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (!sock_flag(sk, SOCK_DEAD)) {
 		sk->state_change(sk);
-
-	__set_bit(SOCK_DEAD, &sk->flags);
+		sock_set_flag(sk, SOCK_DEAD);
+	}
 }
diff -Nru a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c
--- a/net/netrom/nr_timer.c	Mon Mar  3 04:56:53 2003
+++ b/net/netrom/nr_timer.c	Wed May 28 01:07:02 2003
@@ -141,9 +141,8 @@
 	case NR_STATE_0:
 		/* Magic here: If we listen() and a new link dies before it
 		   is accepted() it isn't 'dead' so doesn't get removed. */
-		if (test_bit(SOCK_DESTROY, &sk->flags) ||
-				(sk->state == TCP_LISTEN &&
-					test_bit(SOCK_DEAD, &sk->flags))) {
+		if (sock_flag(sk, SOCK_DESTROY) ||
+		    (sk->state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) {
 			nr_destroy_socket(sk);
 			return;
 		}
@@ -211,10 +210,10 @@
 	sk->err       = 0;
 	sk->shutdown |= SEND_SHUTDOWN;
 
-	if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (!sock_flag(sk, SOCK_DEAD)) {
 		sk->state_change(sk);
-
-	__set_bit(SOCK_DEAD, &sk->flags);
+		sock_set_flag(sk, SOCK_DEAD);
+	}
 	bh_unlock_sock(sk);
 }
 
diff -Nru a/net/netsyms.c b/net/netsyms.c
--- a/net/netsyms.c	Sun May 25 19:42:46 2003
+++ b/net/netsyms.c	Thu May 29 20:14:56 2003
@@ -609,8 +609,6 @@
 EXPORT_SYMBOL(dev_mc_upload);
 EXPORT_SYMBOL(__kill_fasync);
 
-EXPORT_SYMBOL(if_port_text);
-
 #ifdef CONFIG_HIPPI
 EXPORT_SYMBOL(hippi_type_trans);
 #endif
diff -Nru a/net/packet/af_packet.c b/net/packet/af_packet.c
--- a/net/packet/af_packet.c	Sun May 25 19:36:24 2003
+++ b/net/packet/af_packet.c	Wed May 28 01:07:02 2003
@@ -198,7 +198,7 @@
 	BUG_TRAP(atomic_read(&sk->rmem_alloc)==0);
 	BUG_TRAP(atomic_read(&sk->wmem_alloc)==0);
 
-	if (!test_bit(SOCK_DEAD, &sk->flags)) {
+	if (!sock_flag(sk, SOCK_DEAD)) {
 		printk("Attempt to release alive packet socket: %p\n", sk);
 		return;
 	}
@@ -844,7 +844,7 @@
 			po->running = 1;
 		} else {
 			sk->err = ENETDOWN;
-			if (!test_bit(SOCK_DEAD, &sk->flags))
+			if (!sock_flag(sk, SOCK_DEAD))
 				sk->error_report(sk);
 		}
 	} else {
@@ -1381,7 +1381,7 @@
 					__sock_put(sk);
 					po->running = 0;
 					sk->err = ENETDOWN;
-					if (!test_bit(SOCK_DEAD, &sk->flags))
+					if (!sock_flag(sk, SOCK_DEAD))
 						sk->error_report(sk);
 				}
 				if (msg == NETDEV_UNREGISTER) {
diff -Nru a/net/rose/af_rose.c b/net/rose/af_rose.c
--- a/net/rose/af_rose.c	Fri May  2 23:38:42 2003
+++ b/net/rose/af_rose.c	Thu May 29 03:10:34 2003
@@ -356,8 +356,9 @@
 	rose_clear_queues(sk);		/* Flush the queues */
 
 	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
-		if (skb->sk != sk) {			/* A pending connection */
-			__set_bit(SOCK_DEAD, &skb->sk->flags);	/* Queue the unaccepted socket for death */
+		if (skb->sk != sk) {	/* A pending connection */
+			/* Queue the unaccepted socket for death */
+			sock_set_flag(skb->sk, SOCK_DEAD);
 			rose_start_heartbeat(skb->sk);
 			rose_sk(skb->sk)->state = ROSE_STATE_0;
 		}
@@ -637,8 +638,8 @@
 		sk->state    = TCP_CLOSE;
 		sk->shutdown |= SEND_SHUTDOWN;
 		sk->state_change(sk);
-		__set_bit(SOCK_DEAD, &sk->flags);
-		__set_bit(SOCK_DESTROY, &sk->flags);
+		sock_set_flag(sk, SOCK_DEAD);
+		sock_set_flag(sk, SOCK_DESTROY);
 		break;
 
 	default:
@@ -1010,7 +1011,7 @@
 
 	rose_start_heartbeat(make);
 
-	if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (!sock_flag(sk, SOCK_DEAD))
 		sk->data_ready(sk, skb->len);
 
 	return 1;
@@ -1535,7 +1536,6 @@
 			dev_rose[i].priv = NULL;
 			unregister_netdev(&dev_rose[i]);
 		}
-		kfree(dev_rose[i].name);
 	}
 
 	kfree(dev_rose);
diff -Nru a/net/rose/rose_in.c b/net/rose/rose_in.c
--- a/net/rose/rose_in.c	Mon Mar  3 04:56:53 2003
+++ b/net/rose/rose_in.c	Wed May 28 01:07:02 2003
@@ -54,7 +54,7 @@
 		rose->vl        = 0;
 		rose->state     = ROSE_STATE_3;
 		sk->state                    = TCP_ESTABLISHED;
-		if (!test_bit(SOCK_DEAD, &sk->flags))
+		if (!sock_flag(sk, SOCK_DEAD))
 			sk->state_change(sk);
 		break;
 
diff -Nru a/net/rose/rose_route.c b/net/rose/rose_route.c
--- a/net/rose/rose_route.c	Mon Mar  3 04:56:53 2003
+++ b/net/rose/rose_route.c	Wed May 28 01:07:03 2003
@@ -910,9 +910,10 @@
 			sk->state	 = TCP_CLOSE;
 			sk->err		 = 0;
 			sk->shutdown	 |= SEND_SHUTDOWN;
-			if (!test_bit(SOCK_DEAD, &sk->flags))
+			if (!sock_flag(sk, SOCK_DEAD)) {
 				sk->state_change(sk);
-			__set_bit(SOCK_DEAD, &sk->flags);
+				sock_set_flag(sk, SOCK_DEAD);
+			}
 		}
 		else {
 			skb->h.raw = skb->data;
diff -Nru a/net/rose/rose_subr.c b/net/rose/rose_subr.c
--- a/net/rose/rose_subr.c	Mon Mar  3 04:56:53 2003
+++ b/net/rose/rose_subr.c	Wed May 28 01:07:03 2003
@@ -510,8 +510,8 @@
 	sk->err       = reason;
 	sk->shutdown |= SEND_SHUTDOWN;
 
-	if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (!sock_flag(sk, SOCK_DEAD)) {
 		sk->state_change(sk);
-
-	__set_bit(SOCK_DEAD, &sk->flags);
+		sock_set_flag(sk, SOCK_DEAD);
+	}
 }
diff -Nru a/net/rose/rose_timer.c b/net/rose/rose_timer.c
--- a/net/rose/rose_timer.c	Mon Mar  3 04:56:53 2003
+++ b/net/rose/rose_timer.c	Wed May 28 01:07:03 2003
@@ -136,9 +136,8 @@
 	case ROSE_STATE_0:
 		/* Magic here: If we listen() and a new link dies before it
 		   is accepted() it isn't 'dead' so doesn't get removed. */
-		if (test_bit(SOCK_DESTROY, &sk->flags) ||
-				(sk->state == TCP_LISTEN &&
-					test_bit(SOCK_DEAD, &sk->flags))) {
+		if (sock_flag(sk, SOCK_DESTROY) ||
+		    (sk->state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) {
 			rose_destroy_socket(sk);
 			return;
 		}
@@ -209,9 +208,9 @@
 	sk->err       = 0;
 	sk->shutdown |= SEND_SHUTDOWN;
 
-	if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (!sock_flag(sk, SOCK_DEAD)) {
 		sk->state_change(sk);
-
-	__set_bit(SOCK_DEAD, &sk->flags);
+		sock_set_flag(sk, SOCK_DEAD);
+	}
 	bh_unlock_sock(sk);
 }
diff -Nru a/net/sctp/socket.c b/net/sctp/socket.c
--- a/net/sctp/socket.c	Mon May 12 18:59:25 2003
+++ b/net/sctp/socket.c	Wed May 28 01:07:03 2003
@@ -731,7 +731,7 @@
 				sctp_unhash_established(asoc);
 				sctp_association_free(asoc);
 
-			} else if (test_bit(SOCK_LINGER, &sk->flags) &&
+			} else if (sock_flag(sk, SOCK_LINGER) &&
 				   !sk->lingertime)
 				sctp_primitive_ABORT(asoc, NULL);
 			else
diff -Nru a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
--- a/net/sctp/ulpqueue.c	Thu Apr 17 06:44:11 2003
+++ b/net/sctp/ulpqueue.c	Wed May 28 01:07:03 2003
@@ -189,7 +189,7 @@
 	/* If the socket is just going to throw this away, do not
 	 * even try to deliver it.
 	 */
-	if (test_bit(SOCK_DEAD, &sk->flags) || (sk->shutdown & RCV_SHUTDOWN))
+	if (sock_flag(sk, SOCK_DEAD) || (sk->shutdown & RCV_SHUTDOWN))
 		goto out_free;
 
 	/* Check if the user wishes to receive this event.  */
diff -Nru a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
--- a/net/sunrpc/svcsock.c	Mon May 19 23:34:35 2003
+++ b/net/sunrpc/svcsock.c	Thu May 29 22:42:47 2003
@@ -589,6 +589,8 @@
 	rqstp->rq_addr.sin_port = skb->h.uh->source;
 	rqstp->rq_addr.sin_addr.s_addr = skb->nh.iph->saddr;
 
+	svsk->sk_sk->stamp = skb->stamp;
+
 	if (skb_is_nonlinear(skb)) {
 		/* we have to copy */
 		local_bh_disable();
@@ -629,7 +631,6 @@
 		serv->sv_stats->netudpcnt++;
 
 	/* One down, maybe more to go... */
-	svsk->sk_sk->stamp = skb->stamp;
 	svc_sock_received(svsk);
 
 	return len;
diff -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
--- a/net/sunrpc/xprt.c	Wed May  7 04:07:31 2003
+++ b/net/sunrpc/xprt.c	Wed May 28 01:07:03 2003
@@ -963,7 +963,7 @@
 	dprintk("RPC:      tcp_state_change client %p...\n", xprt);
 	dprintk("RPC:      state %x conn %d dead %d zapped %d\n",
 				sk->state, xprt_connected(xprt),
-				test_bit(SOCK_DEAD, &sk->flags), sk->zapped);
+				sock_flag(sk, SOCK_DEAD), sk->zapped);
 
 	switch (sk->state) {
 	case TCP_ESTABLISHED:
diff -Nru a/net/unix/af_unix.c b/net/unix/af_unix.c
--- a/net/unix/af_unix.c	Wed May 14 20:37:15 2003
+++ b/net/unix/af_unix.c	Wed May 28 01:07:03 2003
@@ -334,8 +334,7 @@
 		 * we signal error. Messages are lost. Do not make this,
 		 * when peer was not connected to us.
 		 */
-		if (!test_bit(SOCK_DEAD, &other->flags) &&
-				unix_peer(other) == sk) {
+		if (!sock_flag(other, SOCK_DEAD) && unix_peer(other) == sk) {
 			other->err = ECONNRESET;
 			other->error_report(other);
 		}
@@ -351,7 +350,7 @@
 	BUG_TRAP(atomic_read(&sk->wmem_alloc) == 0);
 	BUG_TRAP(!u->list);
 	BUG_TRAP(sk->socket==NULL);
-	if (!test_bit(SOCK_DEAD, &sk->flags)) {
+	if (!sock_flag(sk, SOCK_DEAD)) {
 		printk("Attempt to release alive unix socket: %p\n", sk);
 		return;
 	}
@@ -863,9 +862,9 @@
 
 	prepare_to_wait_exclusive(&u->peer_wait, &wait, TASK_INTERRUPTIBLE);
 
-	sched = (!test_bit(SOCK_DEAD, &other->flags) &&
-		 !(other->shutdown&RCV_SHUTDOWN) &&
-		 skb_queue_len(&other->receive_queue) > other->max_ack_backlog);
+	sched = !sock_flag(other, SOCK_DEAD) &&
+		!(other->shutdown & RCV_SHUTDOWN) &&
+		skb_queue_len(&other->receive_queue) > other->max_ack_backlog;
 
 	unix_state_runlock(other);
 
@@ -927,7 +926,7 @@
 	unix_state_rlock(other);
 
 	/* Apparently VFS overslept socket death. Retry. */
-	if (test_bit(SOCK_DEAD, &other->flags)) {
+	if (sock_flag(other, SOCK_DEAD)) {
 		unix_state_runlock(other);
 		sock_put(other);
 		goto restart;
@@ -1267,7 +1266,7 @@
 	if (!unix_may_send(sk, other))
 		goto out_unlock;
 
-	if (test_bit(SOCK_DEAD, &other->flags)) {
+	if (sock_flag(other, SOCK_DEAD)) {
 		/*
 		 *	Check with 1003.1g - what should
 		 *	datagram error
@@ -1418,8 +1417,8 @@
 
 		unix_state_rlock(other);
 
-		if (test_bit(SOCK_DEAD, &other->flags) ||
-				(other->shutdown & RCV_SHUTDOWN))
+		if (sock_flag(other, SOCK_DEAD) ||
+		    (other->shutdown & RCV_SHUTDOWN))
 			goto pipe_err_free;
 
 		skb_queue_tail(&other->receive_queue, skb);
diff -Nru a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c
--- a/net/wanrouter/af_wanpipe.c	Sun May 25 19:36:24 2003
+++ b/net/wanrouter/af_wanpipe.c	Wed May 28 01:07:03 2003
@@ -1003,7 +1003,7 @@
 
 	sock->sk = NULL;
 	sk->socket = NULL;
-	__set_bit(SOCK_DEAD, &sk->flags);
+	sock_set_flag(sk, SOCK_DEAD);
 
 	/* Purge queues */
 	skb_queue_purge(&sk->receive_queue);
@@ -1075,7 +1075,7 @@
 		while ((skb=skb_dequeue(&sk->receive_queue))!=NULL){
 			if ((deadsk = get_newsk_from_skb(skb))){
 				DBG_PRINTK (KERN_INFO "wansock: RELEASE: FOUND DEAD SOCK\n");
-				__set_bit(SOCK_DEAD, &deadsk->flags);
+				sock_set_flag(deadsk, SOCK_DEAD);
 				start_cleanup_timer(deadsk);
 			}
 			kfree_skb(skb);
diff -Nru a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c
--- a/net/wanrouter/wanproc.c	Sun May 18 07:58:29 2003
+++ b/net/wanrouter/wanproc.c	Mon May 26 19:28:25 2003
@@ -87,7 +87,8 @@
 	lock_kernel();
 	if (!l--)
 		return (void *)1;
-	for (wandev = router_devlist; l-- && wandev; wandev = wandev->next)
+	for (wandev = wanrouter_router_devlist; l-- && wandev;
+	     wandev = wandev->next)
 		;
 	return wandev;
 }
@@ -96,7 +97,7 @@
 {
 	struct wan_device *wandev = v;
 	(*pos)++;
-	return (v == (void *)1) ? router_devlist : wandev->next;
+	return (v == (void *)1) ? wanrouter_router_devlist : wandev->next;
 }
 
 static void r_stop(struct seq_file *m, void *v)
diff -Nru a/net/x25/af_x25.c b/net/x25/af_x25.c
--- a/net/x25/af_x25.c	Fri May  2 23:40:57 2003
+++ b/net/x25/af_x25.c	Wed May 28 01:07:03 2003
@@ -344,7 +344,7 @@
 			/*
 			 * Queue the unaccepted socket for death
 			 */
-			__set_bit(SOCK_DEAD, &skb->sk->flags);
+			sock_set_flag(skb->sk, SOCK_DEAD);
 			x25_start_heartbeat(skb->sk);
 			x25_sk(skb->sk)->state = X25_STATE_0;
 		}
@@ -574,8 +574,8 @@
 			sk->state               = TCP_CLOSE;
 			sk->shutdown           |= SEND_SHUTDOWN;
 			sk->state_change(sk);
-			__set_bit(SOCK_DEAD, &sk->flags);
-			__set_bit(SOCK_DESTROY, &sk->flags);
+			sock_set_flag(sk, SOCK_DEAD);
+			sock_set_flag(sk, SOCK_DESTROY);
 			break;
 	}
 
@@ -896,7 +896,7 @@
 
 	x25_start_heartbeat(make);
 
-	if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (!sock_flag(sk, SOCK_DEAD))
 		sk->data_ready(sk, skb->len);
 	rc = 1;
 	sock_put(sk);
@@ -1106,8 +1106,8 @@
 
 	if (flags & MSG_OOB) {
 		rc = -EINVAL;
-		if (test_bit(SOCK_URGINLINE, &sk->flags) ||
-				!skb_peek(&x25->interrupt_in_queue))
+		if (sock_flag(sk, SOCK_URGINLINE) ||
+		    !skb_peek(&x25->interrupt_in_queue))
 			goto out;
 
 		skb = skb_dequeue(&x25->interrupt_in_queue);
diff -Nru a/net/x25/x25_in.c b/net/x25/x25_in.c
--- a/net/x25/x25_in.c	Mon Mar  3 04:56:53 2003
+++ b/net/x25/x25_in.c	Wed May 28 01:07:03 2003
@@ -86,7 +86,7 @@
 
 	skb_set_owner_r(skbn, sk);
 	skb_queue_tail(&sk->receive_queue, skbn);
-	if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (!sock_flag(sk, SOCK_DEAD))
 		sk->data_ready(sk, skbn->len);
 
 	return 0;
@@ -129,7 +129,7 @@
 				       skb->len);
 				x25->calluserdata.cudlength = skb->len;
 			}
-			if (!test_bit(SOCK_DEAD, &sk->flags))
+			if (!sock_flag(sk, SOCK_DEAD))
 				sk->state_change(sk);
 			break;
 		}
@@ -277,9 +277,9 @@
 			break;
 
 		case X25_INTERRUPT:
-			if (test_bit(SOCK_URGINLINE, &sk->flags)) {
-				queued = (sock_queue_rcv_skb(sk, skb) == 0);
-			} else {
+			if (sock_flag(sk, SOCK_URGINLINE))
+				queued = !sock_queue_rcv_skb(sk, skb);
+			else {
 				skb_set_owner_r(skb, sk);
 				skb_queue_tail(&x25->interrupt_in_queue, skb);
 				queued = 1;
diff -Nru a/net/x25/x25_subr.c b/net/x25/x25_subr.c
--- a/net/x25/x25_subr.c	Mon Mar  3 04:56:53 2003
+++ b/net/x25/x25_subr.c	Wed May 28 01:07:03 2003
@@ -344,10 +344,10 @@
 	sk->err       = reason;
 	sk->shutdown |= SEND_SHUTDOWN;
 
-	if (!test_bit(SOCK_DEAD, &sk->flags))
+	if (!sock_flag(sk, SOCK_DEAD)) {
 		sk->state_change(sk);
-
-	__set_bit(SOCK_DEAD, &sk->flags);
+		sock_set_flag(sk, SOCK_DEAD);
+	}
 }
 
 /*
diff -Nru a/net/x25/x25_timer.c b/net/x25/x25_timer.c
--- a/net/x25/x25_timer.c	Mon Mar  3 04:56:53 2003
+++ b/net/x25/x25_timer.c	Wed May 28 01:07:03 2003
@@ -137,9 +137,14 @@
 	switch (x25_sk(sk)->state) {
 
 		case X25_STATE_0:
-			/* Magic here: If we listen() and a new link dies before it
-			   is accepted() it isn't 'dead' so doesn't get removed. */
-			if (test_bit(SOCK_DESTROY, &sk->flags) || (sk->state == TCP_LISTEN && test_bit(SOCK_DEAD, &sk->flags))) {
+			/*
+			 * Magic here: If we listen() and a new link dies
+			 * before it is accepted() it isn't 'dead' so doesn't
+			 * get removed.
+			 */
+			if (sock_flag(sk, SOCK_DESTROY) ||
+			    (sk->state == TCP_LISTEN &&
+			     sock_flag(sk, SOCK_DEAD))) {
 				x25_destroy_socket(sk);
 				goto unlock;
 			}
diff -Nru a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
--- a/net/xfrm/xfrm_policy.c	Thu May 22 09:44:33 2003
+++ b/net/xfrm/xfrm_policy.c	Tue May 27 02:11:56 2003
@@ -244,22 +244,34 @@
 int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
 {
 	struct xfrm_policy *pol, **p;
+	struct xfrm_policy *delpol = NULL;
+	struct xfrm_policy **newpos = NULL;
 
 	write_lock_bh(&xfrm_policy_lock);
 	for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) {
-		if (memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0) {
+		if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0) {
 			if (excl) {
 				write_unlock_bh(&xfrm_policy_lock);
 				return -EEXIST;
 			}
+			*p = pol->next;
+			delpol = pol;
+			if (policy->priority > pol->priority)
+				continue;
+		} else if (policy->priority >= pol->priority)
+			continue;
+		if (!newpos)
+			newpos = p;
+		if (delpol)
 			break;
-		}
 	}
+	if (newpos)
+		p = newpos;
 	xfrm_pol_hold(policy);
-	policy->next = pol ? pol->next : NULL;
+	policy->next = *p;
 	*p = policy;
 	atomic_inc(&flow_cache_genid);
-	policy->index = pol ? pol->index : xfrm_gen_index(dir);
+	policy->index = delpol ? delpol->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 &&
@@ -267,10 +279,10 @@
 		xfrm_pol_hold(policy);
 	write_unlock_bh(&xfrm_policy_lock);
 
-	if (pol) {
-		atomic_dec(&pol->refcnt);
-		xfrm_policy_kill(pol);
-		xfrm_pol_put(pol);
+	if (delpol) {
+		atomic_dec(&delpol->refcnt);
+		xfrm_policy_kill(delpol);
+		xfrm_pol_put(delpol);
 	}
 	return 0;
 }
