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

diff -urN linux-2.5.6-pre1/CREDITS linux-2.5.6-pre2/CREDITS
--- linux-2.5.6-pre1/CREDITS	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/CREDITS	Thu Feb 28 13:34:18 2002
@@ -1579,8 +1579,10 @@
 S: Luxembourg
 
 N: Gerd Knorr
-E: kraxel@goldbach.in-berlin.de
-D: SCSI CD-ROM driver hacking, vesafb, v4l, minor bug fixes
+W: http://bytesex.org
+E: kraxel@bytesex.org
+E: kraxel@suse.de
+D: video4linux, bttv, vesafb, some scsi, misc fixes
 
 N: Harald Koenig
 E: koenig@tat.physik.uni-tuebingen.de
diff -urN linux-2.5.6-pre1/Documentation/Changes linux-2.5.6-pre2/Documentation/Changes
--- linux-2.5.6-pre1/Documentation/Changes	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre2/Documentation/Changes	Thu Feb 28 13:34:18 2002
@@ -54,6 +54,7 @@
 o  util-linux             2.10o                   # fdformat --version
 o  modutils               2.4.2                   # insmod -V
 o  e2fsprogs              1.25                    # tune2fs
+o  jfsutils               1.0.14                  # fsck.jfs -V
 o  reiserfsprogs          3.x.0j                  # reiserfsck 2>&1|grep reiserfsprogs
 o  pcmcia-cs              3.1.21                  # cardmgr -V
 o  PPP                    2.4.0                   # pppd --version
@@ -106,8 +107,8 @@
 your kernel.  This change does, however, mean that you need a recent
 release of binutils.
 
-System utilities
-================
+System utililities
+==================
 
 Architectural changes
 ---------------------
@@ -165,6 +166,16 @@
 The latest version of e2fsprogs fixes several bugs in fsck and
 debugfs.  Obviously, it's a good idea to upgrade.
 
+JFSutils
+--------
+
+The jfsutils package contains the utilities for the file system.
+The following utilities are available:
+o fsck.jfs - initiate replay of the transaction log, and check
+  and repair a JFS formatted partition.
+o mkfs.jfs - create a JFS formatted partition.
+o other file system utilities are also available in this package.
+
 Reiserfsprogs
 -------------
 
@@ -303,6 +314,10 @@
 ---------
 o  <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.25.tar.gz>
 
+JFSutils
+--------
+o  <http://oss.software.ibm.com/jfs>
+
 Reiserfsprogs
 -------------
 o  <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.x.0j.tar.gz>
diff -urN linux-2.5.6-pre1/Documentation/arm/Interrupts linux-2.5.6-pre2/Documentation/arm/Interrupts
--- linux-2.5.6-pre1/Documentation/arm/Interrupts	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/Documentation/arm/Interrupts	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,173 @@
+2.5.2-rmk5
+----------
+
+This is the first kernel that contains a major shake up of some of the
+major architecture-specific subsystems.
+
+Firstly, it contains some pretty major changes to the way we handle the
+MMU TLB.  Each MMU TLB variant is now handled completely separately -
+we have TLB v3, TLB v4 (without write buffer), TLB v4 (with write buffer),
+and finally TLB v4 (with write buffer, with I TLB invalidate entry).
+There is more assembly code inside each of these functions, mainly to
+allow more flexible TLB handling for the future.
+
+Secondly, the IRQ subsystem.
+
+The 2.5 kernels will be having major changes to the way IRQs are handled.
+Unfortunately, this means that machine types that touch the irq_desc[]
+array (basically all machine types) will break, and this means every
+machine type that we currently have.
+
+Lets take an example.  On the Assabet with Neponset, we have:
+
+                  GPIO25                 IRR:2
+        SA1100 ------------> Neponset -----------> SA1111
+                                         IIR:1
+                                      -----------> USAR
+                                         IIR:0
+                                      -----------> SMC9196
+
+The way stuff currently works, all SA1111 interrupts are mutually
+exclusive of each other - if you're processing one interrupt from the
+SA1111 and another comes in, you have to wait for that interrupt to
+finish processing before you can service the new interrupt.  Eg, an
+IDE PIO-based interrupt on the SA1111 excludes all other SA1111 and
+SMC9196 interrupts until it has finished transferring its multi-sector
+data, which can be a long time.  Note also that since we loop in the
+SA1111 IRQ handler, SA1111 IRQs can hold off SMC9196 IRQs indefinitely.
+
+
+The new approach brings several new ideas...
+
+We introduce the concept of a "parent" and a "child".  For example,
+to the Neponset handler, the "parent" is GPIO25, and the "children"d
+are SA1111, SMC9196 and USAR.
+
+We also bring the idea of an IRQ "chip" (mainly to reduce the size of
+the irqdesc array).  This doesn't have to be a real "IC"; indeed the
+SA11x0 IRQs are handled by two separate "chip" structures, one for
+GPIO0-10, and another for all the rest.  It is just a container for
+the various operations (maybe this'll change to a better name).
+This structure has the following operations:
+
+struct irqchip {
+        /*
+         * Acknowledge the IRQ.
+         * If this is a level-based IRQ, then it is expected to mask the IRQ
+         * as well.
+         */
+        void (*ack)(unsigned int irq);
+        /*
+         * Mask the IRQ in hardware.
+         */
+        void (*mask)(unsigned int irq);
+        /*
+         * Unmask the IRQ in hardware.
+         */
+        void (*unmask)(unsigned int irq);
+        /*
+         * Re-run the IRQ
+         */
+        void (*rerun)(unsigned int irq);
+        /*
+         * Set the type of the IRQ.
+         */
+        int (*type)(unsigned int irq, unsigned int, type);
+};
+
+ack    - required.  May be the same function as mask for IRQs
+         handled by do_level_IRQ.
+mask   - required.
+unmask - required.
+rerun  - optional.  Not required if you're using do_level_IRQ for all
+         IRQs that use this 'irqchip'.  Generally expected to re-trigger
+         the hardware IRQ if possible.  If not, may call the handler
+	 directly.
+type   - optional.  If you don't support changing the type of an IRQ,
+         it should be null so people can detect if they are unable to
+         set the IRQ type.
+
+For each IRQ, we keep the following information:
+
+        - "disable" depth (number of disable_irq()s without enable_irq()s)
+        - flags indicating what we can do with this IRQ (valid, probe,
+          noautounmask) as before
+        - status of the IRQ (probing, enable, etc)
+        - chip
+        - per-IRQ handler
+        - irqaction structure list
+
+The handler can be one of the 3 standard handlers - "level", "edge" and
+"simple", or your own specific handler if you need to do something special.
+
+The "level" handler is what we currently have - its pretty simple.
+"edge" knows about the brokenness of such IRQ implementations - that you
+need to leave the hardware IRQ enabled while processing it, and queueing
+further IRQ events should the IRQ happen again while processing.  The
+"simple" handler is very basic, and does not perform any hardware
+manipulation, nor state tracking.  This is useful for things like the
+SMC9196 and USAR above.
+
+So, what's changed?
+
+1. Machine implementations must not write to the irqdesc array.
+
+2. New functions to manipulate the irqdesc array.  The first 4 are expected
+   to be useful only to machine specific code.  The last is recommended to
+   only be used by machine specific code, but may be used in drivers if
+   absolutely necessary.
+
+        set_irq_chip(irq,chip)
+
+                Set the mask/unmask methods for handling this IRQ
+
+        set_irq_handler(irq,handler)
+
+                Set the handler for this IRQ (level, edge, simple)
+
+        set_irq_chained_handler(irq,handler)
+
+                Set a "chained" handler for this IRQ - automatically
+                enables this IRQ (eg, Neponset and SA1111 handlers).
+
+        set_irq_flags(irq,flags)
+
+                Set the valid/probe/noautoenable flags.
+
+        set_irq_type(irq,type)
+
+                Set active the IRQ edge(s)/level.  This replaces the
+                SA1111 INTPOL manipulation, and the set_GPIO_IRQ_edge()
+                function.  Type should be one of the following:
+
+                #define IRQT_NOEDGE     (0)
+                #define IRQT_RISING     (__IRQT_RISEDGE)
+                #define IRQT_FALLING    (__IRQT_FALEDGE)
+                #define IRQT_BOTHEDGE   (__IRQT_RISEDGE|__IRQT_FALEDGE)
+                #define IRQT_LOW        (__IRQT_LOWLVL)
+                #define IRQT_HIGH       (__IRQT_HIGHLVL)
+
+3. set_GPIO_IRQ_edge() is obsolete, and should be replaced by set_irq_type.
+
+4. Direct access to SA1111 INTPOL is depreciated.  Use set_irq_type instead.
+
+5. A handler is expected to perform any necessary acknowledgement of the
+   parent IRQ via the correct chip specific function.  For instance, if
+   the SA1111 is directly connected to a SA1110 GPIO, then you should
+   acknowledge the SA1110 IRQ each time you re-read the SA1111 IRQ status.
+
+6. For any child which doesn't have its own IRQ enable/disable controls
+   (eg, SMC9196), the handler must mask or acknowledge the parent IRQ
+   while the child handler is called, and the child handler should be the
+   "simple" handler (not "edge" nor "level").  After the handler completes,
+   the parent IRQ should be unmasked, and the status of all children must
+   be re-checked for pending events.  (see the Neponset IRQ handler for
+   details).
+
+7. fixup_irq() is gone, as is include/asm-arm/arch-*/irq.h
+
+Please note that this will not solve all problems - some of them are
+hardware based.  Mixing level-based and edge-based IRQs on the same
+parent signal (eg neponset) is one such area where a software based
+solution can't provide the full answer to low IRQ latency.
+
diff -urN linux-2.5.6-pre1/Documentation/driver-model.txt linux-2.5.6-pre2/Documentation/driver-model.txt
--- linux-2.5.6-pre1/Documentation/driver-model.txt	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/Documentation/driver-model.txt	Thu Feb 28 13:34:18 2002
@@ -118,7 +118,18 @@
 
 By virtue of having a complete hierarchical view of all the devices in the
 system, exporting a complete hierarchical view to userspace becomes relatively
-easy.
+easy. This has been accomplished by implementing a special purpose virtual
+file system named driverfs. It is hence possible for the user to mount the
+whole driverfs on a particular mount point in the unified UNIX file hierarchy.
+
+This can be done permanently by providing the following entry into the
+/dev/fstab (under the provision that the mount point does exist, of course):
+
+none     	/devices	driverfs    defaults		0	0
+
+Or by hand on the command line:
+
+~: mount -t driverfs none /devices
 
 Whenever a device is inserted into the tree, a directory is created for it.
 This directory may be populated at each layer of discovery - the global layer,
@@ -343,6 +354,8 @@
 via driverfs, and tell each device to go to sleep. It will do this multiple
 times based on what the system policy is.
 
+[ FIXME: URL pointer to the corresponding utility is missing here! ]
+
 Device resume should happen in the same manner when the system awakens.
 
 Each suspend stage is described below:
diff -urN linux-2.5.6-pre1/Documentation/filesystems/00-INDEX linux-2.5.6-pre2/Documentation/filesystems/00-INDEX
--- linux-2.5.6-pre1/Documentation/filesystems/00-INDEX	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/Documentation/filesystems/00-INDEX	Thu Feb 28 13:34:18 2002
@@ -22,6 +22,8 @@
 	- info and mount options for the OS/2 HPFS.
 isofs.txt
 	- info and mount options for the ISO 9660 (CDROM) filesystem.
+jfs.txt
+	- info and mount options for the JFS filesystem.
 ncpfs.txt
 	- info on Novell Netware(tm) filesystem using NCP protocol.
 ntfs.txt
diff -urN linux-2.5.6-pre1/Documentation/filesystems/jfs.txt linux-2.5.6-pre2/Documentation/filesystems/jfs.txt
--- linux-2.5.6-pre1/Documentation/filesystems/jfs.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/Documentation/filesystems/jfs.txt	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,136 @@
+IBM's Journaled File System (JFS) for Linux version 1.0.15
+Team members
+Steve Best         sbest@us.ibm.com
+Dave Kleikamp      shaggy@austin.ibm.com  
+Barry Arndt        barndt@us.ibm.com
+Christoph Hellwig  hch@caldera.de
+
+
+Release February 15, 2002 (version 1.0.15)
+
+This is our fifty-third release of IBM's Enterprise JFS technology port to Linux.
+Beta 1 was release 0.1.0 on 12/8/2000, Beta 2 was release 0.2.0 on 3/7/2001, 
+Beta 3 was release 0.3.0 on 4/30/2001, and release 1.0.0 on 6/28/2001.
+ 
+The changelog.jfs file contains detailed information of changes done in each source
+code drop.
+
+JFS has a source tree that can be built on 2.4.3 - 2.4.17 and 2.5.4 kernel.org
+source trees.
+ 
+Our current goal on the 2.5.x series of the kernel is to update to the latest 
+2.5.x version and only support the latest version of this kernel.
+This will change when the distros start shipping the 2.5.x series of the kernel.
+
+Our current goal on the 2.4.x series of the kernel is to continue to support
+all of the kernels in this series as we do today.
+
+There is an anonymous cvs access available for the JFS tree. The steps below are
+what is needed to pull the JFS cvs tree from the oss.software.ibm.com server.
+
+id anoncvs
+password anoncvs
+
+To checkout 2.4.x series of the JFS files do the following:
+CVSROOT should be set to :pserver:anoncvs@oss.software.ibm.com:/usr/cvs/jfs
+cvs checkout linux24
+
+To checkout 2.5.2 series of the JFS files do the following:
+CVSROOT should be set to :pserver:anoncvs@oss.software.ibm.com:/usr/cvs/jfs
+cvs checkout linux25
+
+To checkout the JFS utilities do the following:
+CVSROOT should be set to :pserver:anoncvs@oss.software.ibm.com:/usr/cvs/jfs
+cvs checkout jfsutils
+
+The cvs tree contains the latest changes being done to JFS. To receive notification
+of commits to the cvs tree, please send e-mail to linuxjfs@us.ibm.com stating that 
+you would like notifications sent to you. 
+
+The jfs-2.4-1.0.15-patch.tar.gz is the easiest way to get the latest file system
+source code on your system. There are also patch files that can move your jfs source
+code from one release to another. If you have release 1.0.14 and would like to move
+to release 1.0.15 the patch file named jfs-2.4-1_0_14-to-1_0_15-patch.gz will do that.
+
+The jfs-2.4-1.0.15-patch.tar.gz file contains a readme and patch files for different
+levels of the 2.4 kernel. Please see the README in the jfs-2.4-1.0.15-patch.tar.gz
+file for help on applying the two patch files. 
+
+
+The following files in the kernel source tree have been changed so JFS can be built.
+The jfs-2.4-1.0.15.tar.gz source tar ball contains each of the files below with
+the extension of the kernel level it is associated with. As an example, there are now
+four Config.in files named Config.in-2.4.0, Config.in-2.4.5, Config.in-2.4.7 and 
+Config.in-2.4.17.
+
+
+If you use the jfs-2.4-1.0.15.tar.gz to build JFS you must rename each of the 
+kernel files to the file names listed below. The standard kernel from www.kernel.org 
+is the source of the kernel files that are included in the jfs tar file. 
+
+
+In sub dir fs Config.in, Makefile
+In sub dir fs/nls Config.in
+In sub dir Documentation Configure.help, Changes
+In sub dir Documentation/filesystems 00-INDEX
+In sub dir linux MAINTAINERS
+
+Please backup the above files before the JFS tar file is added to the kernel source 
+tree. All JFS files are located in the include/linux/jfs or fs/jfs sub dirs.
+
+Our development team has used the Linux kernel levels  2.4.3 - 2.4.17 kernels
+with gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release) 
+for our port so far. A goal of the JFS team is to have JFS run on all architectures
+that Linux supports, there is no architecture specific code in JFS. JFS has been run
+on the following architectures (x86, PowerPC, Alpha, s/390, ARM) so far. 
+
+To make JFS build, during the "make config" step of building the kernel answer y to
+the Prompt for development and/or incomplete code/drivers in the Code maturity level
+options section. In the Filesystems section use the m for the answer to 
+JFS filesystem support (experimental) (CONFIG_JFS_FS) [Y/m/n?]
+ 
+
+Build in /usr/src/linux with the command:
+
+
+make modules
+make modules_install
+
+If you rebuild jfs.o after having mounted and unmounted a partition, "modprobe -r jfs" 
+will unload the old module.
+
+For the file system debugging messages are being written to /var/log/messages.
+
+Please see the readme in the utilities package for information about building
+the JFS utilities.
+
+JFS TODO list:
+
+Plans for our near term development items
+
+   - get defrag capabilities operational in the FS
+   - get extendfs capabilities operational in the FS
+   - test EXTENDFS utility, for growing JFS partitions
+   - test defrag utility, calls file system to defrag the file system.
+   - add support for block sizes (512,1024,2048)
+   - add support for logfile on dedicated partition
+
+   
+Longer term work items
+
+   - get access control list functionality operational
+   - get extended attributes functionality operational
+   - add quota support
+
+Please send bugs, comments, cards and letters to linuxjfs@us.ibm.com.
+
+The JFS mailing list can be subscribed to by using the link labeled "Mail list Subscribe"
+at our web page http://oss.software.ibm.com/jfs/.
+
+
+
+
+
+
+
+
diff -urN linux-2.5.6-pre1/Documentation/usb/auerswald.txt linux-2.5.6-pre2/Documentation/usb/auerswald.txt
--- linux-2.5.6-pre1/Documentation/usb/auerswald.txt	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/Documentation/usb/auerswald.txt	Thu Feb 28 13:34:18 2002
@@ -19,9 +19,9 @@
 auerswald and shipped as part of the java software.
 
 You may create the devices with:
-	mknod -m 666 /dev/usb/auer0 c 180 80
+	mknod -m 666 /dev/usb/auer0 c 180 112
 	...
-	mknod -m 666 /dev/usb/auer15 c 180 95
+	mknod -m 666 /dev/usb/auer15 c 180 127
 
 Future plans
 ============
diff -urN linux-2.5.6-pre1/Documentation/usb/usb-serial.txt linux-2.5.6-pre2/Documentation/usb/usb-serial.txt
--- linux-2.5.6-pre1/Documentation/usb/usb-serial.txt	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/Documentation/usb/usb-serial.txt	Thu Feb 28 13:34:18 2002
@@ -95,12 +95,13 @@
   Kroah-Hartman at greg@kroah.com
 
 
-Compaq iPAQ driver
+Compaq iPAQ and HP Jornada driver
 
-  This driver can be used to connect to Compaq iPAQ PDAs running
-  Windows CE 3.0 using a USB autosync cable. It has been tested only on
-  the Compaq H3135. It should work with the H3600 and later models too.
-  It may work with other CE based handhelds as well.
+  This driver can be used to connect to Compaq iPAQ and HP Jornada PDAs
+  running Windows CE 3.0 or PocketPC 2002 using a USB cable/cradle. It
+  has been tested only on the Compaq H3135, but is rumoured to work on
+  with the H3600 and later models as well as the Jornada 548 and 568.
+  With minor modifications, it may work for other CE based handhelds too.
 
   The driver presents a serial interface (usually on /dev/ttyUSB0) over
   which one may run ppp and establish a TCP/IP link to the iPAQ. Once this
@@ -109,11 +110,14 @@
   kbytes/sec for download/upload to the iPAQ.
 
   The driver works intermittently with the usb-uhci driver but quite
-  reliably with the uhci driver. Make sure you have the right driver
-  loaded - usb-uhci is often the default.
+  reliably with the uhci driver. However, performance is much better
+  with usb-uhci. It does not seem to work with ohci at all.
 
   You must setup hotplug to invoke pppd as soon as the iPAQ is connected.
-  A ppp script like the one below may be used:
+  A ppp script like the one below should be kept in the file
+  /etc/hotplug/usb/ipaq Remember to chmod +x. Make sure there are no
+  options in /etc/ppp/options or ~/.ppprc which conflict with the ones
+  given below.
 
 	#!/bin/bash
 
@@ -133,7 +137,7 @@
   On connecting the cable, you should see the usual "Device Connected",
   "User Authenticated" messages flash by on your iPAQ. Once connected,
   you can use Win CE programs like ftpView, Pocket Outlook from the iPAQ
-  and other synce utilities from the Linux side. Remember to enable IP
+  and xcerdisp, synce utilities from the Linux side. Remember to enable IP
   forwarding. 
 
   To use Pocket IE, follow the instructions given at
diff -urN linux-2.5.6-pre1/MAINTAINERS linux-2.5.6-pre2/MAINTAINERS
--- linux-2.5.6-pre1/MAINTAINERS	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/MAINTAINERS	Thu Feb 28 13:34:18 2002
@@ -272,9 +272,9 @@
 
 BTTV VIDEO4LINUX DRIVER
 P:	Gerd Knorr
-M:	kraxel@goldbach.in-berlin.de
+M:	kraxel@bytesex.org
 L:	video4linux-list@redhat.com
-W:	http://me.in-berlin.de/~kraxel/bttv.html
+W:	http://bytesex.org/bttv/
 S:	Maintained
 
 BUSLOGIC SCSI DRIVER
@@ -856,6 +856,13 @@
 W:	http://sources.redhat.com/jffs2/
 S:	Maintained
 
+JFS FILESYSTEM
+P:	Dave Kleikamp
+M:	shaggy@austin.ibm.com
+L:	jfs-discussion@oss.software.ibm.com
+W:	http://oss.software.ibm.com/jfs/
+S:	Supported
+
 JOYSTICK DRIVER
 P:	Vojtech Pavlik
 M:	vojtech@suse.cz
@@ -1752,10 +1759,10 @@
 S:	Maintained
 
 VIDEO FOR LINUX
-P:	Alan Cox
-M:	Alan.Cox@linux.org
+P:	Gerd Knorr
+M:	kraxel@bytesex.org
 W:	http://roadrunner.swansea.linux.org.uk/v4l.shtml
-S:	Maintained for 2.2 only
+S:	Maintained
 
 WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC)
 P:	Nenad Corbic
diff -urN linux-2.5.6-pre1/Makefile linux-2.5.6-pre2/Makefile
--- linux-2.5.6-pre1/Makefile	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/Makefile	Thu Feb 28 13:34:18 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 6
-EXTRAVERSION =-pre1
+EXTRAVERSION =-pre2
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.5.6-pre1/arch/arm/Config.help linux-2.5.6-pre2/arch/arm/Config.help
--- linux-2.5.6-pre1/arch/arm/Config.help	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/Config.help	Thu Feb 28 13:34:18 2002
@@ -657,6 +657,10 @@
   platform with a 640x480 LCD, touchscreen, CIR keyboard, PCMCIA slots,
   and a telco interface.
 
+CONFIG_SA1100_STORK
+  Say Y here if you intend to run this kernel on the Stork
+  handheld computer.
+
 CONFIG_SA1100_VICTOR
   Say Y here if you are using a Visu Aide Intel(R) StrongARM(R)
   SA-1100 based Victor Digital Talking Book Reader.  See
diff -urN linux-2.5.6-pre1/arch/arm/Makefile linux-2.5.6-pre2/arch/arm/Makefile
--- linux-2.5.6-pre1/arch/arm/Makefile	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/arch/arm/Makefile	Thu Feb 28 13:34:18 2002
@@ -134,6 +134,10 @@
 MACHINE		 = clps711x
 endif
 
+ifeq ($(CONFIG_ARCH_FORTUNET),y)
+TEXTADDR	 = 0xc0008000
+endif
+
 ifeq ($(CONFIG_ARCH_ANAKIN),y)
 MACHINE		 = anakin
 endif
@@ -215,6 +219,7 @@
 	arch/arm/vmlinux.lds
 
 MRPROPER_FILES	+= \
+	arch/arm/tools/constants.h* \
 	include/asm-arm/arch \
 	include/asm-arm/proc \
 	include/asm-arm/constants.h* \
diff -urN linux-2.5.6-pre1/arch/arm/boot/Makefile linux-2.5.6-pre2/arch/arm/boot/Makefile
--- linux-2.5.6-pre1/arch/arm/boot/Makefile	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/arch/arm/boot/Makefile	Thu Feb 28 13:34:18 2002
@@ -54,6 +54,10 @@
 INITRD_VIRT	 = 0xc0800000
 endif
 
+ifeq ($(CONFIG_ARCH_CAMELOT),y)
+ZTEXTADDR	 = 0x00008000
+endif
+
 ifeq ($(CONFIG_ARCH_NEXUSPCI),y)
 ZTEXTADDR	 = 0x40008000
 endif
diff -urN linux-2.5.6-pre1/arch/arm/boot/compressed/Makefile linux-2.5.6-pre2/arch/arm/boot/compressed/Makefile
--- linux-2.5.6-pre1/arch/arm/boot/compressed/Makefile	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/arch/arm/boot/compressed/Makefile	Thu Feb 28 13:34:18 2002
@@ -33,6 +33,10 @@
 OBJS		+= head-integrator.o
 endif
 
+ifeq ($(CONFIG_ARCH_CAMELOT),y)
+OBJS		+= head-epxa10db.o
+endif
+
 ifeq ($(CONFIG_ARCH_FTVPCI),y)
 OBJS		+= head-ftvpci.o
 endif
diff -urN linux-2.5.6-pre1/arch/arm/boot/compressed/head-epxa10db.S linux-2.5.6-pre2/arch/arm/boot/compressed/head-epxa10db.S
--- linux-2.5.6-pre1/arch/arm/boot/compressed/head-epxa10db.S	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/boot/compressed/head-epxa10db.S	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,5 @@
+#include <asm/mach-types.h>
+#include <asm/arch/excalibur.h>
+
+		.section	".start", #alloc, #execinstr
+		mov	r7, #MACH_TYPE_CAMELOT
diff -urN linux-2.5.6-pre1/arch/arm/boot/compressed/misc.c linux-2.5.6-pre2/arch/arm/boot/compressed/misc.c
--- linux-2.5.6-pre1/arch/arm/boot/compressed/misc.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/arch/arm/boot/compressed/misc.c	Thu Feb 28 13:34:18 2002
@@ -18,6 +18,8 @@
 
 unsigned int __machine_arch_type;
 
+#include <linux/kernel.h>
+
 #include <asm/uaccess.h>
 #include <asm/arch/uncompress.h>
 #include <asm/proc/uncompress.h>
diff -urN linux-2.5.6-pre1/arch/arm/config.in linux-2.5.6-pre2/arch/arm/config.in
--- linux-2.5.6-pre1/arch/arm/config.in	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/config.in	Thu Feb 28 13:34:18 2002
@@ -91,6 +91,7 @@
 dep_bool '  FreeBird-v1.1' CONFIG_SA1100_FREEBIRD $CONFIG_ARCH_SA1100
 dep_bool '  GraphicsClient Plus' CONFIG_SA1100_GRAPHICSCLIENT $CONFIG_ARCH_SA1100
 dep_bool '  GraphicsMaster' CONFIG_SA1100_GRAPHICSMASTER $CONFIG_ARCH_SA1100
+dep_bool '  HP Labs BadgePAD 4' CONFIG_SA1100_BADGE4 $CONFIG_ARCH_SA1100
 dep_bool '  HP Jornada 720' CONFIG_SA1100_JORNADA720 $CONFIG_ARCH_SA1100
 dep_bool '  HuW WebPanel' CONFIG_SA1100_HUW_WEBPANEL $CONFIG_ARCH_SA1100
 dep_bool '  Itsy' CONFIG_SA1100_ITSY $CONFIG_ARCH_SA1100
@@ -107,6 +108,7 @@
 dep_bool '  Victor' CONFIG_SA1100_VICTOR $CONFIG_ARCH_SA1100
 dep_bool '  XP860' CONFIG_SA1100_XP860 $CONFIG_ARCH_SA1100
 dep_bool '  Yopy' CONFIG_SA1100_YOPY $CONFIG_ARCH_SA1100
+dep_bool '  Stork' CONFIG_SA1100_STORK $CONFIG_ARCH_SA1100
 
 # Determine if SA1111 support is required
 if [ "$CONFIG_ASSABET_NEPONSET" = "y" -o \
@@ -115,7 +117,8 @@
      "$CONFIG_SA1100_XP860" = "y" -o \
      "$CONFIG_SA1100_GRAPHICSMASTER" = "y" -o \
      "$CONFIG_SA1100_PT_SYSTEM3" = "y" -o \
-     "$CONFIG_SA1100_ADSBITSY" = "y" ]; then
+     "$CONFIG_SA1100_ADSBITSY" = "y" -o \
+     "$CONFIG_SA1100_BADGE4" = "y" ]; then
    define_bool CONFIG_SA1111 y
    define_int CONFIG_FORCE_MAX_ZONEORDER 9
 fi
@@ -134,6 +137,7 @@
 dep_bool '  CLEP7312' CONFIG_ARCH_CLEP7312 $CONFIG_ARCH_CLPS711X
 dep_bool '  EDB7211' CONFIG_ARCH_EDB7211 $CONFIG_ARCH_CLPS711X
 dep_bool '  P720T' CONFIG_ARCH_P720T $CONFIG_ARCH_CLPS711X
+dep_bool '  FORTUNET' CONFIG_ARCH_FORTUNET $CONFIG_ARCH_CLPS711X
 
 # XXX Maybe these should indicate register compatibility
 # instead of being mutually exclusive.
diff -urN linux-2.5.6-pre1/arch/arm/def-configs/badge4 linux-2.5.6-pre2/arch/arm/def-configs/badge4
--- linux-2.5.6-pre1/arch/arm/def-configs/badge4	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/def-configs/badge4	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,923 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_RPC is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_SHARK is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+
+#
+# Archimedes/A5000 Implementations (select only ONE)
+#
+
+#
+# Footbridge Implementations
+#
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_H3XXX is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+CONFIG_SA1100_BADGE4=y
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+CONFIG_SA1111=y
+CONFIG_FORCE_MAX_ZONEORDER=9
+CONFIG_SA1100_USB=m
+CONFIG_SA1100_USB_NETLINK=m
+CONFIG_SA1100_USB_CHAR=m
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+
+#
+# Processor Type
+#
+# CONFIG_CPU_32v3 is not set
+CONFIG_CPU_32v4=y
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_SA110 is not set
+CONFIG_CPU_SA1100=y
+# CONFIG_ARM_THUMB is not set
+CONFIG_DISCONTIGMEM=y
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+CONFIG_ISA=y
+# CONFIG_ISA_DMA is not set
+CONFIG_CPU_FREQ=y
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_PROBE=y
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_SA1100=y
+CONFIG_NET=y
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+CONFIG_FPE_FASTFPE=m
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_PM is not set
+CONFIG_ARTHUR=m
+CONFIG_CMDLINE="init=/linuxrc root=/dev/mtdblock3"
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=1
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_BOOTLDR_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_SA1100=y
+# CONFIG_MTD_IQ80310 is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTDRAM_TOTAL_SIZE=4096
+CONFIG_MTDRAM_ERASE_SIZE=128
+CONFIG_MTD_BLKMTD=m
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRO is not set
+CONFIG_HERMES=y
+
+#
+# Wireless Pcmcia cards support
+#
+CONFIG_PCMCIA_HERMES=y
+CONFIG_AIRO_CS=m
+CONFIG_NET_WIRELESS=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=y
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=y
+CONFIG_PCMCIA_AXNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_NET_PCMCIA_RADIO=y
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_PCMCIA_NETWAVE=m
+CONFIG_PCMCIA_WAVELAN=m
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+CONFIG_IRDA=y
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=y
+CONFIG_IRCOMM=y
+CONFIG_IRDA_ULTRA=y
+# CONFIG_IRDA_OPTIONS is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+CONFIG_SA1100_FIR=y
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=m
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+CONFIG_BLK_DEV_IDESCSI=m
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx_sync is not set
+# CONFIG_SCSI_NCR53C7xx_FAST is not set
+# CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_SCSI_PCMCIA is not set
+
+#
+# I2O device support
+#
+CONFIG_I2O=m
+CONFIG_I2O_BLOCK=m
+CONFIG_I2O_LAN=m
+CONFIG_I2O_SCSI=m
+CONFIG_I2O_PROC=m
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=m
+CONFIG_INPUT_KEYBDEV=m
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SA1100_DEFAULT_BAUDRATE=115200
+# CONFIG_SERIAL_8250 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_ELV=m
+CONFIG_I2C_VELLEMAN=m
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ELEKTOR=m
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_PROC=m
+
+#
+# L3 serial bus support
+#
+CONFIG_L3=m
+
+#
+# Other L3 adapters
+#
+# CONFIG_BIT_SA1100_GPIO is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_SERIO is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_SOFT_WATCHDOG=m
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+CONFIG_SA1100_WATCHDOG=m
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_NVRAM is not set
+CONFIG_RTC=m
+CONFIG_SA1100_RTC=m
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=m
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_CRAMFS=m
+# CONFIG_TMPFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+CONFIG_MINIX_FS=m
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=m
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_ZISOFS_FS is not set
+CONFIG_ZLIB_FS_INFLATE=m
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_SOUND_SA1100=y
+CONFIG_SOUND_UDA1341=m
+CONFIG_SOUND_SA1111_UDA1341=m
+CONFIG_SOUND_SA1100SSP=m
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_LONG_TIMEOUT is not set
+
+#
+# USB Controllers
+#
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+CONFIG_USB_OHCI_SA1111=y
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_AUDIO=y
+CONFIG_USB_BLUETOOTH=m
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_HP8200e=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=m
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_KBD=m
+CONFIG_USB_MOUSE=m
+CONFIG_USB_WACOM=m
+
+#
+# USB Imaging devices
+#
+CONFIG_USB_DC2XX=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_SCANNER=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USB_HPUSBSCSI=m
+
+#
+# USB Multimedia devices
+#
+
+#
+#   Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_CATC=m
+CONFIG_USB_CDCETHER=m
+CONFIG_USB_USBNET=m
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_GENERIC is not set
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_RIO500=m
+
+#
+# Bluetooth support
+#
+CONFIG_BLUEZ=m
+CONFIG_BLUEZ_L2CAP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BLUEZ_HCIUSB=m
+CONFIG_BLUEZ_HCIUART=m
+CONFIG_BLUEZ_HCIVHCI=m
+
+#
+# Kernel hacking
+#
+# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_LL_SER3=y
diff -urN linux-2.5.6-pre1/arch/arm/def-configs/epxa10db linux-2.5.6-pre2/arch/arm/def-configs/epxa10db
--- linux-2.5.6-pre1/arch/arm/def-configs/epxa10db	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/arch/arm/def-configs/epxa10db	Thu Feb 28 13:34:18 2002
@@ -8,6 +8,8 @@
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
 
 #
 # Code maturity level options
@@ -25,6 +27,7 @@
 #
 # System Type
 #
+# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
@@ -34,6 +37,7 @@
 CONFIG_ARCH_CAMELOT=y
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP310 is not set
 # CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
@@ -62,12 +66,16 @@
 # CONFIG_SA1100_ADSBITSY is not set
 # CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
 # CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_H3XXX is not set
 # CONFIG_SA1100_EXTENEX1 is not set
 # CONFIG_SA1100_FLEXANET is not set
 # CONFIG_SA1100_FREEBIRD is not set
 # CONFIG_SA1100_GRAPHICSCLIENT is not set
 # CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_BADGE4 is not set
 # CONFIG_SA1100_JORNADA720 is not set
 # CONFIG_SA1100_HUW_WEBPANEL is not set
 # CONFIG_SA1100_ITSY is not set
@@ -76,20 +84,28 @@
 # CONFIG_SA1100_OMNIMETER is not set
 # CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
 # CONFIG_SA1100_SHERMAN is not set
 # CONFIG_SA1100_SIMPAD is not set
 # CONFIG_SA1100_PFS168 is not set
 # CONFIG_SA1100_VICTOR is not set
 # CONFIG_SA1100_XP860 is not set
 # CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+# CONFIG_H3600_SLEEVE is not set
 
 #
 # CLPS711X/EP721X Implementations
 #
+# CONFIG_ARCH_AUTCPU12 is not set
 # CONFIG_ARCH_CDB89712 is not set
 # CONFIG_ARCH_CLEP7312 is not set
 # CONFIG_ARCH_EDB7211 is not set
 # CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_FORTUNET is not set
 # CONFIG_ARCH_EP7211 is not set
 # CONFIG_ARCH_EP7212 is not set
 # CONFIG_ARCH_ACORN is not set
@@ -103,14 +119,17 @@
 # CONFIG_CPU_ARM610 is not set
 # CONFIG_CPU_ARM710 is not set
 # CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
 CONFIG_CPU_ARM922T=y
-CONFIG_CPU_ARM92X_CPU_IDLE=y
-CONFIG_CPU_ARM92X_I_CACHE_ON=y
-CONFIG_CPU_ARM92X_D_CACHE_ON=y
-# CONFIG_CPU_ARM92X_WRITETHROUGH is not set
+CONFIG_CPU_ARM922_CPU_IDLE=y
+CONFIG_CPU_ARM922_I_CACHE_ON=y
+CONFIG_CPU_ARM922_D_CACHE_ON=y
+# CONFIG_CPU_ARM922_WRITETHROUGH is not set
+# CONFIG_CPU_ARM926T is not set
 # CONFIG_CPU_ARM1020 is not set
 # CONFIG_CPU_SA110 is not set
 # CONFIG_CPU_SA1100 is not set
+# CONFIG_XSCALE_PMU is not set
 # CONFIG_ARM_THUMB is not set
 # CONFIG_DISCONTIGMEM is not set
 
@@ -120,6 +139,7 @@
 # CONFIG_PCI is not set
 # CONFIG_ISA is not set
 # CONFIG_ISA_DMA is not set
+# CONFIG_FIQ is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
 CONFIG_NET=y
@@ -134,6 +154,7 @@
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
+# CONFIG_APM is not set
 # CONFIG_ARTHUR is not set
 CONFIG_CMDLINE="console=ttyUA0,38400 root=/dev/mtdblock0 rw"
 CONFIG_ALIGNMENT_TRAP=y
@@ -171,42 +192,28 @@
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
 # CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
 
 #
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_SUN_UFLASH is not set
 # CONFIG_MTD_NORA is not set
-# CONFIG_MTD_PNC2000 is not set
-# CONFIG_MTD_RPXLITE is not set
-# CONFIG_MTD_TQM8XXL is not set
-# CONFIG_MTD_SC520CDP is not set
-# CONFIG_MTD_NETSC520 is not set
-# CONFIG_MTD_SBC_GXX is not set
-# CONFIG_MTD_ELAN_104NC is not set
-# CONFIG_MTD_DBOX2 is not set
-# CONFIG_MTD_CSTM_MIPS_IXX is not set
-CONFIG_MTD_EPXA10DB=y
-# CONFIG_MTD_CFI_FLAGADM is not set
-# CONFIG_MTD_SOLUTIONENGINE is not set
-# CONFIG_MTD_MIXMEM is not set
-# CONFIG_MTD_OCTAGON is not set
-# CONFIG_MTD_VMAX is not set
-# CONFIG_MTD_OCELOT is not set
-# CONFIG_MTD_L440GX is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_CDB89712 is not set
 # CONFIG_MTD_SA1100 is not set
 # CONFIG_MTD_DC21285 is not set
 # CONFIG_MTD_IQ80310 is not set
+CONFIG_MTD_EPXA10DB=y
+# CONFIG_MTD_PCI is not set
 
 #
 # Self-contained MTD device drivers
 #
 # CONFIG_MTD_PMC551 is not set
 # CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_LART is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
 # CONFIG_MTD_DOC1000 is not set
@@ -224,7 +231,6 @@
 #
 # CONFIG_PNP is not set
 # CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
 
 #
 # Block devices
@@ -234,6 +240,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
@@ -250,6 +257,7 @@
 # CONFIG_MD_RAID0 is not set
 # CONFIG_MD_RAID1 is not set
 # CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
 # CONFIG_BLK_DEV_LVM is not set
 
 #
@@ -275,6 +283,7 @@
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
 # CONFIG_DECNET is not set
@@ -311,7 +320,8 @@
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
-CONFIG_ETHER00=y
+# CONFIG_ARM_AM79C961A is not set
+CONFIG_ETHER00=m
 # CONFIG_SUNLANCE is not set
 # CONFIG_SUNBMAC is not set
 # CONFIG_SUNQE is not set
@@ -343,8 +353,8 @@
 # CONFIG_PPP_FILTER is not set
 CONFIG_PPP_ASYNC=y
 CONFIG_PPP_SYNC_TTY=y
-CONFIG_PPP_DEFLATE=y
-CONFIG_PPP_BSDCOMP=y
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
 # CONFIG_PPPOE is not set
 # CONFIG_SLIP is not set
 
@@ -437,12 +447,14 @@
 # CONFIG_SERIAL_SA1100_CONSOLE is not set
 # CONFIG_SERIAL_8250 is not set
 # CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_ATOMWIDE_SERIAL is not set
+# CONFIG_DUALSP_SERIAL is not set
 # CONFIG_SERIAL_8250_EXTENDED is not set
 # CONFIG_SERIAL_8250_MANY_PORTS is not set
 # CONFIG_SERIAL_8250_SHARE_IRQ is not set
 # CONFIG_SERIAL_8250_DETECT_IRQ is not set
 # CONFIG_SERIAL_8250_MULTIPORT is not set
-# CONFIG_SERIAL_8250_HUB6 is not set
+# CONFIG_SERIAL_8250_RSA is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
@@ -460,7 +472,6 @@
 # CONFIG_L3_ALGOBIT is not set
 # CONFIG_L3_BIT_SA1100_GPIO is not set
 # CONFIG_L3_SA1111 is not set
-# CONFIG_L3_DRV_UDA1341 is not set
 # CONFIG_BIT_SA1100_GPIO is not set
 
 #
@@ -485,7 +496,6 @@
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
-# CONFIG_SONYPI is not set
 
 #
 # Ftape, the floppy tape device driver
@@ -513,7 +523,6 @@
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
-# CONFIG_CMS_FS is not set
 # CONFIG_EXT3_FS is not set
 # CONFIG_JBD is not set
 # CONFIG_JBD_DEBUG is not set
@@ -522,16 +531,17 @@
 # CONFIG_UMSDOS_FS is not set
 # CONFIG_VFAT_FS is not set
 # CONFIG_EFS_FS is not set
-CONFIG_JFFS_FS=y
-CONFIG_JFFS_FS_VERBOSE=0
-# CONFIG_JFFS2_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
 # CONFIG_CRAMFS is not set
-# CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
-# CONFIG_FREEVXFS_FS is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
@@ -572,6 +582,8 @@
 # CONFIG_NCPFS_SMALLDOS is not set
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -582,9 +594,19 @@
 # CONFIG_NLS is not set
 
 #
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+
+#
 # USB support
 #
 # CONFIG_USB is not set
+# CONFIG_USB_EHCI_HCD is not set
 # CONFIG_USB_UHCI is not set
 # CONFIG_USB_UHCI_ALT is not set
 # CONFIG_USB_OHCI is not set
@@ -596,10 +618,10 @@
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
 # CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
 # CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_HP8200e is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
 # CONFIG_USB_DC2XX is not set
@@ -607,8 +629,6 @@
 # CONFIG_USB_SCANNER is not set
 # CONFIG_USB_MICROTEK is not set
 # CONFIG_USB_HPUSBSCSI is not set
-# CONFIG_USB_DABUSB is not set
-# CONFIG_USB_PLUSB is not set
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_CATC is not set
@@ -627,21 +647,27 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
 # CONFIG_USB_SERIAL_KEYSPAN is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
 # CONFIG_USB_SERIAL_OMNINET is not set
 # CONFIG_USB_RIO500 is not set
-# CONFIG_USB_ID75 is not set
+# CONFIG_USB_AUERSWALD is not set
 
 #
 # Bluetooth support
@@ -652,11 +678,21 @@
 # Kernel hacking
 #
 # CONFIG_NO_FRAME_POINTER is not set
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_INFO=y
-CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
 # CONFIG_NO_PGT_CACHE is not set
-CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
 # CONFIG_DEBUG_DC21285_PORT is not set
 # CONFIG_DEBUG_CLPS711X_UART2 is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
diff -urN linux-2.5.6-pre1/arch/arm/def-configs/fortunet linux-2.5.6-pre2/arch/arm/def-configs/fortunet
--- linux-2.5.6-pre1/arch/arm/def-configs/fortunet	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/def-configs/fortunet	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,593 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+CONFIG_ARCH_CLPS711X=y
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_H3XXX is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+# CONFIG_H3600_SLEEVE is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_P720T is not set
+CONFIG_ARCH_FORTUNET=y
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_32v3 is not set
+CONFIG_CPU_32v4=y
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+CONFIG_CPU_ARM720T=y
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_SA110 is not set
+# CONFIG_CPU_SA1100 is not set
+# CONFIG_ARM_THUMB is not set
+# CONFIG_DISCONTIGMEM is not set
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+# CONFIG_ISA_DMA is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_FPE_NWFPE is not set
+CONFIG_FPE_FASTFPE=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_PARTITIONS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_BOOTLDR_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_CDB89712 is not set
+# CONFIG_MTD_SA1100 is not set
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_IQ80310 is not set
+CONFIG_MTD_FORTUNET=y
+# CONFIG_MTD_PCI is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+# CONFIG_INET is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET_AUNUDP is not set
+# CONFIG_ECONET_NATIVE is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network device support
+#
+# CONFIG_NETDEVICES is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Synchronous Serial Interface
+#
+# CONFIG_SSI is not set
+# CONFIG_SSI_CLPS711X is not set
+# CONFIG_SSI_JUNO is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+CONFIG_SERIAL_CLPS711X=y
+CONFIG_SERIAL_CLPS711X_CONSOLE=y
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
+# CONFIG_SERIAL_SA1100 is not set
+# CONFIG_SERIAL_SA1100_CONSOLE is not set
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# L3 serial bus support
+#
+# CONFIG_L3 is not set
+# CONFIG_L3_ALGOBIT is not set
+# CONFIG_L3_BIT_SA1100_GPIO is not set
+# CONFIG_L3_SA1111 is not set
+# CONFIG_BIT_SA1100_GPIO is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS_FS=y
+CONFIG_JFFS_FS_VERBOSE=0
+# CONFIG_JFFS_PROC_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+# CONFIG_USB_OHCI_SA1111 is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_RIO500 is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_NO_PGT_CACHE is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
+# CONFIG_DEBUG_LL_SER3 is not set
diff -urN linux-2.5.6-pre1/arch/arm/def-configs/shark linux-2.5.6-pre2/arch/arm/def-configs/shark
--- linux-2.5.6-pre1/arch/arm/def-configs/shark	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/arch/arm/def-configs/shark	Thu Feb 28 13:34:18 2002
@@ -9,6 +9,7 @@
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 # CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
 
 #
 # Code maturity level options
@@ -26,14 +27,17 @@
 #
 # System Type
 #
+# CONFIG_ARCH_ADIFCC is not set
 # CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
 # CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP310 is not set
 # CONFIG_ARCH_L7200 is not set
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
@@ -66,12 +70,16 @@
 # CONFIG_SA1100_ADSBITSY is not set
 # CONFIG_SA1100_BRUTUS is not set
 # CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
 # CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_H3XXX is not set
 # CONFIG_SA1100_EXTENEX1 is not set
 # CONFIG_SA1100_FLEXANET is not set
 # CONFIG_SA1100_FREEBIRD is not set
 # CONFIG_SA1100_GRAPHICSCLIENT is not set
 # CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_BADGE4 is not set
 # CONFIG_SA1100_JORNADA720 is not set
 # CONFIG_SA1100_HUW_WEBPANEL is not set
 # CONFIG_SA1100_ITSY is not set
@@ -80,20 +88,28 @@
 # CONFIG_SA1100_OMNIMETER is not set
 # CONFIG_SA1100_PANGOLIN is not set
 # CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
 # CONFIG_SA1100_SHERMAN is not set
 # CONFIG_SA1100_SIMPAD is not set
 # CONFIG_SA1100_PFS168 is not set
 # CONFIG_SA1100_VICTOR is not set
 # CONFIG_SA1100_XP860 is not set
 # CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+# CONFIG_H3600_SLEEVE is not set
 
 #
 # CLPS711X/EP721X Implementations
 #
+# CONFIG_ARCH_AUTCPU12 is not set
 # CONFIG_ARCH_CDB89712 is not set
 # CONFIG_ARCH_CLEP7312 is not set
 # CONFIG_ARCH_EDB7211 is not set
 # CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_FORTUNET is not set
 # CONFIG_ARCH_EP7211 is not set
 # CONFIG_ARCH_EP7212 is not set
 # CONFIG_ARCH_ACORN is not set
@@ -112,9 +128,12 @@
 # CONFIG_CPU_ARM710 is not set
 # CONFIG_CPU_ARM720T is not set
 # CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_CPU_ARM926T is not set
 # CONFIG_CPU_ARM1020 is not set
 CONFIG_CPU_SA110=y
 # CONFIG_CPU_SA1100 is not set
+# CONFIG_XSCALE_PMU is not set
 # CONFIG_ARM_THUMB is not set
 # CONFIG_DISCONTIGMEM is not set
 
@@ -122,8 +141,11 @@
 # General setup
 #
 CONFIG_PCI=y
+# CONFIG_PCI_HOST_PLX90X0 is not set
+CONFIG_PCI_HOST_VIA82C505=y
 CONFIG_ISA=y
 CONFIG_ISA_DMA=y
+# CONFIG_FIQ is not set
 # CONFIG_PCI_NAMES is not set
 # CONFIG_HOTPLUG is not set
 # CONFIG_PCMCIA is not set
@@ -143,6 +165,7 @@
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
+# CONFIG_APM is not set
 # CONFIG_ARTHUR is not set
 CONFIG_LEDS=y
 CONFIG_LEDS_TIMER=y
@@ -172,7 +195,6 @@
 #
 # CONFIG_PNP is not set
 # CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
 
 #
 # Block devices
@@ -182,6 +204,7 @@
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
@@ -204,10 +227,11 @@
 #
 # Networking options
 #
-# CONFIG_PACKET is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
 # CONFIG_NETLINK is not set
 # CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
+CONFIG_FILTER=y
 CONFIG_UNIX=y
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
@@ -220,6 +244,7 @@
 # CONFIG_IPV6 is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
 
 #
 #  
@@ -260,6 +285,7 @@
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
+# CONFIG_ARM_AM79C961A is not set
 # CONFIG_SUNLANCE is not set
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNBMAC is not set
@@ -280,6 +306,7 @@
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 CONFIG_CS89x0=y
+# CONFIG_DE2104X is not set
 # CONFIG_TULIP is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
@@ -291,6 +318,7 @@
 # CONFIG_NE2K_PCI is not set
 # CONFIG_NE3210 is not set
 # CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
 # CONFIG_8139TOO is not set
 # CONFIG_8139TOO_PIO is not set
 # CONFIG_8139TOO_TUNE_TWISTER is not set
@@ -300,6 +328,7 @@
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
 # CONFIG_NET_POCKET is not set
 
@@ -416,7 +445,6 @@
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
-# CONFIG_SCSI_DEBUG_QUEUES is not set
 # CONFIG_SCSI_MULTI_LUN is not set
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
@@ -453,6 +481,7 @@
 # CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_NCR53C8XX is not set
 # CONFIG_SCSI_SYM53C8XX is not set
 # CONFIG_SCSI_PAS16 is not set
@@ -521,16 +550,20 @@
 # CONFIG_SERIAL_21285 is not set
 # CONFIG_SERIAL_21285_OLD is not set
 # CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
 # CONFIG_SERIAL_SA1100 is not set
 # CONFIG_SERIAL_SA1100_CONSOLE is not set
 # CONFIG_SERIAL_8250 is not set
 # CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_ATOMWIDE_SERIAL is not set
+# CONFIG_DUALSP_SERIAL is not set
 # CONFIG_SERIAL_8250_EXTENDED is not set
 # CONFIG_SERIAL_8250_MANY_PORTS is not set
 # CONFIG_SERIAL_8250_SHARE_IRQ is not set
 # CONFIG_SERIAL_8250_DETECT_IRQ is not set
 # CONFIG_SERIAL_8250_MULTIPORT is not set
-# CONFIG_SERIAL_8250_HUB6 is not set
+# CONFIG_SERIAL_8250_RSA is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
 CONFIG_PRINTER=m
@@ -588,7 +621,6 @@
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
-# CONFIG_SONYPI is not set
 
 #
 # Ftape, the floppy tape device driver
@@ -596,7 +628,6 @@
 # CONFIG_FTAPE is not set
 # CONFIG_AGP is not set
 # CONFIG_DRM is not set
-# CONFIG_MWAVE is not set
 
 #
 # Multimedia devices
@@ -617,7 +648,6 @@
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
-# CONFIG_CMS_FS is not set
 CONFIG_EXT3_FS=y
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
@@ -630,12 +660,12 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 CONFIG_JOLIET=y
 # CONFIG_ZISOFS is not set
 # CONFIG_MINIX_FS is not set
-# CONFIG_FREEVXFS_FS is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
@@ -807,7 +837,7 @@
 # CONFIG_SOUND_DMAP is not set
 # CONFIG_SOUND_AD1816 is not set
 # CONFIG_SOUND_SGALAXY is not set
-# CONFIG_SOUND_ADLIB is not set
+CONFIG_SOUND_ADLIB=m
 # CONFIG_SOUND_ACI_MIXER is not set
 # CONFIG_SOUND_CS4232 is not set
 # CONFIG_SOUND_SSCAPE is not set
@@ -850,8 +880,9 @@
 # CONFIG_USB is not set
 
 #
-# USB Controllers
+# USB Host Controller Drivers
 #
+# CONFIG_USB_EHCI_HCD is not set
 # CONFIG_USB_UHCI is not set
 # CONFIG_USB_UHCI_ALT is not set
 # CONFIG_USB_OHCI is not set
@@ -867,10 +898,10 @@
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
 # CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
 # CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_HP8200e is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
 
@@ -898,12 +929,10 @@
 #
 #   Video4Linux support is needed for USB Multimedia device support
 #
-# CONFIG_USB_DABUSB is not set
 
 #
 # USB Network adaptors
 #
-# CONFIG_USB_PLUSB is not set
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_KAWETH is not set
 # CONFIG_USB_CATC is not set
@@ -926,27 +955,31 @@
 # CONFIG_USB_SERIAL_EMPEG is not set
 # CONFIG_USB_SERIAL_FTDI_SIO is not set
 # CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
 # CONFIG_USB_SERIAL_KEYSPAN is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
 # CONFIG_USB_SERIAL_PL2303 is not set
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
 # CONFIG_USB_SERIAL_OMNINET is not set
 
 #
-# Miscellaneous USB drivers
+# USB Miscellaneous drivers
 #
 # CONFIG_USB_RIO500 is not set
-# CONFIG_USB_ID75 is not set
+# CONFIG_USB_AUERSWALD is not set
 
 #
 # Bluetooth support
@@ -957,11 +990,21 @@
 # Kernel hacking
 #
 CONFIG_NO_FRAME_POINTER=y
-CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_MAGIC_SYSRQ is not set
 # CONFIG_NO_PGT_CACHE is not set
-CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
 # CONFIG_DEBUG_DC21285_PORT is not set
 # CONFIG_DEBUG_CLPS711X_UART2 is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
diff -urN linux-2.5.6-pre1/arch/arm/def-configs/stork linux-2.5.6-pre2/arch/arm/def-configs/stork
--- linux-2.5.6-pre1/arch/arm/def-configs/stork	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/def-configs/stork	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,976 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ADIFCC is not set
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP310 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_RPC is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_SHARK is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+
+#
+# Archimedes/A5000 Implementations (select only ONE)
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
+CONFIG_SA1100_H3600=y
+# CONFIG_SA1100_H3800 is not set
+CONFIG_SA1100_H3XXX=y
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+CONFIG_SA1100_USB=m
+CONFIG_SA1100_USB_NETLINK=m
+# CONFIG_SA1100_USB_CHAR is not set
+CONFIG_H3600_SLEEVE=m
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_FORTUNET is not set
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+
+#
+# Processor Type
+#
+# CONFIG_CPU_32v3 is not set
+CONFIG_CPU_32v4=y
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_SA110 is not set
+CONFIG_CPU_SA1100=y
+# CONFIG_XSCALE_PMU is not set
+# CONFIG_ARM_THUMB is not set
+CONFIG_DISCONTIGMEM=y
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+CONFIG_ISA=y
+# CONFIG_ISA_DMA is not set
+# CONFIG_FIQ is not set
+CONFIG_CPU_FREQ=y
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+CONFIG_PCMCIA_PROBE=y
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+# CONFIG_PCMCIA_CLPS6700 is not set
+CONFIG_PCMCIA_SA1100=m
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=m
+CONFIG_FPE_FASTFPE=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PM=y
+# CONFIG_APM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="N"
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_BOOTLDR_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_GEOMETRY is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_CDB89712 is not set
+CONFIG_MTD_SA1100=y
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_EPXA10DB is not set
+# CONFIG_MTD_PCI is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+CONFIG_RTNETLINK=y
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+CONFIG_WAVELAN=m
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_AIRO is not set
+CONFIG_HERMES=m
+
+#
+# Wireless Pcmcia cards support
+#
+CONFIG_PCMCIA_HERMES=m
+# CONFIG_AIRO_CS is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+CONFIG_PCMCIA_PCNET=m
+# CONFIG_PCMCIA_NMCLAN is not set
+# CONFIG_PCMCIA_SMC91C92 is not set
+CONFIG_PCMCIA_XIRC2PS=m
+# CONFIG_PCMCIA_AXNET is not set
+# CONFIG_ARCNET_COM20020_CS is not set
+# CONFIG_PCMCIA_IBMTR is not set
+# CONFIG_NET_PCMCIA_RADIO is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=m
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_VT_CONSOLE is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SA1100_DEFAULT_BAUDRATE=115200
+CONFIG_SERIAL_8250=m
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_ATOMWIDE_SERIAL is not set
+# CONFIG_DUALSP_SERIAL is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_RSA is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# L3 serial bus support
+#
+CONFIG_L3=y
+CONFIG_L3_ALGOBIT=y
+CONFIG_L3_BIT_SA1100_GPIO=y
+
+#
+# Other L3 adapters
+#
+# CONFIG_L3_SA1111 is not set
+CONFIG_BIT_SA1100_GPIO=y
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=m
+# CONFIG_PSMOUSE is not set
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_SA1100_RTC=m
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_PCMCIA_SERIAL_CS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_CRAMFS=y
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+CONFIG_ZLIB_FS_INFLATE=y
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+CONFIG_PC_KEYMAP=y
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_ACORN is not set
+# CONFIG_FB_ANAKIN is not set
+# CONFIG_FB_CLPS711X is not set
+CONFIG_FB_SA1100=y
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
+# CONFIG_FBCON_CFB8 is not set
+CONFIG_FBCON_CFB16=y
+# CONFIG_FBCON_CFB24 is not set
+# CONFIG_FBCON_CFB32 is not set
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA_PLANES is not set
+# CONFIG_FBCON_VGA is not set
+# CONFIG_FBCON_HGA is not set
+CONFIG_FBCON_FONTWIDTH8_ONLY=y
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+CONFIG_SOUND_SA1100=y
+CONFIG_SOUND_UDA1341=m
+# CONFIG_SOUND_ASSABET_UDA1341 is not set
+CONFIG_SOUND_H3600_UDA1341=m
+# CONFIG_SOUND_PANGOLIN_UDA1341 is not set
+# CONFIG_SOUND_SA1111_UDA1341 is not set
+# CONFIG_SOUND_SA1100SSP is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_WAVEARTIST is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+# CONFIG_USB_OHCI_SA1111 is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH is not set
+
+#
+#   SCSI support is needed for USB Storage
+#
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+
+#
+#   Input core support is needed for USB HID
+#
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+
+#
+#   Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_NO_FRAME_POINTER is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_NO_PGT_CACHE is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
diff -urN linux-2.5.6-pre1/arch/arm/kernel/armksyms.c linux-2.5.6-pre2/arch/arm/kernel/armksyms.c
--- linux-2.5.6-pre1/arch/arm/kernel/armksyms.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/kernel/armksyms.c	Thu Feb 28 13:34:18 2002
@@ -124,6 +124,7 @@
 EXPORT_SYMBOL(__readwrite_bug);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(set_irq_type);
 EXPORT_SYMBOL(pm_idle);
 EXPORT_SYMBOL(pm_power_off);
 
diff -urN linux-2.5.6-pre1/arch/arm/kernel/debug.S linux-2.5.6-pre2/arch/arm/kernel/debug.S
--- linux-2.5.6-pre1/arch/arm/kernel/debug.S	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/arch/arm/kernel/debug.S	Thu Feb 28 13:34:18 2002
@@ -164,28 +164,49 @@
 		.endm
 
 #elif defined(CONFIG_ARCH_SA1100)
+
 		.macro	addruart,rx
 		mrc	p15, 0, \rx, c1, c0
 		tst	\rx, #1			@ MMU enabled?
 		moveq	\rx, #0x80000000	@ physical base address
 		movne	\rx, #0xf8000000	@ virtual address
-		@add	\rx, \rx, #0x00050000	@ Ser3
-		add	\rx, \rx, #0x00010000	@ Ser1
+
+		@ We probe for the active serial port here, coherently with
+		@ the comment in include/asm-arm/arch-sa1100/uncompress.h.
+		@ We assume r1 can be clobbered.
+
+		@ see if Ser3 is active
+		add	\rx, \rx, #0x00050000
+		ldr	r1, [\rx, #UTCR3]
+		tst	r1, #UTCR3_TXE
+
+		@ if Ser3 is inactive, then try Ser1
+		addeq	\rx, \rx, #(0x00010000 - 0x00050000)
+		ldreq	r1, [\rx, #UTCR3]
+		tsteq	r1, #UTCR3_TXE
+
+		@ if Ser1 is inactive, then try Ser2
+		addeq	\rx, \rx, #(0x00030000 - 0x00010000)
+		ldreq	r1, [\rx, #UTCR3]
+		tsteq	r1, #UTCR3_TXE
+
+		@ if all ports are inactive, then there is nothing we can do
+		moveq	pc, lr
 		.endm
 
 		.macro	senduart,rd,rx
-		str	\rd, [\rx, #0x14]	@ UTDR
+		str	\rd, [\rx, #UTDR]
 		.endm
 
 		.macro	waituart,rd,rx
-1001:		ldr	\rd, [\rx, #0x20]	@ UTSR1
-		tst	\rd, #1 << 2		@ UTSR1_TNF
+1001:		ldr	\rd, [\rx, #UTSR1]
+		tst	\rd, #UTSR1_TNF
 		beq	1001b
 		.endm
 
 		.macro	busyuart,rd,rx
-1001:		ldr	\rd, [\rx, #0x20]	@ UTSR1
-		tst	\rd, #1 << 0		@ UTSR1_TBY
+1001:		ldr	\rd, [\rx, #UTSR1]
+		tst	\rd, #UTSR1_TBY
 		bne	1001b
 		.endm
 
diff -urN linux-2.5.6-pre1/arch/arm/kernel/ecard.c linux-2.5.6-pre2/arch/arm/kernel/ecard.c
--- linux-2.5.6-pre1/arch/arm/kernel/ecard.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/arch/arm/kernel/ecard.c	Thu Feb 28 13:34:18 2002
@@ -91,17 +91,8 @@
 ecard_loader_reset(volatile unsigned char *pa, loader_t loader);
 asmlinkage extern int
 ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader);
-extern int setup_arm_irq(int, struct irqaction *);
-extern void do_ecard_IRQ(int, struct pt_regs *);
 
 
-static void
-ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs);
-
-static struct irqaction irqexpansioncard = {
-	ecard_irq_noexpmask, SA_INTERRUPT, 0, "expansion cards", NULL, NULL
-};
-
 static inline unsigned short
 ecard_getu16(unsigned char *v)
 {
@@ -558,7 +549,7 @@
  *
  * They are not meant to be called directly, but via enable/disable_irq.
  */
-static void ecard_enableirq(unsigned int irqnr)
+static void ecard_irq_mask(unsigned int irqnr)
 {
 	ecard_t *ec = slot_to_ecard(irqnr - 32);
 
@@ -574,7 +565,7 @@
 	}
 }
 
-static void ecard_disableirq(unsigned int irqnr)
+static void ecard_irq_unmask(unsigned int irqnr)
 {
 	ecard_t *ec = slot_to_ecard(irqnr - 32);
 
@@ -587,6 +578,12 @@
 	}
 }
 
+static struct irqchip ecard_chip = {
+	ack:	ecard_irq_mask,
+	mask:	ecard_irq_mask,
+	unmask:	ecard_irq_unmask,
+};
+
 void ecard_enablefiq(unsigned int fiqnr)
 {
 	ecard_t *ec = slot_to_ecard(fiqnr);
@@ -632,8 +629,7 @@
 		       ec->irqaddr, ec->irqmask, *ec->irqaddr);
 }
 
-static void
-ecard_check_lockup(void)
+static void ecard_check_lockup(struct irqdesc *desc)
 {
 	static int last, lockup;
 	ecard_t *ec;
@@ -653,7 +649,7 @@
 			printk(KERN_ERR "\nInterrupt lockup detected - "
 			       "disabling all expansion card interrupts\n");
 
-			disable_irq(IRQ_EXPANSIONCARD);
+			desc->chip->mask(IRQ_EXPANSIONCARD);
 
 			printk("Expansion card IRQ state:\n");
 
@@ -674,11 +670,12 @@
 }
 
 static void
-ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs)
+ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
 {
 	ecard_t *ec;
 	int called = 0;
 
+	desc->chip->mask(irq);
 	for (ec = cards; ec; ec = ec->next) {
 		int pending;
 
@@ -691,14 +688,15 @@
 			pending = ecard_default_ops.irqpending(ec);
 
 		if (pending) {
-			do_ecard_IRQ(ec->irq, regs);
+			struct irqdesc *d = irq_desc + ec->irq;
+			d->handle(ec->irq, d, regs);
 			called ++;
 		}
 	}
-	cli();
+	desc->chip->unmask(irq);
 
 	if (called == 0)
-		ecard_check_lockup();
+		ecard_check_lockup(desc);
 }
 
 #ifdef HAS_EXPMASK
@@ -714,20 +712,18 @@
 };
 
 static void
-ecard_irq_expmask(int intr_no, void *dev_id, struct pt_regs *regs)
+ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
 {
 	const unsigned int statusmask = 15;
 	unsigned int status;
 
 	status = __raw_readb(EXPMASK_STATUS) & statusmask;
 	if (status) {
-		unsigned int slot;
-		ecard_t *ec;
-again:
-		slot = first_set[status];
-		ec = slot_to_ecard(slot);
+		unsigned int slot = first_set[status];
+		ecard_t *ec = slot_to_ecard(slot);
+
 		if (ec->claimed) {
-			unsigned int oldexpmask;
+			struct irqdesc *d = irqdesc + ec->irq;
 			/*
 			 * this ugly code is so that we can operate a
 			 * prioritorising system:
@@ -740,17 +736,7 @@
 			 * Serial cards should go in 0/1, ethernet/scsi in 2/3
 			 * otherwise you will lose serial data at high speeds!
 			 */
-			oldexpmask = have_expmask;
-			have_expmask &= priority_masks[slot];
-			__raw_writeb(have_expmask, EXPMASK_ENABLE);
-			sti();
-			do_ecard_IRQ(ec->irq, regs);
-			cli();
-			have_expmask = oldexpmask;
-			__raw_writeb(have_expmask, EXPMASK_ENABLE);
-			status = __raw_readb(EXPMASK_STATUS) & statusmask;
-			if (status)
-				goto again;
+			d->handle(ec->irq, d, regs);
 		} else {
 			printk(KERN_WARNING "card%d: interrupt from unclaimed "
 			       "card???\n", slot);
@@ -761,8 +747,7 @@
 		printk(KERN_WARNING "Wild interrupt from backplane (masks)\n");
 }
 
-static void __init
-ecard_probeirqhw(void)
+static int __init ecard_probeirqhw(void)
 {
 	ecard_t *ec;
 	int found;
@@ -772,24 +757,24 @@
 	found = (__raw_readb(EXPMASK_STATUS) & 15) == 0;
 	__raw_writeb(0xff, EXPMASK_ENABLE);
 
-	if (!found)
-		return;
-
-	printk(KERN_DEBUG "Expansion card interrupt "
-	       "management hardware found\n");
+	if (found) {
+		printk(KERN_DEBUG "Expansion card interrupt "
+		       "management hardware found\n");
 
-	irqexpansioncard.handler = ecard_irq_expmask;
+		/* for each card present, set a bit to '1' */
+		have_expmask = 0x80000000;
 
-	/* for each card present, set a bit to '1' */
-	have_expmask = 0x80000000;
+		for (ec = cards; ec; ec = ec->next)
+			have_expmask |= 1 << ec->slot_no;
 
-	for (ec = cards; ec; ec = ec->next)
-		have_expmask |= 1 << ec->slot_no;
+		__raw_writeb(have_expmask, EXPMASK_ENABLE);
+	}
 
-	__raw_writeb(have_expmask, EXPMASK_ENABLE);
+	return found;
 }
 #else
-#define ecard_probeirqhw()
+#define ecard_irqexp_handler NULL
+#define ecard_probeirqhw() (0)
 #endif
 
 #ifndef IO_EC_MEMC8_BASE
@@ -977,10 +962,9 @@
 	 * hook the interrupt handlers
 	 */
 	if (ec->irq != 0 && ec->irq >= 32) {
-		irq_desc[ec->irq].mask_ack = ecard_disableirq;
-		irq_desc[ec->irq].mask     = ecard_disableirq;
-		irq_desc[ec->irq].unmask   = ecard_enableirq;
-		irq_desc[ec->irq].valid    = 1;
+		set_irq_chip(ec->irq, &ecard_chip);
+		set_irq_handler(ec->irq, do_level_IRQ);
+		set_irq_flags(ec->irq, IRQF_VALID);
 	}
 
 #ifdef CONFIG_ARCH_RPC
@@ -1042,21 +1026,6 @@
 	return finding_pos;
 }
 
-static void __init ecard_free_all(void)
-{
-	ecard_t *ec, *ecn;
-
-	for (ec = cards; ec; ec = ecn) {
-		ecn = ec->next;
-
-		kfree(ec);
-	}
-
-	cards = NULL;
-
-	memset(slot_to_expcard, 0, sizeof(slot_to_expcard));
-}
-
 /*
  * Initialise the expansion card system.
  * Locate all hardware - interrupt management and
@@ -1064,7 +1033,7 @@
  */
 void __init ecard_init(void)
 {
-	int slot;
+	int slot, irqhw;
 
 	/*
 	 * Register our reboot notifier
@@ -1086,13 +1055,10 @@
 	ecard_probe(8, ECARD_IOC);
 #endif
 
-	ecard_probeirqhw();
+	irqhw = ecard_probeirqhw();
 
-	if (setup_arm_irq(IRQ_EXPANSIONCARD, &irqexpansioncard)) {
-		printk(KERN_ERR "Unable to claim IRQ%d for expansion cards\n",
-		       IRQ_EXPANSIONCARD);
-		ecard_free_all();
-	}
+	set_irq_chained_handler(IRQ_EXPANSIONCARD,
+				irqhw ? ecard_irqexp_handler : ecard_irq_handler);
 
 	ecard_proc_init();
 }
diff -urN linux-2.5.6-pre1/arch/arm/kernel/entry-armo.S linux-2.5.6-pre2/arch/arm/kernel/entry-armo.S
--- linux-2.5.6-pre1/arch/arm/kernel/entry-armo.S	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/arch/arm/kernel/entry-armo.S	Thu Feb 28 13:34:18 2002
@@ -354,7 +354,7 @@
 		@
 		adr	lr, 1b
 		orr	lr, lr, #0x08000003		@ Force SVC
-		bne	do_IRQ
+		bne	asm_do_IRQ
 
 		mov	why, #0
 		get_current_task r5
@@ -377,7 +377,7 @@
 		@
 		adr	lr, 1b
 		orr	lr, lr, #0x08000003		@ Force SVC
-		bne	do_IRQ				@ Returns to 1b
+		bne	asm_do_IRQ			@ Returns to 1b
 		SVC_RESTORE_ALL
 
 __irq_invalid:	mov	r0, sp
diff -urN linux-2.5.6-pre1/arch/arm/kernel/entry-armv.S linux-2.5.6-pre2/arch/arm/kernel/entry-armv.S
--- linux-2.5.6-pre1/arch/arm/kernel/entry-armv.S	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/kernel/entry-armv.S	Thu Feb 28 13:34:18 2002
@@ -734,19 +734,22 @@
 		ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
 
 #ifdef CONFIG_PREEMPT
-svc_preempt:	teq	r9, #0
-		movne	pc, lr
+svc_preempt:	teq	r9, #0				@ was preempt count = 0
+		movne	pc, lr				@ no
 		ldr	r0, [r6, #4]			@ local_irq_count
-		ldr	r1, [r6, #8]			@ local_b_count
+		ldr	r1, [r6, #8]			@ local_bh_count
 		adds	r0, r0, r1
 		movne	pc, lr
-1:		set_cpsr_c r0, #MODE_SVC		@ enable IRQs
-		bl	SYMBOL_NAME(preempt_schedule)
+		ldr	r1, [r8, #TI_TASK]
+		set_cpsr_c r2, #MODE_SVC		@ enable IRQs
+		str	r0, [r1, #0]			@ current->state = TASK_RUNNING
+1:		bl	SYMBOL_NAME(schedule)
 		set_cpsr_c r0, #PSR_I_BIT | MODE_SVC	@ disable IRQs
 		ldr	r0, [r8, #TI_FLAGS]
 		tst	r0, #_TIF_NEED_RESCHED
-		bne	1b
-		b	preempt_return
+		beq	preempt_return
+		set_cpsr_c r0, #MODE_SVC		@ enable IRQs
+		b	1b
 #endif
 
 		.align	5
diff -urN linux-2.5.6-pre1/arch/arm/kernel/entry-common.S linux-2.5.6-pre2/arch/arm/kernel/entry-common.S
--- linux-2.5.6-pre1/arch/arm/kernel/entry-common.S	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/kernel/entry-common.S	Thu Feb 28 13:34:18 2002
@@ -55,7 +55,7 @@
  */
 ENTRY(ret_to_user)
 ret_slow_syscall:
-	set_cpsr_c r1, #PSR_I_BIT | MODE_SVC
+	set_cpsr_c r1, #PSR_I_BIT | MODE_SVC	@ disable interrupts
 	ldr	r1, [tsk, #TI_FLAGS]
 	tst	r1, #_TIF_WORK_MASK
 	beq	no_work_pending
@@ -73,12 +73,9 @@
 	b	SYMBOL_NAME(do_notify_resume)	@ note the bl above sets lr
 
 /*
- * This is how we return from a fork.  __switch_to will be calling us
- * with r0 pointing at the previous task that was running (ready for
- * calling schedule_tail).
+ * This is how we return from a fork.
  */
 ENTRY(ret_from_fork)
-	bl	SYMBOL_NAME(schedule_tail)
 	get_thread_info tsk
 	ldr	ip, [tsk, #TI_FLAGS]		@ check for syscall tracing
 	mov	why, #1
diff -urN linux-2.5.6-pre1/arch/arm/kernel/head.S linux-2.5.6-pre2/arch/arm/kernel/head.S
--- linux-2.5.6-pre1/arch/arm/kernel/head.S	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/kernel/head.S	Thu Feb 28 13:34:18 2002
@@ -14,6 +14,7 @@
 
 #include <asm/assembler.h>
 #include <asm/mach-types.h>
+#include <asm/procinfo.h>
 #include <asm/mach/arch.h>
 
 #define K(a,b,c)	((a) << 24 | (b) << 12 | (c))
@@ -126,7 +127,7 @@
 		mov	r1, #MACH_TYPE_L7200
 #endif
 
-		mov	r0, #F_BIT | I_BIT | MODE_SVC	@ make sure svc mode
+		mov	r0, #PSR_F_BIT | PSR_I_BIT | MODE_SVC	@ make sure svc mode
 		msr	cpsr_c, r0			@ and all irqs disabled
 		bl	__lookup_processor_type
 		teq	r10, #0				@ invalid processor?
@@ -374,7 +375,7 @@
 		and	r6, r6, r9			@ mask wanted bits
 		teq	r5, r6
 		moveq	pc, lr
-		add	r10, r10, #36			@ sizeof(proc_info_list)
+		add	r10, r10, #PROC_INFO_SZ		@ sizeof(proc_info_list)
 		cmp	r10, r7
 		blt	1b
 		mov	r10, #0				@ unknown processor
diff -urN linux-2.5.6-pre1/arch/arm/kernel/irq.c linux-2.5.6-pre2/arch/arm/kernel/irq.c
--- linux-2.5.6-pre1/arch/arm/kernel/irq.c	Tue Feb 19 18:10:52 2002
+++ linux-2.5.6-pre2/arch/arm/kernel/irq.c	Thu Feb 28 13:34:18 2002
@@ -34,8 +34,6 @@
 #include <asm/system.h>
 #include <asm/mach/irq.h>
 
-#include <asm/arch/irq.h>	/* pick up fixup_irq definition */
-
 /*
  * Maximum IRQ count.  Currently, this is arbitary.  However, it should
  * not be set too low to prevent false triggering.  Conversely, if it
@@ -54,25 +52,44 @@
 /*
  * Dummy mask/unmask handler
  */
-static void dummy_mask_unmask_irq(unsigned int irq)
+void dummy_mask_unmask_irq(unsigned int irq)
 {
 }
 
+void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+	irq_err_count += 1;
+	printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
+}
+
+static struct irqchip bad_chip = {
+	ack:	dummy_mask_unmask_irq,
+	mask:	dummy_mask_unmask_irq,
+	unmask:	dummy_mask_unmask_irq,
+};
+
+static struct irqdesc bad_irq_desc = {
+	chip:	&bad_chip,
+	handle:	do_bad_IRQ,
+	depth:	1,
+};
+
 /**
  *	disable_irq - disable an irq and wait for completion
  *	@irq: Interrupt to disable
  *
- *	Disable the selected interrupt line.
+ *	Disable the selected interrupt line.  We do this lazily.
  *
- *	This function may be called - with care - from IRQ context.
+ *	This function may be called from IRQ context.
  */
 void disable_irq(unsigned int irq)
 {
+	struct irqdesc *desc = irq_desc + irq;
 	unsigned long flags;
 
 	spin_lock_irqsave(&irq_controller_lock, flags);
-	irq_desc[irq].enabled = 0;
-	irq_desc[irq].mask(irq);
+	if (!desc->depth++)
+		desc->enabled = 0;
 	spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
@@ -80,19 +97,35 @@
  *	enable_irq - enable interrupt handling on an irq
  *	@irq: Interrupt to enable
  *
- *	Re-enables the processing of interrupts on this IRQ line
+ *	Re-enables the processing of interrupts on this IRQ line.
+ *	Note that this may call the interrupt handler, so you may
+ *	get unexpected results if you hold IRQs disabled.
  *
  *	This function may be called from IRQ context.
  */
 void enable_irq(unsigned int irq)
 {
+	struct irqdesc *desc = irq_desc + irq;
 	unsigned long flags;
+	int pending = 0;
 
 	spin_lock_irqsave(&irq_controller_lock, flags);
-	irq_desc[irq].probing = 0;
-	irq_desc[irq].triggered = 0;
-	irq_desc[irq].enabled = 1;
-	irq_desc[irq].unmask(irq);
+	if (unlikely(!desc->depth)) {
+		printk("enable_irq(%u) unbalanced from %p\n", irq,
+			__builtin_return_address(0));
+	} else if (!--desc->depth) {
+		desc->probing = 0;
+		desc->enabled = 1;
+		desc->chip->unmask(irq);
+		pending = desc->pending;
+		desc->pending = 0;
+		/*
+		 * If the interrupt was waiting to be processed,
+		 * retrigger it.
+		 */
+		if (pending)
+			desc->chip->rerun(irq);
+	}
 	spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
@@ -128,7 +161,7 @@
  * a large number if IRQs to appear in the same jiffie with the
  * same instruction pointer (or within 2 instructions).
  */
-static void check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs)
+static int check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs)
 {
 	unsigned long instr_ptr = instruction_pointer(regs);
 
@@ -138,123 +171,283 @@
 
 		if (desc->lck_cnt > MAX_IRQ_CNT) {
 			printk(KERN_ERR "IRQ LOCK: IRQ%d is locking the system, disabled\n", irq);
-			disable_irq(irq);
+			return 1;
 		}
 	} else {
 		desc->lck_cnt = 0;
 		desc->lck_pc  = instruction_pointer(regs);
 		desc->lck_jif = jiffies;
 	}
+	return 0;
+}
+
+static void
+__do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs)
+{
+	unsigned int status;
+
+	spin_unlock(&irq_controller_lock);
+
+	if (!(action->flags & SA_INTERRUPT))
+		__sti();
+
+	status = 0;
+	do {
+		status |= action->flags;
+		action->handler(irq, action->dev_id, regs);
+		action = action->next;
+	} while (action);
+
+	if (status & SA_SAMPLE_RANDOM)
+		add_interrupt_randomness(irq);
+
+	__cli();
+	spin_lock(&irq_controller_lock);
 }
 
 /*
- * do_IRQ handles all normal device IRQ's
+ * This is for software-decoded IRQs.  The caller is expected to
+ * handle the ack, clear, mask and unmask issues.
  */
-asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
+void
+do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
 {
-	struct irqdesc * desc;
-	struct irqaction * action;
-	int cpu;
+	struct irqaction *action;
+	const int cpu = smp_processor_id();
+
+	desc->triggered = 1;
+
+	irq_enter(cpu, irq);
+	kstat.irqs[cpu][irq]++;
+
+	action = desc->action;
+	if (action)
+		__do_irq(irq, desc->action, regs);
+
+	irq_exit(cpu, irq);
+}
+
+/*
+ * Most edge-triggered IRQ implementations seem to take a broken
+ * approach to this.  Hence the complexity.
+ */
+void
+do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+	const int cpu = smp_processor_id();
 
-	irq = fixup_irq(irq);
+	desc->triggered = 1;
 
 	/*
-	 * Some hardware gives randomly wrong interrupts.  Rather
-	 * than crashing, do something sensible.
+	 * If we're currently running this IRQ, or its disabled,
+	 * we shouldn't process the IRQ.  Instead, turn on the
+	 * hardware masks.
 	 */
-	if (irq >= NR_IRQS)
-		goto bad_irq;
+	if (unlikely(desc->running || !desc->enabled))
+		goto running;
 
-	desc = irq_desc + irq;
+	/*
+	 * Acknowledge and clear the IRQ, but don't mask it.
+	 */
+	desc->chip->ack(irq);
 
-	spin_lock(&irq_controller_lock);
-	desc->mask_ack(irq);
-	spin_unlock(&irq_controller_lock);
+	/*
+	 * Mark the IRQ currently in progress.
+	 */
+	desc->running = 1;
 
-	cpu = smp_processor_id();
 	irq_enter(cpu, irq);
 	kstat.irqs[cpu][irq]++;
-	desc->triggered = 1;
 
-	/* Return with this interrupt masked if no action */
-	action = desc->action;
+	do {
+		struct irqaction *action;
 
-	if (action) {
-		int status = 0;
+		action = desc->action;
+		if (!action)
+			break;
 
-		if (desc->nomask) {
-			spin_lock(&irq_controller_lock);
-			desc->unmask(irq);
-			spin_unlock(&irq_controller_lock);
+		if (desc->pending && desc->enabled) {
+			desc->pending = 0;
+			desc->chip->unmask(irq);
 		}
 
-		if (!(action->flags & SA_INTERRUPT))
-			__sti();
+		__do_irq(irq, action, regs);
+	} while (desc->pending);
 
-		do {
-			status |= action->flags;
-			action->handler(irq, action->dev_id, regs);
-			action = action->next;
-		} while (action);
-
-		if (status & SA_SAMPLE_RANDOM)
-			add_interrupt_randomness(irq);
-		__cli();
-
-		if (!desc->nomask && desc->enabled) {
-			spin_lock(&irq_controller_lock);
-			desc->unmask(irq);
-			spin_unlock(&irq_controller_lock);
+	irq_exit(cpu, irq);
+
+	desc->running = 0;
+
+	/*
+	 * If we were disabled or freed, shut down the handler.
+	 */
+	if (likely(desc->action && !check_irq_lock(desc, irq, regs)))
+		return;
+
+ running:
+	/*
+	 * We got another IRQ while this one was masked or
+	 * currently running.  Delay it.
+	 */
+	desc->pending = 1;
+	desc->chip->mask(irq);
+	desc->chip->ack(irq);
+}
+
+/*
+ * Level-based IRQ handler.  Nice and simple.
+ */
+void
+do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+	struct irqaction *action;
+	const int cpu = smp_processor_id();
+
+	desc->triggered = 1;
+
+	/*
+	 * Acknowledge, clear _AND_ disable the interrupt.
+	 */
+	desc->chip->ack(irq);
+
+	if (likely(desc->enabled)) {
+		irq_enter(cpu, irq);
+		kstat.irqs[cpu][irq]++;
+
+		/*
+		 * Return with this interrupt masked if no action
+		 */
+		action = desc->action;
+		if (action) {
+			__do_irq(irq, desc->action, regs);
+
+			if (likely(desc->enabled &&
+				   !check_irq_lock(desc, irq, regs)))
+				desc->chip->unmask(irq);
 		}
 	}
 
+	irq_exit(cpu, irq);
+}
+
+/*
+ * do_IRQ handles all hardware IRQ's.  Decoded IRQs should not
+ * come via this function.  Instead, they should provide their
+ * own 'handler'
+ */
+asmlinkage void asm_do_IRQ(int irq, struct pt_regs *regs)
+{
+	struct irqdesc *desc = irq_desc + irq;
+
 	/*
-	 * Debug measure - hopefully we can continue if an
-	 * IRQ lockup problem occurs...
+	 * Some hardware gives randomly wrong interrupts.  Rather
+	 * than crashing, do something sensible.
 	 */
-	check_irq_lock(desc, irq, regs);
+	if (irq >= NR_IRQS)
+		desc = &bad_irq_desc;
 
-	irq_exit(cpu, irq);
+	spin_lock(&irq_controller_lock);
+	desc->handle(irq, desc, regs);
+	spin_unlock(&irq_controller_lock);
 
-	if (softirq_pending(cpu))
+	if (softirq_pending(smp_processor_id()))
 		do_softirq();
-	return;
+}
 
-bad_irq:
-	irq_err_count += 1;
-	printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
-	return;
+void __set_irq_handler(unsigned int irq, irq_handler_t handle, int is_chained)
+{
+	struct irqdesc *desc;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS) {
+		printk(KERN_ERR "Trying to install handler for IRQ%d\n", irq);
+		return;
+	}
+
+	if (handle == NULL)
+		handle = do_bad_IRQ;
+
+	desc = irq_desc + irq;
+
+	if (is_chained && desc->chip == &bad_chip)
+		printk(KERN_WARNING "Trying to install chained handler for IRQ%d\n", irq);
+
+	spin_lock_irqsave(&irq_controller_lock, flags);
+	if (handle == do_bad_IRQ) {
+		desc->chip->mask(irq);
+		desc->chip->ack(irq);
+		desc->depth = 1;
+		desc->enabled = 0;
+	}
+	desc->handle = handle;
+	if (handle != do_bad_IRQ && is_chained) {
+		desc->valid = 0;
+		desc->probe_ok = 0;
+		desc->depth = 0;
+		desc->chip->unmask(irq);
+	}
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
-#ifdef CONFIG_ARCH_ACORN
-void do_ecard_IRQ(int irq, struct pt_regs *regs)
+void set_irq_chip(unsigned int irq, struct irqchip *chip)
 {
-	struct irqdesc * desc;
-	struct irqaction * action;
-	int cpu;
+	struct irqdesc *desc;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS) {
+		printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq);
+		return;
+	}
+
+	if (chip == NULL)
+		chip = &bad_chip;
 
 	desc = irq_desc + irq;
+	spin_lock_irqsave(&irq_controller_lock, flags);
+	desc->chip = chip;
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
 
-	cpu = smp_processor_id();
-	kstat.irqs[cpu][irq]++;
-	desc->triggered = 1;
+int set_irq_type(unsigned int irq, unsigned int type)
+{
+	struct irqdesc *desc;
+	unsigned long flags;
+	int ret = -ENXIO;
 
-	action = desc->action;
+	if (irq >= NR_IRQS) {
+		printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq);
+		return -ENODEV;
+	}
 
-	if (action) {
-		do {
-			action->handler(irq, action->dev_id, regs);
-			action = action->next;
-		} while (action);
-	} else {
-		spin_lock(&irq_controller_lock);
-		desc->mask(irq);
-		spin_unlock(&irq_controller_lock);
+	desc = irq_desc + irq;
+	if (desc->chip->type) {
+		spin_lock_irqsave(&irq_controller_lock, flags);
+		ret = desc->chip->type(irq, type);
+		spin_unlock_irqrestore(&irq_controller_lock, flags);
 	}
+
+	return ret;
+}
+
+void set_irq_flags(unsigned int irq, unsigned int iflags)
+{
+	struct irqdesc *desc;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS) {
+		printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
+		return;
+	}
+
+	desc = irq_desc + irq;
+	spin_lock_irqsave(&irq_controller_lock, flags);
+	desc->valid = (iflags & IRQF_VALID) != 0;
+	desc->probe_ok = (iflags & IRQF_PROBE) != 0;
+	desc->noautoenable = (iflags & IRQF_NOAUTOEN) != 0;
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
-#endif
 
-int setup_arm_irq(int irq, struct irqaction * new)
+int setup_irq(unsigned int irq, struct irqaction *new)
 {
 	int shared = 0;
 	struct irqaction *old, **p;
@@ -302,11 +495,14 @@
 	*p = new;
 
 	if (!shared) {
-		desc->nomask = (new->flags & SA_IRQNOMASK) ? 1 : 0;
-		desc->probing = 0;
+ 		desc->probing = 0;
+		desc->running = 0;
+		desc->pending = 0;
+		desc->depth = 1;
 		if (!desc->noautoenable) {
+			desc->depth = 0;
 			desc->enabled = 1;
-			desc->unmask(irq);
+			desc->chip->unmask(irq);
 		}
 	}
 
@@ -366,7 +562,7 @@
 	action->next = NULL;
 	action->dev_id = dev_id;
 
-	retval = setup_arm_irq(irq, action);
+	retval = setup_irq(irq, action);
 
 	if (retval)
 		kfree(action);
@@ -433,14 +629,12 @@
 	 */
 	spin_lock_irq(&irq_controller_lock);
 	for (i = 0; i < NR_IRQS; i++) {
-		if (!irq_desc[i].valid ||
-		    !irq_desc[i].probe_ok ||
-		    irq_desc[i].action)
+		if (!irq_desc[i].probe_ok || irq_desc[i].action)
 			continue;
 
 		irq_desc[i].probing = 1;
 		irq_desc[i].triggered = 0;
-		irq_desc[i].unmask(i);
+		irq_desc[i].chip->unmask(i);
 		irqs += 1;
 	}
 	spin_unlock_irq(&irq_controller_lock);
@@ -456,15 +650,13 @@
 	 */
 	spin_lock_irq(&irq_controller_lock);
 	for (i = 0; i < NR_IRQS; i++) {
-		if (irq_desc[i].probing &&
-		    irq_desc[i].triggered) {
+		if (irq_desc[i].probing && irq_desc[i].triggered) {
 			irq_desc[i].probing = 0;
 			irqs -= 1;
 		}
 	}
 	spin_unlock_irq(&irq_controller_lock);
 
-	/* now filter out any obviously spurious interrupts */
 	return irqs;
 }
 
@@ -508,17 +700,12 @@
 
 void __init init_IRQ(void)
 {
+	struct irqdesc *desc;
 	extern void init_dma(void);
 	int irq;
 
-	for (irq = 0; irq < NR_IRQS; irq++) {
-		irq_desc[irq].probe_ok = 0;
-		irq_desc[irq].valid    = 0;
-		irq_desc[irq].noautoenable = 0;
-		irq_desc[irq].mask_ack = dummy_mask_unmask_irq;
-		irq_desc[irq].mask     = dummy_mask_unmask_irq;
-		irq_desc[irq].unmask   = dummy_mask_unmask_irq;
-	}
+	for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++)
+		*desc = bad_irq_desc;
 
 	init_arch_irq();
 	init_dma();
diff -urN linux-2.5.6-pre1/arch/arm/kernel/ptrace.c linux-2.5.6-pre2/arch/arm/kernel/ptrace.c
--- linux-2.5.6-pre1/arch/arm/kernel/ptrace.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/kernel/ptrace.c	Thu Feb 28 13:34:18 2002
@@ -34,7 +34,7 @@
 /*
  * Breakpoint SWI instruction: SWI &9F0001
  */
-#define BREAKINST	0xef9f0001
+#define BREAKINST_ARM	0xef9f0001
 
 /*
  * Get the address of the live pt_regs for the specified task.
@@ -183,6 +183,20 @@
 	return val;
 }
 
+#define OP_MASK	0x01e00000
+#define OP_AND	0x00000000
+#define OP_EOR	0x00200000
+#define OP_SUB	0x00400000
+#define OP_RSB	0x00600000
+#define OP_ADD	0x00800000
+#define OP_ADC	0x00a00000
+#define OP_SBC	0x00c00000
+#define OP_RSC	0x00e00000
+#define OP_ORR	0x01800000
+#define OP_MOV	0x01a00000
+#define OP_BIC	0x01c00000
+#define OP_MVN	0x01e00000
+
 static unsigned long
 get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn)
 {
@@ -201,21 +215,21 @@
 
 		aluop1 = ptrace_getrn(child, insn);
 		aluop2 = ptrace_getaluop2(child, insn);
-		ccbit  = get_stack_long(child, REG_PSR) & CC_C_BIT ? 1 : 0;
+		ccbit  = get_stack_long(child, REG_PSR) & PSR_C_BIT ? 1 : 0;
 
-		switch (insn & 0x01e00000) {
-		case 0x00000000: alt = aluop1 & aluop2;		break;
-		case 0x00200000: alt = aluop1 ^ aluop2;		break;
-		case 0x00400000: alt = aluop1 - aluop2;		break;
-		case 0x00600000: alt = aluop2 - aluop1;		break;
-		case 0x00800000: alt = aluop1 + aluop2;		break;
-		case 0x00a00000: alt = aluop1 + aluop2 + ccbit;	break;
-		case 0x00c00000: alt = aluop1 - aluop2 + ccbit;	break;
-		case 0x00e00000: alt = aluop2 - aluop1 + ccbit;	break;
-		case 0x01800000: alt = aluop1 | aluop2;		break;
-		case 0x01a00000: alt = aluop2;			break;
-		case 0x01c00000: alt = aluop1 & ~aluop2;	break;
-		case 0x01e00000: alt = ~aluop2;			break;
+		switch (insn & OP_MASK) {
+		case OP_AND: alt = aluop1 & aluop2;		break;
+		case OP_EOR: alt = aluop1 ^ aluop2;		break;
+		case OP_SUB: alt = aluop1 - aluop2;		break;
+		case OP_RSB: alt = aluop2 - aluop1;		break;
+		case OP_ADD: alt = aluop1 + aluop2;		break;
+		case OP_ADC: alt = aluop1 + aluop2 + ccbit;	break;
+		case OP_SBC: alt = aluop1 - aluop2 + ccbit;	break;
+		case OP_RSC: alt = aluop2 - aluop1 + ccbit;	break;
+		case OP_ORR: alt = aluop1 | aluop2;		break;
+		case OP_MOV: alt = aluop2;			break;
+		case OP_BIC: alt = aluop1 & ~aluop2;		break;
+		case OP_MVN: alt = ~aluop2;			break;
 		}
 		break;
 	}
@@ -276,7 +290,7 @@
 			base = ptrace_getrn(child, insn);
 
 			if (read_tsk_long(child, base + nr_regs, &alt) == 0)
-				alt = pc_pointer (alt);
+				alt = pc_pointer(alt);
 			break;
 		}
 		break;
@@ -313,7 +327,7 @@
 	if (nr < 2) {
 		res = read_tsk_long(child, addr, &dbg->bp[nr].insn);
 		if (res == 0)
-			res = write_tsk_long(child, addr, BREAKINST);
+			res = write_tsk_long(child, addr, BREAKINST_ARM);
 
 		if (res == 0) {
 			dbg->bp[nr].address = addr;
@@ -382,7 +396,7 @@
 
 		read_tsk_long(child, dbg->bp[i].address, &tmp);
 		write_tsk_long(child, dbg->bp[i].address, dbg->bp[i].insn);
-		if (tmp != BREAKINST)
+		if (tmp != BREAKINST_ARM)
 			printk(KERN_ERR "ptrace_cancel_bpt: weirdness\n");
 	}
 }
diff -urN linux-2.5.6-pre1/arch/arm/kernel/setup.c linux-2.5.6-pre2/arch/arm/kernel/setup.c
--- linux-2.5.6-pre1/arch/arm/kernel/setup.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/kernel/setup.c	Thu Feb 28 13:34:18 2002
@@ -73,6 +73,9 @@
 #ifdef MULTI_CPU
 struct processor processor;
 #endif
+#ifdef MULTI_TLB
+struct cpu_tlb_fns cpu_tlb;
+#endif
 
 unsigned char aux_device_present;
 char elf_platform[ELF_PLATFORM_SIZE];
@@ -180,7 +183,7 @@
 
 static inline void dump_cache(const char *prefix, unsigned int cache)
 {
-	unsigned int mult = 2 + CACHE_M(cache) ? 1 : 0;
+	unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
 
 	printk("%s size %dK associativity %d line length %d sets %d\n",
 		prefix,
@@ -242,6 +245,9 @@
 #ifdef MULTI_CPU
 	processor = *list->proc;
 #endif
+#ifdef MULTI_TLB
+	cpu_tlb = *list->tlb;
+#endif
 
 	printk("Processor: %s %s revision %d\n",
 	       proc_info.manufacturer, proc_info.cpu_name,
@@ -665,7 +671,7 @@
 static void
 c_show_cache(struct seq_file *m, const char *type, unsigned int cache)
 {
-	unsigned int mult = 2 + CACHE_M(cache) ? 1 : 0;
+	unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
 
 	seq_printf(m, "%s size\t\t: %d\n"
 		      "%s assoc\t\t: %d\n"
@@ -738,7 +744,7 @@
 				   cache_types[CACHE_TYPE(cache_info)],
 				   cache_clean[CACHE_TYPE(cache_info)],
 				   cache_lockdown[CACHE_TYPE(cache_info)],
-				   CACHE_S(cache_info) ? "separate I,D" : "unified");
+				   CACHE_S(cache_info) ? "Harvard" : "Unified");
 
 			if (CACHE_S(cache_info)) {
 				c_show_cache(m, "I", CACHE_ISIZE(cache_info));
diff -urN linux-2.5.6-pre1/arch/arm/kernel/signal.c linux-2.5.6-pre2/arch/arm/kernel/signal.c
--- linux-2.5.6-pre1/arch/arm/kernel/signal.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/kernel/signal.c	Thu Feb 28 13:34:18 2002
@@ -396,8 +396,12 @@
 		if (__put_user(retcodes[idx], rc))
 			return 1;
 
-		flush_icache_range((unsigned long)rc,
-				   (unsigned long)(rc + 1));
+		/*
+		 * Ensure that the instruction cache sees
+		 * the return code written onto the stack.
+		 */
+		cpu_icache_invalidate_range((unsigned long)rc,
+					    (unsigned long)(rc + 1));
 
 		retcode = ((unsigned long)rc) + thumb;
 	}
diff -urN linux-2.5.6-pre1/arch/arm/kernel/time.c linux-2.5.6-pre2/arch/arm/kernel/time.c
--- linux-2.5.6-pre1/arch/arm/kernel/time.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/arch/arm/kernel/time.c	Thu Feb 28 13:34:18 2002
@@ -31,10 +31,16 @@
 #include <asm/irq.h>
 #include <asm/leds.h>
 
-extern int setup_arm_irq(int, struct irqaction *);
 extern rwlock_t xtime_lock;
 extern unsigned long wall_jiffies;
 
+/* this needs a better home */
+spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+
+#ifdef CONFIG_SA1100_RTC_MODULE
+EXPORT_SYMBOL(rtc_lock);
+#endif
+
 /* change this if you have some constant time drift */
 #define USECS_PER_JIFFY	(1000000/HZ)
 
diff -urN linux-2.5.6-pre1/arch/arm/kernel/traps.c linux-2.5.6-pre2/arch/arm/kernel/traps.c
--- linux-2.5.6-pre1/arch/arm/kernel/traps.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/kernel/traps.c	Thu Feb 28 13:34:18 2002
@@ -95,7 +95,7 @@
 	int i;
 
 	printk("Code: ");
-	for (i = -2; i < 3; i++) {
+	for (i = -4; i < 1; i++) {
 		unsigned int val, bad;
 
 		if (thumb)
diff -urN linux-2.5.6-pre1/arch/arm/kernel/via82c505.c linux-2.5.6-pre2/arch/arm/kernel/via82c505.c
--- linux-2.5.6-pre1/arch/arm/kernel/via82c505.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/arch/arm/kernel/via82c505.c	Thu Feb 28 13:34:18 2002
@@ -74,85 +74,7 @@
 	via82c505_write_config_dword,
 };
 
-#ifdef CONFIG_ARCH_SHARK
-
-static char size_wanted;
-
-static int
-dummy_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-	*value=0;
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-dummy_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-	*value=0;
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-dummy_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-	if (dev->devfn != 0) *value = 0;
-	else
-	  switch(where) {
-	  case PCI_VENDOR_ID:
-	    *value = PCI_VENDOR_ID_INTERG | PCI_DEVICE_ID_INTERG_2010 << 16;
-	    break;
-	  case PCI_CLASS_REVISION:
-	    *value = PCI_CLASS_DISPLAY_VGA << 16;
-	    break;
-	  case PCI_BASE_ADDRESS_0:
-	    if (size_wanted) {
-	      /* 0x00900000 bytes long (0xff700000) */
-	      *value = 0xff000000;
-	      size_wanted = 0;
-	    } else {
-	      *value = FB_START;
-	    }
-	    break;
-	  case PCI_INTERRUPT_LINE:
-	    *value = 6;
-	    break;
-	  default:
-	    *value = 0;
-	  }
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-dummy_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-dummy_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-dummy_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-	if ((dev->devfn == 0) && (where == PCI_BASE_ADDRESS_0) && (value == 0xffffffff))
-	  size_wanted = 1;
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops dummy_ops = {
-	dummy_read_config_byte,
-	dummy_read_config_word,
-	dummy_read_config_dword,
-	dummy_write_config_byte,
-	dummy_write_config_word,
-	dummy_write_config_dword,
-};
-#endif
-
-void __init via82c505_init(void *sysdata)
+void __init via82c505_preinit(void *sysdata)
 {
 	struct pci_bus *bus;
 
@@ -166,13 +88,17 @@
 	outb(0x93,0xA8);
 	outb(0xd0,0xA9);
 
-	pci_scan_bus(0, &via82c505_ops, sysdata);
+}
+
+int __init via82c505_setup(int nr, struct pci_sys_data *sys)
+{
+	return (nr == 0);
+}
+
+struct pci_bus * __init via82c505_scan_bus(int nr, struct pci_sys_data *sysdata)
+{
+	if (nr == 0)
+		return pci_scan_bus(0, &via82c505_ops, sysdata);
 
-#ifdef CONFIG_ARCH_SHARK
-	/* 
-	 * Initialize a fake pci-bus number 1 for the CyberPro
-         * on the vlbus
-	 */
-	bus = pci_scan_bus(1, &dummy_ops, sysdata);
-#endif
+	return NULL;
 }
diff -urN linux-2.5.6-pre1/arch/arm/lib/Makefile linux-2.5.6-pre2/arch/arm/lib/Makefile
--- linux-2.5.6-pre1/arch/arm/lib/Makefile	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/arch/arm/lib/Makefile	Thu Feb 28 13:34:18 2002
@@ -44,8 +44,6 @@
 obj-y		+= io-writesl.o
 
 obj-$(CONFIG_CPU_26) += uaccess-armo.o
-obj-$(CONFIG_CPU_32) += copy_page-armv3.o copy_page-armv4.o copy_page-armv4mc.o
-obj-$(CONFIG_CPU_32v5) += copy_page-armv5te.o
 
 include $(TOPDIR)/Rules.make
 
diff -urN linux-2.5.6-pre1/arch/arm/lib/copy_page-armv3.S linux-2.5.6-pre2/arch/arm/lib/copy_page-armv3.S
--- linux-2.5.6-pre1/arch/arm/lib/copy_page-armv3.S	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/arch/arm/lib/copy_page-armv3.S	Wed Dec 31 16:00:00 1969
@@ -1,59 +0,0 @@
-/*
- *  linux/arch/arm/lib/copypage.S
- *
- *  Copyright (C) 1995-1999 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.
- *
- *  ASM optimised string functions
- */
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-#include <asm/constants.h>
-
-		.text
-		.align	5
-/*
- * ARMv3 optimised copy_user_page
- *
- * FIXME: do we need to handle cache stuff...
- */
-ENTRY(armv3_copy_user_page)
-	stmfd	sp!, {r4, lr}			@	2
-	mov	r2, #PAGE_SZ/64			@	1
-	ldmia	r1!, {r3, r4, ip, lr}		@	4+1
-1:	stmia	r0!, {r3, r4, ip, lr}		@	4
-	ldmia	r1!, {r3, r4, ip, lr}		@	4+1
-	stmia	r0!, {r3, r4, ip, lr}		@	4
-	ldmia	r1!, {r3, r4, ip, lr}		@	4+1
-	stmia	r0!, {r3, r4, ip, lr}		@	4
-	ldmia	r1!, {r3, r4, ip, lr}		@	4
-	subs	r2, r2, #1			@	1
-	stmia	r0!, {r3, r4, ip, lr}		@	4
-	ldmneia	r1!, {r3, r4, ip, lr}		@	4
-	bne	1b				@	1
-	LOADREGS(fd, sp!, {r4, pc})		@	3
-
-	.align	5
-/*
- * ARMv3 optimised clear_user_page
- *
- * FIXME: do we need to handle cache stuff...
- */
-ENTRY(armv3_clear_user_page)
-	str	lr, [sp, #-4]!
-	mov	r1, #PAGE_SZ/64			@ 1
-	mov	r2, #0				@ 1
-	mov	r3, #0				@ 1
-	mov	ip, #0				@ 1
-	mov	lr, #0				@ 1
-1:	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	subs	r1, r1, #1			@ 1
-	bne	1b				@ 1
-	ldr	pc, [sp], #4
-
diff -urN linux-2.5.6-pre1/arch/arm/lib/copy_page-armv4.S linux-2.5.6-pre2/arch/arm/lib/copy_page-armv4.S
--- linux-2.5.6-pre1/arch/arm/lib/copy_page-armv4.S	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/arch/arm/lib/copy_page-armv4.S	Wed Dec 31 16:00:00 1969
@@ -1,70 +0,0 @@
-/*
- *  linux/arch/arm/lib/copypage.S
- *
- *  Copyright (C) 1995-1999 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.
- *
- *  ASM optimised string functions
- */
-#include <linux/linkage.h>
-#include <asm/constants.h>
-
-	.text
-	.align	5
-/*
- * ARMv4 optimised copy_user_page
- *
- * We flush the destination cache lines just before we write the data into the
- * corresponding address.  Since the Dcache is read-allocate, this removes the
- * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
- * and merged as appropriate.
- *
- * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
- * instruction.  If your processor does not supply this, you have to write your
- * own copy_user_page that does the right thing.
- */
-ENTRY(armv4_copy_user_page)
-	stmfd	sp!, {r4, lr}			@ 2
-	mov	r2, #PAGE_SZ/64			@ 1
-	ldmia	r1!, {r3, r4, ip, lr}		@ 4
-1:	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line
-	stmia	r0!, {r3, r4, ip, lr}		@ 4
-	ldmia	r1!, {r3, r4, ip, lr}		@ 4+1
-	stmia	r0!, {r3, r4, ip, lr}		@ 4
-	ldmia	r1!, {r3, r4, ip, lr}		@ 4
-	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line
-	stmia	r0!, {r3, r4, ip, lr}		@ 4
-	ldmia	r1!, {r3, r4, ip, lr}		@ 4
-	subs	r2, r2, #1			@ 1
-	stmia	r0!, {r3, r4, ip, lr}		@ 4
-	ldmneia	r1!, {r3, r4, ip, lr}		@ 4
-	bne	1b				@ 1
-	mcr	p15, 0, r1, c7, c10, 4		@ 1   drain WB
-	ldmfd	 sp!, {r4, pc}			@ 3
-
-	.align	5
-/*
- * ARMv4 optimised clear_user_page
- *
- * Same story as above.
- */
-ENTRY(armv4_clear_user_page)
-	str	lr, [sp, #-4]!
-	mov	r1, #PAGE_SZ/64			@ 1
-	mov	r2, #0				@ 1
-	mov	r3, #0				@ 1
-	mov	ip, #0				@ 1
-	mov	lr, #0				@ 1
-1:	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line
-	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line
-	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	subs	r1, r1, #1			@ 1
-	bne	1b				@ 1
-	mcr	p15, 0, r1, c7, c10, 4		@ 1   drain WB
-	ldr	pc, [sp], #4
diff -urN linux-2.5.6-pre1/arch/arm/lib/copy_page-armv4mc.S linux-2.5.6-pre2/arch/arm/lib/copy_page-armv4mc.S
--- linux-2.5.6-pre1/arch/arm/lib/copy_page-armv4mc.S	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/arch/arm/lib/copy_page-armv4mc.S	Wed Dec 31 16:00:00 1969
@@ -1,71 +0,0 @@
-/*
- *  linux/arch/arm/lib/copy_page-armv4mc.S
- *
- *  Copyright (C) 1995-2001 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  ASM optimised string functions
- */
-#include <linux/linkage.h>
-#include <asm/constants.h>
-
-	.text
-	.align	5
-/*
- * ARMv4 mini-dcache optimised copy_user_page
- *
- * We flush the destination cache lines just before we write the data into the
- * corresponding address.  Since the Dcache is read-allocate, this removes the
- * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
- * and merged as appropriate.
- *
- * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
- * instruction.  If your processor does not supply this, you have to write your
- * own copy_user_page that does the right thing.
- */
-ENTRY(armv4_mc_copy_user_page)
-	stmfd	sp!, {r4, lr}			@ 2
-	mov	r4, r0
-	mov	r0, r1
-	bl	map_page_minicache
-	mov	r1, #PAGE_SZ/64			@ 1
-	ldmia	r0!, {r2, r3, ip, lr}		@ 4
-1:	mcr	p15, 0, r4, c7, c6, 1		@ 1   invalidate D line
-	stmia	r4!, {r2, r3, ip, lr}		@ 4
-	ldmia	r0!, {r2, r3, ip, lr}		@ 4+1
-	stmia	r4!, {r2, r3, ip, lr}		@ 4
-	ldmia	r0!, {r2, r3, ip, lr}		@ 4
-	mcr	p15, 0, r4, c7, c6, 1		@ 1   invalidate D line
-	stmia	r4!, {r2, r3, ip, lr}		@ 4
-	ldmia	r0!, {r2, r3, ip, lr}		@ 4
-	subs	r1, r1, #1			@ 1
-	stmia	r4!, {r2, r3, ip, lr}		@ 4
-	ldmneia	r0!, {r2, r3, ip, lr}		@ 4
-	bne	1b				@ 1
-	ldmfd	sp!, {r4, pc}			@ 3
-
-	.align	5
-/*
- * ARMv4 optimised clear_user_page
- *
- * Same story as above.
- */
-ENTRY(armv4_mc_clear_user_page)
-	str	lr, [sp, #-4]!
-	mov	r1, #PAGE_SZ/64			@ 1
-	mov	r2, #0				@ 1
-	mov	r3, #0				@ 1
-	mov	ip, #0				@ 1
-	mov	lr, #0				@ 1
-1:	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line
-	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line
-	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	stmia	r0!, {r2, r3, ip, lr}		@ 4
-	subs	r1, r1, #1			@ 1
-	bne	1b				@ 1
-	ldr	pc, [sp], #4
diff -urN linux-2.5.6-pre1/arch/arm/lib/copy_page-armv5te.S linux-2.5.6-pre2/arch/arm/lib/copy_page-armv5te.S
--- linux-2.5.6-pre1/arch/arm/lib/copy_page-armv5te.S	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/arch/arm/lib/copy_page-armv5te.S	Wed Dec 31 16:00:00 1969
@@ -1,79 +0,0 @@
-/*
- *  linux/arch/arm/lib/copypage-armv5te.S
- *
- *  Copyright (C) 2001 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/linkage.h>
-#include <asm/constants.h>
-
-/*
- * General note:
- *  We don't really want write-allocate cache behaviour for these functions
- *  since that will just eat through 8K of the cache.
- */
-
-	.text
-	.align	5
-/*
- * ARMv5TE optimised copy_user_page
- *  r0 = destination
- *  r1 = source
- *  r2 = virtual user address of ultimate destination page
- *
- * The source page may have some clean entries in the cache already, but we
- * can safely ignore them - break_cow() will flush them out of the cache
- * if we eventually end up using our copied page.
- *
- * What we could do is use the mini-cache to buffer reads from the source
- * page.  We rely on the mini-cache being smaller than one page, so we'll
- * cycle through the complete cache anyway.
- */
-ENTRY(armv5te_copy_user_page)
-	stmfd	sp!, {r4, r5, lr}
-	mov	r5, r0
-	mov	r0, r1
-	bl	map_page_minicache
-	mov	r1, r5
-	mov	lr, #PAGE_SZ/32
-
-1:	mov	ip, r1
-	ldrd	r2, [r0], #8
-	ldrd	r4, [r0], #8
-	strd	r2, [r1], #8
-	ldrd	r2, [r0], #8
-	strd	r4, [r1], #8
-	ldrd	r4, [r0], #8
-	strd	r2, [r1], #8
-	strd	r4, [r1], #8
-	mcr	p15, 0, ip, c7, c10, 1		@ clean D line
-	mcr	p15, 0, ip, c7, c6, 1		@ invalidate D line
-	subs	lr, lr, #1
-	bne	1b
-
-	ldmfd	sp!, {r4, r5, pc}
-
-	.align	5
-/*
- * ARMv5TE optimised clear_user_page
- *  r0 = destination
- *  r1 = virtual user address of ultimate destination page
- */
-ENTRY(armv5te_clear_user_page)
-	str	lr, [sp, #-4]!
-	mov	r1, #PAGE_SZ/32
-	mov	r2, #0
-	mov	r3, #0
-1:	mov	ip, r0
-	strd	r2, [r0], #8
-	strd	r2, [r0], #8
-	strd	r2, [r0], #8
-	strd	r2, [r0], #8
-	mcr	p15, 0, ip, c7, c10, 1		@ clean D line
-	mcr	p15, 0, ip, c7, c6, 1		@ invalidate D line
-	subs	r1, r1, #1
-	bne	1b
-	ldr	pc, [sp], #4
diff -urN linux-2.5.6-pre1/arch/arm/lib/ecard.S linux-2.5.6-pre2/arch/arm/lib/ecard.S
--- linux-2.5.6-pre1/arch/arm/lib/ecard.S	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/arch/arm/lib/ecard.S	Thu Feb 28 13:34:18 2002
@@ -12,7 +12,7 @@
 #include <asm/assembler.h>
 #include <asm/hardware.h>
 
-#if defined(CONFIG_CPU_26)
+#ifdef CONFIG_CPU_26
 #define CPSR2SPSR(rt)
 #else
 #define CPSR2SPSR(rt) \
diff -urN linux-2.5.6-pre1/arch/arm/lib/io-acorn.S linux-2.5.6-pre2/arch/arm/lib/io-acorn.S
--- linux-2.5.6-pre1/arch/arm/lib/io-acorn.S	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/arch/arm/lib/io-acorn.S	Thu Feb 28 13:34:18 2002
@@ -58,7 +58,7 @@
 @ Proto  : void memc_write(int register, int value);
 @ Returns: nothing
 
-#if defined(CONFIG_CPU_26)
+#ifdef CONFIG_CPU_26
 ENTRY(memc_write)
 		cmp	r0, #7
 		RETINSTR(movgt,pc,lr)
diff -urN linux-2.5.6-pre1/arch/arm/mach-arc/dma.c linux-2.5.6-pre2/arch/arm/mach-arc/dma.c
--- linux-2.5.6-pre1/arch/arm/mach-arc/dma.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/arch/arm/mach-arc/dma.c	Thu Feb 28 13:34:18 2002
@@ -28,6 +28,10 @@
 static void arc_floppy_data_enable_dma(dmach_t channel, dma_t *dma)
 {
 	DPRINTK("arc_floppy_data_enable_dma\n");
+
+	if (dma->using_sg)
+		BUG();
+
 	switch (dma->dma_mode) {
 	case DMA_MODE_READ: { /* read */
 		extern unsigned char fdc1772_dma_read, fdc1772_dma_read_end;
@@ -39,7 +43,7 @@
 			
 		memcpy ((void *)0x1c, (void *)&fdc1772_dma_read,
 			&fdc1772_dma_read_end - &fdc1772_dma_read);
-		fdc1772_setupdma(dma->buf.length, dma->buf.address); /* Sets data pointer up */
+		fdc1772_setupdma(dma->buf.length, dma->buf.__address); /* Sets data pointer up */
 		enable_fiq(FIQ_FLOPPYDATA);
 		restore_flags(flags);
 	   }
@@ -54,7 +58,7 @@
 		clf();
 		memcpy ((void *)0x1c, (void *)&fdc1772_dma_write,
 			&fdc1772_dma_write_end - &fdc1772_dma_write);
-		fdc1772_setupdma(dma->buf.length, dma->buf.address); /* Sets data pointer up */
+		fdc1772_setupdma(dma->buf.length, dma->buf.__address); /* Sets data pointer up */
 		enable_fiq(FIQ_FLOPPYDATA;
 
 		restore_flags(flags);
@@ -140,6 +144,9 @@
 	extern void floppy_fiqsetup(unsigned long len, unsigned long addr,
 				     unsigned long port);
 
+	if (dma->using_sg)
+		BUG();
+
 	if (dma->dma_mode == DMA_MODE_READ) {
 		extern unsigned char floppy_fiqin_start, floppy_fiqin_end;
 		fiqhandler_start = &floppy_fiqin_start;
@@ -155,7 +162,7 @@
 	}
 	memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length);
 	regs.ARM_r9 = dma->buf.length;
-	regs.ARM_r10 = (unsigned long)dma->buf.address;
+	regs.ARM_r10 = (unsigned long)dma->buf.__address;
 	regs.ARM_fp = FLOPPYDMA_BASE;
 	set_fiq_regs(&regs);
 	enable_fiq(dma->dma_irq);
diff -urN linux-2.5.6-pre1/arch/arm/mach-clps711x/Makefile linux-2.5.6-pre2/arch/arm/mach-clps711x/Makefile
--- linux-2.5.6-pre1/arch/arm/mach-clps711x/Makefile	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/arch/arm/mach-clps711x/Makefile	Thu Feb 28 13:34:18 2002
@@ -21,9 +21,10 @@
 obj-$(CONFIG_ARCH_AUTCPU12) += autcpu12.o
 obj-$(CONFIG_ARCH_CDB89712) += cdb89712.o
 obj-$(CONFIG_ARCH_CLEP7312) += clep7312.o
-obj-$(CONFIG_ARCH_EDB7211) += edb7211-arch.o edb7211-mm.o
-obj-$(CONFIG_ARCH_P720T) += p720t.o
-leds-$(CONFIG_ARCH_P720T) += p720t-leds.o
-obj-$(CONFIG_LEDS)	+= $(leds-y)
+obj-$(CONFIG_ARCH_EDB7211)  += edb7211-arch.o edb7211-mm.o
+obj-$(CONFIG_ARCH_FORTUNET) += fortunet.o
+obj-$(CONFIG_ARCH_P720T)    += p720t.o
+leds-$(CONFIG_ARCH_P720T)   += p720t-leds.o
+obj-$(CONFIG_LEDS)          += $(leds-y)
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.5.6-pre1/arch/arm/mach-clps711x/fortunet.c linux-2.5.6-pre2/arch/arm/mach-clps711x/fortunet.c
--- linux-2.5.6-pre1/arch/arm/mach-clps711x/fortunet.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mach-clps711x/fortunet.c	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,81 @@
+/*
+ *  linux/arch/arm/mach-clps711x/fortunet.c
+ *
+ *  Derived from linux/arch/arm/mach-integrator/arch.c
+ *
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/amba_kmi.h>
+
+extern void clps711x_map_io(void);
+extern void clps711x_init_irq(void);
+
+struct meminfo memmap = { 1, 0xC1000000, {{0xC0000000,0x01000000,0}}};
+
+typedef struct tag_IMAGE_PARAMS
+{
+	int	ramdisk_ok;
+	int	ramdisk_address;
+	int	ramdisk_size;
+	int	ram_size;
+	int	extra_param_type;
+	int	extra_param_ptr;
+	int	command_line;
+} IMAGE_PARAMS;
+
+#define IMAGE_PARAMS_PHYS	0xC01F0000
+
+static void __init
+fortunet_fixup(struct machine_desc *desc, struct param_struct *params,
+		 char **cmdline, struct meminfo *mi)
+{
+	IMAGE_PARAMS *ip;
+	ip = (IMAGE_PARAMS *)__phys_to_virt(IMAGE_PARAMS_PHYS);
+	*cmdline = (char *)__phys_to_virt(ip->command_line);
+#ifdef CONFIG_BLK_DEV_INITRD
+	if(ip->ramdisk_ok)
+	{
+		initrd_start = __phys_to_virt(ip->ramdisk_address);
+		initrd_end = initrd_start + ip->ramdisk_size;
+	}
+#endif
+	memmap.bank[0].size = ip->ram_size;
+	memmap.end = ip->ram_size+0xC0000000;
+	*mi = memmap;
+}
+
+MACHINE_START(FORTUNET, "ARM-FortuNet")
+	MAINTAINER("FortuNet Inc.")
+        BOOT_MEM(0xc0000000, 0x80000000, 0xf0000000)
+	BOOT_PARAMS(0x00000000)
+	FIXUP(fortunet_fixup)
+	MAPIO(clps711x_map_io)
+	INITIRQ(clps711x_init_irq)
+MACHINE_END
diff -urN linux-2.5.6-pre1/arch/arm/mach-clps711x/irq.c linux-2.5.6-pre2/arch/arm/mach-clps711x/irq.c
--- linux-2.5.6-pre1/arch/arm/mach-clps711x/irq.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/arch/arm/mach-clps711x/irq.c	Thu Feb 28 13:34:18 2002
@@ -26,7 +26,7 @@
 
 #include <asm/hardware/clps7111.h>
 
-static void mask_irq_int1(unsigned int irq)
+static void int1_mask(unsigned int irq)
 {
 	u32 intmr1;
 
@@ -35,7 +35,7 @@
 	clps_writel(intmr1, INTMR1);
 }
 
-static void mask_ack_irq_int1(unsigned int irq)
+static void int1_ack(unsigned int irq)
 {
 	u32 intmr1;
 
@@ -53,7 +53,7 @@
 	}
 }
 
-static void unmask_irq_int1(unsigned int irq)
+static void int1_unmask(unsigned int irq)
 {
 	u32 intmr1;
 
@@ -62,7 +62,13 @@
 	clps_writel(intmr1, INTMR1);
 }
 
-static void mask_irq_int2(unsigned int irq)
+static struct irqchip int1_chip = {
+	ack:	int1_ack,
+	mask:	int1_mask,
+	unmask:	int1_unmask,
+};
+
+static void int2_mask(unsigned int irq)
 {
 	u32 intmr2;
 
@@ -71,7 +77,7 @@
 	clps_writel(intmr2, INTMR2);
 }
 
-static void mask_ack_irq_int2(unsigned int irq)
+static void int2_ack(unsigned int irq)
 {
 	u32 intmr2;
 
@@ -84,7 +90,7 @@
 	}
 }
 
-static void unmask_irq_int2(unsigned int irq)
+static void int2_unmask(unsigned int irq)
 {
 	u32 intmr2;
 
@@ -93,28 +99,26 @@
 	clps_writel(intmr2, INTMR2);
 }
 
+static struct irqchip int2_chip = {
+	ack:	int2_ack,
+	mask:	int2_mask,
+	unmask:	int2_unmask,
+};
+
 void __init clps711x_init_irq(void)
 {
 	unsigned int i;
 
 	for (i = 0; i < NR_IRQS; i++) {
 	        if (INT1_IRQS & (1 << i)) {
-		        irq_desc[i].valid	= 1;
-			irq_desc[i].probe_ok	= 1;
-			irq_desc[i].mask_ack	= (INT1_ACK_IRQS & (1 << i)) ?
-						   mask_ack_irq_int1 :
-						   mask_irq_int1;
-			irq_desc[i].mask	= mask_irq_int1;
-			irq_desc[i].unmask	= unmask_irq_int1;
+	        	set_irq_handler(i, do_level_IRQ);
+	        	set_irq_chip(i, &int1_chip);
+	        	set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
 		}
 		if (INT2_IRQS & (1 << i)) {
-		        irq_desc[i].valid	= 1;
-			irq_desc[i].probe_ok	= 1;
-			irq_desc[i].mask_ack	= (INT2_ACK_IRQS & (1 << i)) ?
-						   mask_ack_irq_int2 :
-						   mask_irq_int2;
-			irq_desc[i].mask	= mask_irq_int2;
-			irq_desc[i].unmask	= unmask_irq_int2;
+			set_irq_handler(i, do_level_IRQ);
+			set_irq_chip(i, &int2_chip);
+			set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
 		}			
 	}
 
diff -urN linux-2.5.6-pre1/arch/arm/mach-ebsa110/core.c linux-2.5.6-pre2/arch/arm/mach-ebsa110/core.c
--- linux-2.5.6-pre1/arch/arm/mach-ebsa110/core.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/arch/arm/mach-ebsa110/core.c	Thu Feb 28 13:34:18 2002
@@ -39,27 +39,31 @@
 {
 	__raw_writeb(1 << irq, IRQ_MSET);
 }
+
+static struct irqchip ebsa110_irq_chip = {
+	ack:	ebsa110_mask_irq,
+	mask:	ebsa110_mask_irq,
+	unmask:	ebsa110_unmask_irq,
+};
  
 static void __init ebsa110_init_irq(void)
 {
 	unsigned long flags;
-	int irq;
+	unsigned int irq;
 
-	save_flags_cli (flags);
+	local_irq_save(flags);
 	__raw_writeb(0xff, IRQ_MCLR);
 	__raw_writeb(0x55, IRQ_MSET);
 	__raw_writeb(0x00, IRQ_MSET);
 	if (__raw_readb(IRQ_MASK) != 0x55)
 		while (1);
 	__raw_writeb(0xff, IRQ_MCLR);	/* clear all interrupt enables */
-	restore_flags (flags);
+	local_irq_restore(flags);
 
 	for (irq = 0; irq < NR_IRQS; irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 1;
-		irq_desc[irq].mask_ack	= ebsa110_mask_irq;
-		irq_desc[irq].mask	= ebsa110_mask_irq;
-		irq_desc[irq].unmask	= ebsa110_unmask_irq;
+		set_irq_chip(irq, &ebsa110_irq_chip);
+		set_irq_handler(irq, do_level_IRQ);
+		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
 }
 
diff -urN linux-2.5.6-pre1/arch/arm/mach-epxa10db/irq.c linux-2.5.6-pre2/arch/arm/mach-epxa10db/irq.c
--- linux-2.5.6-pre1/arch/arm/mach-epxa10db/irq.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/arch/arm/mach-epxa10db/irq.c	Thu Feb 28 13:34:18 2002
@@ -18,28 +18,44 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/init.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
 #include <asm/hardware.h>
 #include <asm/irq.h>
-#include <asm/io.h>
 #include <asm/mach/irq.h>
 #include <asm/arch/platform.h>
 #include <asm/arch/int_ctrl00.h>
 
 
-static void mask_irq(unsigned int irq)
+static void epxa_mask_irq(unsigned int irq)
 {
-        __raw_writel(1 << irq, INT_MC(IO_ADDRESS(EXC_INT_CTRL00_BASE)));
+        writel(1 << irq, INT_MC(IO_ADDRESS(EXC_INT_CTRL00_BASE)));
 }
 
-static void unmask_irq(unsigned int irq)
+static void epxa_unmask_irq(unsigned int irq)
 {
-        __raw_writel(1 << irq, INT_MS(IO_ADDRESS(EXC_INT_CTRL00_BASE)));
+        writel(1 << irq, INT_MS(IO_ADDRESS(EXC_INT_CTRL00_BASE)));
 }
  
+
+static struct irqchip epxa_irq_chip = {
+	ack:		epxa_mask_irq,
+	mask:		epxa_mask_irq,
+	unmask:		epxa_unmask_irq,
+};
+
+static struct resource irq_resource = {
+	name:	"irq_handler",
+	start:	IO_ADDRESS(EXC_INT_CTRL00_BASE),
+	end:	IO_ADDRESS(INT_PRIORITY_FC(EXC_INT_CTRL00_BASE))+4,
+};
+
 void __init epxa10db_init_irq(void)
 {
 	unsigned int i;
 	
+	request_resource(&iomem_resource, &irq_resource);
+
 	/*
 	 * This bit sets up the interrupt controller using 
 	 * the 6 PLD interrupts mode (the default) each 
@@ -49,22 +65,15 @@
 	 * on the contents of your PLD
 	 */
 
-	__raw_writel(3,INT_MODE(IO_ADDRESS(EXC_INT_CTRL00_BASE)));
+	writel(3,INT_MODE(IO_ADDRESS(EXC_INT_CTRL00_BASE)));
 	for (i = 0; i < NR_IRQS; i++){
-		__raw_writel(i+1, INT_PRIORITY_P0(IO_ADDRESS(EXC_INT_CTRL00_BASE)) + (4*i));
-	}
-
-
-	for (i = 0; i < NR_IRQS; i++) {
-	       
-		irq_desc[i].valid	= 1;
-		irq_desc[i].probe_ok	= 1;
-		irq_desc[i].mask_ack	= mask_irq;
-		irq_desc[i].mask	= mask_irq;
-		irq_desc[i].unmask	= unmask_irq;
+		writel(i+1, INT_PRIORITY_P0(IO_ADDRESS(EXC_INT_CTRL00_BASE)) + (4*i));
+		set_irq_chip(i,&epxa_irq_chip);
+		set_irq_handler(i,do_level_IRQ);
+		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
 	}
 
-	/* Disable all interrupt */
-	__raw_writel(-1,INT_MC(IO_ADDRESS(EXC_INT_CTRL00_BASE)));
+	/* Disable all interrupts */
+	writel(-1,INT_MC(IO_ADDRESS(EXC_INT_CTRL00_BASE)));
 
 }
diff -urN linux-2.5.6-pre1/arch/arm/mach-footbridge/Makefile linux-2.5.6-pre2/arch/arm/mach-footbridge/Makefile
--- linux-2.5.6-pre1/arch/arm/mach-footbridge/Makefile	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/arch/arm/mach-footbridge/Makefile	Thu Feb 28 13:34:18 2002
@@ -11,7 +11,7 @@
 
 # Object file lists.
 
-obj-y			:= arch.o dc21285.o dma.o irq.o mm.o
+obj-y			:= arch.o dc21285.o dma.o irq.o isa-irq.o mm.o
 obj-m			:=
 obj-n			:=
 obj-			:=
diff -urN linux-2.5.6-pre1/arch/arm/mach-footbridge/irq.c linux-2.5.6-pre2/arch/arm/mach-footbridge/irq.c
--- linux-2.5.6-pre1/arch/arm/mach-footbridge/irq.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/arch/arm/mach-footbridge/irq.c	Thu Feb 28 13:34:18 2002
@@ -27,6 +27,8 @@
 #include <asm/io.h>
 #include <asm/mach-types.h>
 
+extern void __init isa_init_irq(unsigned int irq);
+
 /*
  * Footbridge IRQ translation table
  *  Converts from our IRQ numbers into FootBridge masks
@@ -64,9 +66,15 @@
 	*CSR_IRQ_ENABLE = fb_irq_mask[_DC21285_INR(irq)];
 }
 
+static struct irqchip fb_chip = {
+	ack:	fb_mask_irq,
+	mask:	fb_mask_irq,
+	unmask:	fb_unmask_irq,
+};
+
 static void __init __fb_init_irq(void)
 {
-	int irq;
+	unsigned int irq;
 
 	/*
 	 * setup DC21285 IRQs
@@ -75,128 +83,9 @@
 	*CSR_FIQ_DISABLE = -1;
 
 	for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(20); irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 1;
-		irq_desc[irq].mask_ack	= fb_mask_irq;
-		irq_desc[irq].mask	= fb_mask_irq;
-		irq_desc[irq].unmask	= fb_unmask_irq;
-	}
-}
-
-extern int isa_irq;
-
-static void isa_mask_pic_lo_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
-}
-
-static void isa_mask_ack_pic_lo_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
-	outb(0x20, PIC_LO);
-}
-
-static void isa_unmask_pic_lo_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO);
-}
-
-static void isa_mask_pic_hi_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
-}
-
-static void isa_mask_ack_pic_hi_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
-	outb(0x62, PIC_LO);
-	outb(0x20, PIC_HI);
-}
-
-static void isa_unmask_pic_hi_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI);
-}
-
-static void no_action(int irq, void *dev_id, struct pt_regs *regs)
-{
-}
-
-static struct irqaction irq_cascade = { handler: no_action, name: "cascade", };
-static struct resource pic1_resource = { "pic1", 0x20, 0x3f };
-static struct resource pic2_resource = { "pic2", 0xa0, 0xbf };
-
-static void __init isa_init_irq(int irq)
-{
-	/*
-	 * Setup, and then probe for an ISA PIC
-	 * If the PIC is not there, then we
-	 * ignore the PIC.
-	 */
-	outb(0x11, PIC_LO);
-	outb(_ISA_IRQ(0), PIC_MASK_LO);	/* IRQ number		*/
-	outb(0x04, PIC_MASK_LO);	/* Slave on Ch2		*/
-	outb(0x01, PIC_MASK_LO);	/* x86			*/
-	outb(0xf5, PIC_MASK_LO);	/* pattern: 11110101	*/
-
-	outb(0x11, PIC_HI);
-	outb(_ISA_IRQ(8), PIC_MASK_HI);	/* IRQ number		*/
-	outb(0x02, PIC_MASK_HI);	/* Slave on Ch1		*/
-	outb(0x01, PIC_MASK_HI);	/* x86			*/
-	outb(0xfa, PIC_MASK_HI);	/* pattern: 11111010	*/
-
-	outb(0x0b, PIC_LO);
-	outb(0x0b, PIC_HI);
-
-	if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) {
-		outb(0xff, PIC_MASK_LO);/* mask all IRQs	*/
-		outb(0xff, PIC_MASK_HI);/* mask all IRQs	*/
-		isa_irq = irq;
-	} else
-		isa_irq = -1;
-
-	if (isa_irq != -1) {
-		for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) {
-			irq_desc[irq].valid	= 1;
-			irq_desc[irq].probe_ok	= 1;
-			irq_desc[irq].mask_ack	= isa_mask_ack_pic_lo_irq;
-			irq_desc[irq].mask	= isa_mask_pic_lo_irq;
-			irq_desc[irq].unmask	= isa_unmask_pic_lo_irq;
-		}
-
-		for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) {
-			irq_desc[irq].valid	= 1;
-			irq_desc[irq].probe_ok	= 1;
-			irq_desc[irq].mask_ack	= isa_mask_ack_pic_hi_irq;
-			irq_desc[irq].mask	= isa_mask_pic_hi_irq;
-			irq_desc[irq].unmask	= isa_unmask_pic_hi_irq;
-		}
-
-		request_resource(&ioport_resource, &pic1_resource);
-		request_resource(&ioport_resource, &pic2_resource);
-		setup_arm_irq(IRQ_ISA_CASCADE, &irq_cascade);
-		setup_arm_irq(isa_irq, &irq_cascade);
-
-		/*
-		 * On the NetWinder, don't automatically
-		 * enable ISA IRQ11 when it is requested.
-		 * There appears to be a missing pull-up
-		 * resistor on this line.
-		 */
-		if (machine_is_netwinder())
-			irq_desc[_ISA_IRQ(11)].noautoenable = 1;
+		set_irq_chip(irq, &fb_chip);
+		set_irq_handler(irq, do_level_IRQ);
+		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
 }
 
diff -urN linux-2.5.6-pre1/arch/arm/mach-footbridge/isa-irq.c linux-2.5.6-pre2/arch/arm/mach-footbridge/isa-irq.c
--- linux-2.5.6-pre1/arch/arm/mach-footbridge/isa-irq.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mach-footbridge/isa-irq.c	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,170 @@
+/*
+ *  linux/arch/arm/mach-footbridge/irq.c
+ *
+ *  Copyright (C) 1996-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Changelog:
+ *   22-Aug-1998 RMK	Restructured IRQ routines
+ *   03-Sep-1998 PJB	Merged CATS support
+ *   20-Jan-1998 RMK	Started merge of EBSA286, CATS and NetWinder
+ *   26-Jan-1999 PJB	Don't use IACK on CATS
+ *   16-Mar-1999 RMK	Added autodetect of ISA PICs
+ */
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/dec21285.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+static void isa_mask_pic_lo_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
+}
+
+static void isa_ack_pic_lo_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
+	outb(0x20, PIC_LO);
+}
+
+static void isa_unmask_pic_lo_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO);
+}
+
+static struct irqchip isa_lo_chip = {
+	ack:	isa_ack_pic_lo_irq,
+	mask:	isa_mask_pic_lo_irq,
+	unmask:	isa_unmask_pic_lo_irq,
+};
+
+static void isa_mask_pic_hi_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
+}
+
+static void isa_ack_pic_hi_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
+	outb(0x62, PIC_LO);
+	outb(0x20, PIC_HI);
+}
+
+static void isa_unmask_pic_hi_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI);
+}
+
+static struct irqchip isa_hi_chip = {
+	ack:	isa_ack_pic_hi_irq,
+	mask:	isa_mask_pic_hi_irq,
+	unmask:	isa_unmask_pic_hi_irq,
+};
+
+static void no_action(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static void
+isa_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+	unsigned int isa_irq = *(unsigned char *)PCIIACK_BASE;
+
+	if (isa_irq < _ISA_IRQ(0) || isa_irq >= _ISA_IRQ(16)) {
+		do_bad_IRQ(isa_irq, desc, regs);
+		return;
+	}
+
+	desc = irq_desc + isa_irq;
+	desc->handle(isa_irq, desc, regs);
+}
+
+static struct irqaction irq_cascade = { handler: no_action, name: "cascade", };
+static struct resource pic1_resource = { "pic1", 0x20, 0x3f };
+static struct resource pic2_resource = { "pic2", 0xa0, 0xbf };
+
+void __init isa_init_irq(unsigned int irq)
+{
+	/*
+	 * Setup, and then probe for an ISA PIC
+	 * If the PIC is not there, then we
+	 * ignore the PIC.
+	 */
+	outb(0x11, PIC_LO);
+	outb(_ISA_IRQ(0), PIC_MASK_LO);	/* IRQ number		*/
+	outb(0x04, PIC_MASK_LO);	/* Slave on Ch2		*/
+	outb(0x01, PIC_MASK_LO);	/* x86			*/
+	outb(0xf5, PIC_MASK_LO);	/* pattern: 11110101	*/
+
+	outb(0x11, PIC_HI);
+	outb(_ISA_IRQ(8), PIC_MASK_HI);	/* IRQ number		*/
+	outb(0x02, PIC_MASK_HI);	/* Slave on Ch1		*/
+	outb(0x01, PIC_MASK_HI);	/* x86			*/
+	outb(0xfa, PIC_MASK_HI);	/* pattern: 11111010	*/
+
+	outb(0x0b, PIC_LO);
+	outb(0x0b, PIC_HI);
+
+	if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) {
+		outb(0xff, PIC_MASK_LO);/* mask all IRQs	*/
+		outb(0xff, PIC_MASK_HI);/* mask all IRQs	*/
+	} else {
+		printk(KERN_INFO "IRQ: ISA PIC not found\n");
+		irq = -1;
+	}
+
+	if (irq != -1) {
+		for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) {
+			set_irq_chip(irq, &isa_lo_chip);
+			set_irq_handler(irq, do_level_IRQ);
+			set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+		}
+
+		for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) {
+			set_irq_chip(irq, &isa_hi_chip);
+			set_irq_handler(irq, do_level_IRQ);
+			set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+		}
+
+		request_resource(&ioport_resource, &pic1_resource);
+		request_resource(&ioport_resource, &pic2_resource);
+		setup_irq(IRQ_ISA_CASCADE, &irq_cascade);
+
+		set_irq_chained_handler(irq, isa_irq_handler);
+
+		/*
+		 * On the NetWinder, don't automatically
+		 * enable ISA IRQ11 when it is requested.
+		 * There appears to be a missing pull-up
+		 * resistor on this line.
+		 */
+		if (machine_is_netwinder())
+			set_irq_flags(_ISA_IRQ(11), IRQF_VALID |
+				      IRQF_PROBE | IRQF_NOAUTOEN);
+	}
+}
+
+
diff -urN linux-2.5.6-pre1/arch/arm/mach-footbridge/netwinder-hw.c linux-2.5.6-pre2/arch/arm/mach-footbridge/netwinder-hw.c
--- linux-2.5.6-pre1/arch/arm/mach-footbridge/netwinder-hw.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/arch/arm/mach-footbridge/netwinder-hw.c	Thu Feb 28 13:34:18 2002
@@ -320,7 +320,7 @@
 	 */
 	spin_lock_irqsave(&gpio_lock, flags);
 	gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN);
-	spin_unlock_irqrestore(&gpio_loc, flags);
+	spin_unlock_irqrestore(&gpio_lock, flags);
 }
 
 /*
diff -urN linux-2.5.6-pre1/arch/arm/mach-integrator/irq.c linux-2.5.6-pre2/arch/arm/mach-integrator/irq.c
--- linux-2.5.6-pre1/arch/arm/mach-integrator/irq.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre2/arch/arm/mach-integrator/irq.c	Thu Feb 28 13:34:18 2002
@@ -46,21 +46,17 @@
 {
         __raw_writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET);
 }
+
+static struct irqchip sc_chip = {
+	ack:	sc_mask_irq,
+	mask:	sc_mask_irq,
+	unmask:	sc_unmask_irq,
+};
  
 void __init integrator_init_irq(void)
 {
 	unsigned int i;
 
-	for (i = 0; i < NR_IRQS; i++) {
-	        if (((1 << i) && INTEGRATOR_SC_VALID_INT) != 0) {
-		        irq_desc[i].valid	= 1;
-			irq_desc[i].probe_ok	= 1;
-			irq_desc[i].mask_ack	= sc_mask_irq;
-			irq_desc[i].mask	= sc_mask_irq;
-			irq_desc[i].unmask	= sc_unmask_irq;
-		}
-	}
-
 	/* Disable all interrupts initially. */
 	/* Do the core module ones */
 	__raw_writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);
@@ -68,4 +64,12 @@
 	/* do the header card stuff next */
 	__raw_writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);
 	__raw_writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
+
+	for (i = 0; i < NR_IRQS; i++) {
+	        if (((1 << i) && INTEGRATOR_SC_VALID_INT) != 0) {
+	        	set_irq_chip(i, &sc_chip);
+	        	set_irq_handler(i, do_level_IRQ);
+	        	set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+		}
+	}
 }
diff -urN linux-2.5.6-pre1/arch/arm/mach-integrator/pci.c linux-2.5.6-pre2/arch/arm/mach-integrator/pci.c
--- linux-2.5.6-pre1/arch/arm/mach-integrator/pci.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/arch/arm/mach-integrator/pci.c	Thu Feb 28 13:34:18 2002
@@ -110,7 +110,6 @@
 	return irq_tab[intnr];
 }
 
-extern void pci_v3_setup_resources(struct resource **res);
 extern void pci_v3_init(void *);
 
 struct hw_pci integrator_pci __initdata = {
@@ -118,6 +117,7 @@
 	swizzle:		integrator_swizzle,
 	map_irq:		integrator_map_irq,
 	setup:			pci_v3_setup,
+	nr_controllers:		1,
 	scan:			pci_v3_scan_bus,
 	preinit:		pci_v3_preinit,
 	postinit:		pci_v3_postinit,
diff -urN linux-2.5.6-pre1/arch/arm/mach-integrator/pci_v3.c linux-2.5.6-pre2/arch/arm/mach-integrator/pci_v3.c
--- linux-2.5.6-pre1/arch/arm/mach-integrator/pci_v3.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/mach-integrator/pci_v3.c	Thu Feb 28 13:34:18 2002
@@ -38,8 +38,6 @@
 
 #include <asm/hardware/pci_v3.h>
 
-int setup_arm_irq(int irq, struct irqaction * new);
-
 /*
  * The V3 PCI interface chip in Integrator provides several windows from
  * local bus memory into the PCI memory areas.   Unfortunately, there
@@ -414,12 +412,19 @@
 	flags:	IORESOURCE_MEM | IORESOURCE_PREFETCH,
 };
 
-static void __init pci_v3_setup_resources(struct resource **resource)
+static int __init pci_v3_setup_resources(struct resource **resource)
 {
-	if (request_resource(&iomem_resource, &non_mem))
-		printk("PCI: unable to allocate non-prefetchable memory region\n");
-	if (request_resource(&iomem_resource, &pre_mem))
-		printk("PCI: unable to allocate prefetchable memory region\n");
+	if (request_resource(&iomem_resource, &non_mem)) {
+		printk(KERN_ERR "PCI: unable to allocate non-prefetchable "
+		       "memory region\n");
+		return -EBUSY;
+	}
+	if (request_resource(&iomem_resource, &pre_mem)) {
+		release_resource(&non_mem);
+		printk(KERN_ERR "PCI: unable to allocate prefetchable "
+		       "memory region\n");
+		return -EBUSY;
+	}
 
 	/*
 	 * bus->resource[0] is the IO resource for this bus
@@ -429,6 +434,8 @@
 	resource[0] = &ioport_resource;
 	resource[1] = &non_mem;
 	resource[2] = &pre_mem;
+
+	return 0;
 }
 
 /*
@@ -444,13 +451,15 @@
 {
 	unsigned long pc = instruction_pointer(regs);
 	unsigned long instr = *(unsigned long *)pc;
-//	char buf[128];
+#if 0
+	char buf[128];
 
-//	sprintf(buf, "V3 fault: address=0x%08lx, pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n",
-//		addr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255,
-//		v3_readb(V3_LB_ISTAT));
-//	printk("%s", buf);
-//	printascii(buf);
+	sprintf(buf, "V3 fault: address=0x%08lx, pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n",
+		addr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255,
+		v3_readb(V3_LB_ISTAT));
+	printk(KERN_DEBUG "%s", buf);
+	printascii(buf);
+#endif
 
 	v3_writeb(V3_LB_ISTAT, 0);
 	__raw_writel(3, SC_PCI);
@@ -514,28 +523,21 @@
 #endif
 }
 
-static struct irqaction v3_int = {
-	name: "V3",
-	handler: v3_irq,
-};
-
-static struct irqaction v3_int2 = {
-	name: "V3TM",
-	handler: v3_irq,
-};
-
 extern int (*external_fault)(unsigned long addr, struct pt_regs *regs);
 
-int pci_v3_setup(int nr, struct pci_sys_data *sys)
+int __init pci_v3_setup(int nr, struct pci_sys_data *sys)
 {
-	if (nr)
-		pci_v3_setup_resources(sys->resource);
-	return nr ? 0 : 1;
+	int ret = 0;
+
+	if (nr == 0)
+		ret = pci_v3_setup_resources(sys->resource);
+
+	return ret;
 }
 
 struct pci_bus *pci_v3_scan_bus(int nr, struct pci_sys_data *sys)
 {
-	return 	pci_scan_bus(sys->busnr, &pci_v3_ops, sys);
+	return pci_scan_bus(sys->busnr, &pci_v3_ops, sys);
 }
 
 /*
@@ -546,6 +548,7 @@
 {
 	unsigned long flags;
 	unsigned int temp;
+	int ret;
 
 	/*
 	 * Hook in our fault handler for PCI errors
@@ -593,7 +596,7 @@
 	temp |= V3_PCI_CFG_M_IO_REG_DIS | V3_PCI_CFG_M_IO_DIS;
 	v3_writew(V3_PCI_CFG, temp);
 
-	printk("FIFO_CFG: %04x  FIFO_PRIO: %04x\n",
+	printk(KERN_DEBUG "FIFO_CFG: %04x  FIFO_PRIO: %04x\n",
 		v3_readw(V3_FIFO_CFG), v3_readw(V3_FIFO_PRIORITY));
 
 	/*
@@ -620,7 +623,10 @@
 	/*
 	 * Grab the PCI error interrupt.
 	 */
-	setup_arm_irq(IRQ_V3INT, &v3_int);
+	ret = request_irq(IRQ_V3INT, v3_irq, 0, "V3", NULL);
+	if (ret)
+		printk(KERN_ERR "PCI: unable to grab PCI error "
+		       "interrupt: %d\n", ret);
 
 	spin_unlock_irqrestore(&v3_lock, flags);
 }
@@ -628,6 +634,7 @@
 void __init pci_v3_postinit(void)
 {
 	unsigned int pci_cmd;
+	int ret;
 
 	pci_cmd = PCI_COMMAND_MEMORY |
 		  PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
@@ -637,5 +644,10 @@
 	v3_writeb(V3_LB_ISTAT, ~0x40);
 	v3_writeb(V3_LB_IMASK, 0x68);
 
-//	setup_arm_irq(IRQ_LBUSTIMEOUT, &v3_int2);
+#if 0
+	ret = request_irq(IRQ_LBUSTIMEOUT, lb_timeout, 0, "bus timeout", NULL);
+	if (ret)
+		printk(KERN_ERR "PCI: unable to grab local bus timeout "
+		       "interrupt: %d\n", ret);
+#endif
 }
diff -urN linux-2.5.6-pre1/arch/arm/mach-iop310/iop310-irq.c linux-2.5.6-pre2/arch/arm/mach-iop310/iop310-irq.c
--- linux-2.5.6-pre1/arch/arm/mach-iop310/iop310-irq.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/mach-iop310/iop310-irq.c	Thu Feb 28 13:34:18 2002
@@ -29,40 +29,46 @@
 
 extern void do_IRQ(int, struct pt_regs *);
 
-u32 iop310_mask = 0;
+static u32 iop310_mask /* = 0 */;
 
-static void
-iop310_irq_mask (unsigned int irq)
+static void iop310_irq_mask (unsigned int irq)
 {
-	iop310_mask |= (1 << (irq - IOP310_IRQ_OFS));
+	iop310_mask ++;
 
 	/*
 	 * No mask bits on the 80312, so we have to
 	 * mask everything from the outside!
 	 */
-	xs80200_irq_mask(IRQ_XS80200_EXTIRQ);
+	if (iop310_mask == 1) {
+		disable_irq(IRQ_XS80200_EXTIRQ);
+		irq_desc[IRQ_XS80200_EXTIRQ].chip->mask(IRQ_XS80200_EXTIRQ);
+	}
 }
 
-static void
-iop310_irq_unmask (unsigned int irq)
+static void iop310_irq_unmask (unsigned int irq)
 {
-	iop310_mask &= ~(1 << (irq - IOP310_IRQ_OFS));
+	if (iop310_mask)
+		iop310_mask --;
 
 	/*
 	 * Check if all 80312 sources are unmasked now
 	 */
-	if(!iop310_mask)
-	{
-		xs80200_irq_unmask(IRQ_XS80200_EXTIRQ);
-
-	}
+	if (iop310_mask == 0)
+		enable_irq(IRQ_XS80200_EXTIRQ);
 }
 
-void iop310_irq_demux(int irq, void *dev_id,
-                                   struct pt_regs *regs)
+struct irqchip ext_chip = {
+	ack:	iop310_irq_mask,
+	mask:	iop310_irq_mask,
+	unmask:	iop310_irq_unmask,
+};
+
+void
+iop310_irq_demux(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
 {
 	u32 fiq1isr = *((volatile u32*)IOP310_FIQ1ISR);
 	u32 fiq2isr = *((volatile u32*)IOP310_FIQ2ISR);
+	struct irqdesc *d;
 	unsigned int irqno = 0;
 
 	if(fiq1isr)
@@ -86,22 +92,22 @@
 			irqno = IRQ_IOP310_MU;
 	}
 
-	do_IRQ(irqno, regs);
+	if (irqno) {
+		d = irq_desc + irqno;
+		d->handle(irqno, d, regs);
+	}
 }
 
 void __init iop310_init_irq(void)
 {
-	int i;
+	unsigned int i;
 
 	for(i = IOP310_IRQ_OFS; i < NR_IOP310_IRQS; i++)
 	{
-		irq_desc[i].valid	= 1;
-		irq_desc[i].probe_ok	= 1;
-		irq_desc[i].mask_ack	= iop310_irq_mask;
-		irq_desc[i].mask	= iop310_irq_mask;
-		irq_desc[i].unmask	= iop310_irq_unmask;
+		set_irq_chip(i, &ext_chip);
+		set_irq_handler(i, do_level_IRQ);
+		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
 	}
 
 	xs80200_init_irq();
 }
-
diff -urN linux-2.5.6-pre1/arch/arm/mach-iop310/iop310-pci.c linux-2.5.6-pre2/arch/arm/mach-iop310/iop310-pci.c
--- linux-2.5.6-pre1/arch/arm/mach-iop310/iop310-pci.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/arch/arm/mach-iop310/iop310-pci.c	Thu Feb 28 13:34:18 2002
@@ -52,7 +52,7 @@
 #ifdef DEBUG
 #define  DBG(x...) printk(x)
 #else
-#define  DBG(x...)
+#define  DBG(x...) do { } while (0)
 #endif
 
 extern int (*external_fault)(unsigned long, struct pt_regs *);
@@ -247,7 +247,8 @@
 		*IOP310_SATUISR = uisr & 0x0000069f;
 		ret = 1;
 	}
-//if (ret) printk("ERROR (%08lx %08lx)", usr, uisr);
+	if (ret)
+		DBG("ERROR (%08lx %08lx)", usr, uisr);
 	return ret;
 }
 
@@ -256,16 +257,19 @@
 {
 	int ret;
 	u8 val;
-//printk("rdb: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where);
+
+	DBG("rdb: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn),
+	    PCI_FUNC(dev->devfn), where);
 	*IOP310_SOCCAR = iop310_cfg_address(dev, where);
 
 	val = (*IOP310_SOCCDR) >> ((where & 3) * 8);
 	__asm__ __volatile__("nop; nop; nop; nop");
-//printk(">= %08lx ", val);
+
+	DBG(">= %08lx ", val);
 	ret = iop310_sec_pci_status();
 	if (ret)
 		val = 0xff;
-//printk("\n");
+	DBG("\n");
 	*p = val;
 
 	return PCIBIOS_SUCCESSFUL;
@@ -276,16 +280,19 @@
 {
 	int ret;
 	u16 val;
-//printk("rdw: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where);
+
+	DBG("rdw: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn),
+	    PCI_FUNC(dev->devfn), where);
 	*IOP310_SOCCAR = iop310_cfg_address(dev, where);
 
 	val = (*IOP310_SOCCDR) >> ((where & 3) * 8);
 	__asm__ __volatile__("nop; nop; nop; nop");
-//printk(">= %08lx ", val);
+
+	DBG(">= %08lx ", val);
 	ret = iop310_sec_pci_status();
 	if (ret)
 		val = 0xffff;
-//printk("\n");
+	DBG("\n");
 	*p = val;
 
 	return PCIBIOS_SUCCESSFUL;
@@ -296,16 +303,19 @@
 {
 	int ret;
 	u32 val;
-//printk("rdl: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where);
+
+	DBG("rdl: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn),
+	    PCI_FUNC(dev->devfn), where);
 	*IOP310_SOCCAR = iop310_cfg_address(dev, where);
 
 	val = *IOP310_SOCCDR;
 	__asm__ __volatile__("nop; nop; nop; nop");
-//printk(">= %08lx ", val);
+
+	DBG(">= %08lx ", val);
 	ret = iop310_sec_pci_status();
 	if (ret)
 		val = 0xffffffff;
-//printk("\n");
+	DBG("\n");
 	*p = val;
 
 	return PCIBIOS_SUCCESSFUL;
@@ -316,12 +326,15 @@
 {
 	int ret;
 	u32 val;
-//printk("wrb: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where);
+
+	DBG("wrb: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn),
+	    PCI_FUNC(dev->devfn), where);
 	*IOP310_SOCCAR = iop310_cfg_address(dev, where);
 
 	val = *IOP310_SOCCDR;
 	__asm__ __volatile__("nop; nop; nop; nop");
-//printk("<= %08lx", v);
+
+	DBG("<= %08lx", v);
 	ret = iop310_sec_pci_status();
 	if (ret == 0) {
 		where = (where & 3) * 8;
@@ -329,7 +342,7 @@
 		val |= v << where;
 		*IOP310_SOCCDR = val;
 	}
-//printk("\n");
+	DBG("\n");
 	return PCIBIOS_SUCCESSFUL;
 }
 
@@ -338,12 +351,15 @@
 {
 	int ret;
 	u32 val;
-//printk("wrw: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where);
+
+	DBG("wrw: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn),
+	    PCI_FUNC(dev->devfn), where);
 	*IOP310_SOCCAR = iop310_cfg_address(dev, where);
 
 	val = *IOP310_SOCCDR;
 	__asm__ __volatile__("nop; nop; nop; nop");
-//printk("<= %08lx", v);
+
+	DBG("<= %08lx", v);
 	ret = iop310_sec_pci_status();
 	if (ret == 0) {
 		where = (where & 2) * 8;
@@ -351,18 +367,20 @@
 		val |= v << where;
 		*IOP310_SOCCDR = val;
 	}
-//printk("\n");
+	DBG("\n");
 	return PCIBIOS_SUCCESSFUL;
 }
 
 static int
 iop310_sec_wr_cfg_dword(struct pci_dev *dev, int where, u32 v)
 {
-//printk("wrl: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where);
+	DBG("wrl: %d:%02x.%x %02x ", dev->bus->number, PCI_SLOT(dev->devfn),
+	    PCI_FUNC(dev->devfn), where);
 	*IOP310_SOCCAR = iop310_cfg_address(dev, where);
 	*IOP310_SOCCDR = v;
 	__asm__ __volatile__("nop; nop; nop; nop");
-//printk("<= %08lx\n", v);
+
+	DBG("<= %08lx\n", v);
 	return PCIBIOS_SUCCESSFUL;
 }
 
@@ -381,8 +399,8 @@
  */
 int iop310_pci_abort_handler(unsigned long addr, struct pt_regs *regs)
 {
-//	printk("PCI abort: address = %08x PC = %08x LR = %08lx\n",
-//		addr, regs->ARM_pc, regs->ARM_lr);
+	DBG("PCI abort: address = %08x PC = %08x LR = %08lx\n",
+		addr, regs->ARM_pc, regs->ARM_lr);
 	return 0;
 }
 
@@ -443,11 +461,11 @@
 	case 1:
 		res[0].start = IOP310_PCISEC_LOWER_IO + 0x6e000000;
 		res[0].end   = IOP310_PCISEC_LOWER_IO + 0x6e00ffff;
-		res[0].name  = "PCI IO Primary";
+		res[0].name  = "PCI IO Secondary";
 
 		res[1].start = IOP310_PCISEC_LOWER_MEM;
 		res[1].end   = IOP310_PCISEC_LOWER_MEM + IOP310_PCI_WINDOW_SIZE;
-		res[1].name  = "PCI Memory Primary";
+		res[1].name  = "PCI Memory Secondary";
 		break;
 	}
 
@@ -465,18 +483,17 @@
 void iop310_init(void)
 {
 	DBG("PCI:  Intel 80312 PCI-to-PCI init code.\n");
-	DBG("  ATU secondary: IOP310_SOMWVR=0x%04x, IOP310_SOIOWVR=0x%04x\n",
-			*IOP310_SOMWVR,
-			*IOP310_SOIOWVR);
-	DBG("  ATU secondary: IOP310_ATUCR=0x%08x\n", *IOP310_ATUCR);
-	DBG("  ATU secondary: IOP310_SIABAR=0x%08x IOP310_SIALR=0x%08x IOP310_SIATVR=%08x\n", *IOP310_SIABAR, *IOP310_SIALR, *IOP310_SIATVR);
-
-	DBG("  ATU primary: IOP310_POMWVR=0x%04x, IOP310_POIOWVR=0x%04x\n",
-			*IOP310_POMWVR,
-			*IOP310_POIOWVR);
-	DBG("  ATU secondary: IOP310_PIABAR=0x%08x IOP310_PIALR=0x%08x IOP310_PIATVR=%08x\n", *IOP310_PIABAR, *IOP310_PIALR, *IOP310_PIATVR);
-
-	DBG("  P2P: IOP310_PCR=0x%04x IOP310_BCR=0x%04x IOP310_EBCR=0x%04x\n", *IOP310_PCR, *IOP310_BCR, *IOP310_EBCR);
+	DBG("  ATU secondary: ATUCR =0x%08x\n", *IOP310_ATUCR);
+	DBG("  ATU secondary: SOMWVR=0x%08x  SOIOWVR=0x%08x\n",
+		*IOP310_SOMWVR,	*IOP310_SOIOWVR);
+	DBG("  ATU secondary: SIABAR=0x%08x  SIALR  =0x%08x SIATVR=%08x\n",
+		*IOP310_SIABAR, *IOP310_SIALR, *IOP310_SIATVR);
+	DBG("  ATU primary:   POMWVR=0x%08x  POIOWVR=0x%08x\n",
+		*IOP310_POMWVR,	*IOP310_POIOWVR);
+	DBG("  ATU primary:   PIABAR=0x%08x  PIALR  =0x%08x PIATVR=%08x\n",
+		*IOP310_PIABAR, *IOP310_PIALR, *IOP310_PIATVR);
+	DBG("  P2P: PCR=0x%04x BCR=0x%04x EBCR=0x%04x\n",
+		*IOP310_PCR, *IOP310_BCR, *IOP310_EBCR);
 
 	/*
 	 * Windows have to be carefully opened via a nice set of calls
@@ -495,6 +512,5 @@
 	*IOP310_PCR &= 0xfff8;
 
 	external_fault = iop310_pci_abort_handler;
-
 }
 
diff -urN linux-2.5.6-pre1/arch/arm/mach-iop310/iq80310-irq.c linux-2.5.6-pre2/arch/arm/mach-iop310/iq80310-irq.c
--- linux-2.5.6-pre1/arch/arm/mach-iop310/iq80310-irq.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/mach-iop310/iq80310-irq.c	Thu Feb 28 13:34:18 2002
@@ -27,121 +27,86 @@
 
 #include <asm/mach-types.h>
 
-extern void xs80200_irq_mask(unsigned int);
-extern void xs80200_irq_unmask(unsigned int);
-extern void xs80200_init_irq(void);
+extern void iop310_init_irq(void);
+extern void iop310_irq_demux(unsigned int, struct irqdesc *, struct pt_regs *);
 
-extern void do_IRQ(int, struct pt_regs *);
+static void iq80310_irq_mask(unsigned int irq)
+{
+	*(volatile char *)IQ80310_INT_MASK |= (1 << (irq - IQ80310_IRQ_OFS));
+}
 
-extern u32 iop310_mask;
+static void iq80310_irq_unmask(unsigned int irq)
+{
+	*(volatile char *)IQ80310_INT_MASK &= ~(1 << (irq - IQ80310_IRQ_OFS));
+}
 
-extern void iop310_irq_demux(int, void *, struct pt_regs *);
+static struct irqchip iq80310_irq_chip = {
+	ack:	iq80310_irq_mask,
+	mask:	iq80310_irq_mask,
+	unmask:	iq80310_irq_unmask,
+};
 
-extern int iop310_init_irq(void);
+extern struct irqchip ext_chip;
 
 static void
-iq80310_irq_mask (unsigned int irq)
+iq80310_cpld_irq_handler(unsigned int irq, struct irqdesc *desc,
+			 struct pt_regs *regs)
 {
-	volatile char *mask = (volatile char *)IQ80310_INT_MASK;
-	*mask |= (1 << (irq - IQ80310_IRQ_OFS));
+	unsigned int irq_stat = *(volatile u8*)IQ80310_INT_STAT;
+	unsigned int irq_mask = *(volatile u8*)IQ80310_INT_MASK;
+	unsigned int i, handled = 0;
+	struct irqdesc *d;
+
+	desc->chip->ack(irq);
 
 	/*
-	 * There's no mask for PCI INT A-C, so we just mask out all
-	 * external interrupts on the CPU.
-	 *
-	 * We set a bit of the iop310 mask so that the iop310_irq_mask
-	 * function does not unmask EXTINT
+	 * Mask out the interrupts which aren't enabled.
 	 */
-    	if (irq > IRQ_IQ80310_INTD)
-    	{
-		xs80200_irq_mask(IRQ_XS80200_EXTIRQ);
-		iop310_mask |=  (0x80000000 >> (irq - IRQ_IQ80310_INTD));
-    	}
-}
-
-static void
-iq80310_irq_unmask (unsigned int irq)
-{
-	volatile char *mask = (volatile char *)IQ80310_INT_MASK;
-	*mask &= ~(1 << (irq - IQ80310_IRQ_OFS));
+	irq_stat &= 0x1f & ~irq_mask;
 
 	/*
-	 * See comment above
+	 * Test each IQ80310 CPLD interrupt
 	 */
-    	if (irq > IRQ_IQ80310_INTD)
-    	{
-		xs80200_irq_unmask(IRQ_XS80200_EXTIRQ);
-		iop310_mask &= ~((0x80000000 >> (irq - IRQ_IQ80310_INTD)));
-    	}
-}
-
-static void iq80310_cpld_irq_demux(int irq, void *dev_id,
-                                   struct pt_regs *regs)
-{
-	u8 irq_stat = *((volatile u8*)IQ80310_INT_STAT);
-	u8 irq_mask = *((volatile u8*)IQ80310_INT_MASK);
-	unsigned int irqno = 0xffffffff;
-
-	// Needed? If IRQ is masked, it shouldn't get through...
-	irq_stat &= ~irq_mask;
-
-
-	if(irq_stat & 0x01)
-		irqno = IRQ_IQ80310_TIMER;
-	else if(irq_stat & 0x02)
-		irqno = IRQ_IQ80310_I82559;
-	else if(irq_stat & 0x04)
-		irqno = IRQ_IQ80310_UART1;
-	else if(irq_stat & 0x08)
-		irqno = IRQ_IQ80310_UART2;
-	else if(irq_stat & 0x10)
-		irqno = IRQ_IQ80310_INTD;
-	else if(system_rev)
-	{
-		irq_stat = *((volatile u8*)IQ80310_PCI_INT_STAT) & 0xf;
-
-		if(irq_stat & 0x1)
-			irqno = IRQ_IQ80310_INTA;
-		else if(irq_stat & 0x2)
-			irqno = IRQ_IQ80310_INTB;
-		else if(irq_stat & 0x4)
-			irqno = IRQ_IQ80310_INTC;
-	}
-	else	/* Running on a REV D.1 or older, assume PCI INTA */
-		irqno = IRQ_IQ80310_INTA;
+	for (i = IRQ_IQ80310_TIMER, d = irq_desc + IRQ_IQ80310_TIMER;
+	     irq_stat; i++, d++, irq_stat >>= 1)
+		if (irq_stat & 1) {
+			d->handle(i, d, regs);
+			handled++;
+		}
 
 	/*
-	 * If we didn't read a CPLD interrupt, we assume it's from
-	 * a device on the chipset itself.
+	 * If running on a board later than REV D.1, we can
+	 * decode the PCI interrupt status.
 	 */
-	if(irqno == 0xffffffff)
-	{
-		iop310_irq_demux(irq, dev_id, regs);
-		return;
+	if (system_rev) {
+		irq_stat = *((volatile u8*)IQ80310_PCI_INT_STAT) & 7;
+
+		for (i = IRQ_IQ80310_INTA, d = irq_desc + IRQ_IQ80310_INTA;
+		     irq_stat; i++, d++, irq_stat >>= 1)
+			if (irq_stat & 0x1) {
+				d->handle(i, d, regs);
+				handled++;
+			}
 	}
 
 	/*
-	 * If on a REV D.1 or lower board, we just assumed INTA since
-	 * PCI is not routed, and it may actually be an on-chip interrupt.
+	 * If on a REV D.1 or lower board, we just assumed INTA
+	 * since PCI is not routed, and it may actually be an
+	 * on-chip interrupt.
+	 *
+	 * Note that we're giving on-chip interrupts slightly
+	 * higher priority than PCI by handling them first.
 	 *
-	 * Note that we're giving on-chip interrupts slightly higher
-	 * priority than PCI by handling them first.
+	 * On boards later than REV D.1, if we didn't read a
+	 * CPLD interrupt, we assume it's from a device on the
+	 * chipset itself.
 	 */
-	if(irqno == IRQ_IQ80310_INTA && !system_rev)
-		iop310_irq_demux(irq, dev_id, regs);
+	if (system_rev == 0 || handled == 0)
+		iop310_irq_demux(irq, desc, regs);
 
-	do_IRQ(irqno, regs);
+	desc->chip->unmask(irq);
 }
 
-
-static struct irqaction iq80310_cpld_irq = {
-    name:       "CPLD_IRQ",
-    handler:    iq80310_cpld_irq_demux,
-    flags:      SA_INTERRUPT
-};
-
-extern int setup_arm_irq(int, struct irqaction *);
-
 void __init iq80310_init_irq(void)
 {
 	volatile char *mask = (volatile char *)IQ80310_INT_MASK;
@@ -154,17 +119,26 @@
 	 */
 	*IOP310_PIRSR = 0xff;
 
-	for (i = IQ80310_IRQ_OFS; i < NR_IRQS; i++) {
-		irq_desc[i].valid	= 1;
-		irq_desc[i].probe_ok	= 1;
-		irq_desc[i].mask_ack	= iq80310_irq_mask;
-		irq_desc[i].mask	= iq80310_irq_mask;
-		irq_desc[i].unmask	= iq80310_irq_unmask;
+	/*
+	 * Setup the IRQs in the FE820000/FE860000 registers
+	 */
+	for (i = IQ80310_IRQ_OFS; i <= IRQ_IQ80310_INTD; i++) {
+		set_irq_chip(i, &iq80310_irq_chip);
+		set_irq_handler(i, do_level_IRQ);
+		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+	}
+
+	/*
+	 * Setup the PCI IRQs
+	 */
+	for (i = IRQ_IQ80310_INTA; i < IRQ_IQ80310_INTC; i++) {
+		set_irq_chip(i, &ext_chip);
+		set_irq_handler(i, do_level_IRQ);
+		set_irq_flags(i, IRQF_VALID);
 	}
 
 	*mask = 0xff;  /* mask all sources */
-	setup_arm_irq(IRQ_XS80200_EXTIRQ, &iq80310_cpld_irq);
 
-	/* enable only external IRQ in the INTCTL for now */
-	asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (1<<1));
+	set_irq_chained_handler(IRQ_XS80200_EXTIRQ,
+				&iq80310_cpld_irq_handler);
 }
diff -urN linux-2.5.6-pre1/arch/arm/mach-iop310/iq80310-time.c linux-2.5.6-pre2/arch/arm/mach-iop310/iq80310-time.c
--- linux-2.5.6-pre1/arch/arm/mach-iop310/iq80310-time.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/arch/arm/mach-iop310/iq80310-time.c	Thu Feb 28 13:34:18 2002
@@ -11,25 +11,21 @@
  * published by the Free Software Foundation.
  *
  */
-
-
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/time.h>
 #include <linux/init.h>
+#include <linux/timex.h>
 #include <linux/smp.h>
 
-#include <asm/uaccess.h>
+#include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-
-#include <linux/timex.h>
-#include <asm/hardware.h>
-
+#include <asm/uaccess.h>
 #include <asm/mach-types.h>
+#include <asm/mach/irq.h>
 
 static void iq80310_write_timer (u_long val)
 {
@@ -109,14 +105,12 @@
 };
 
 
-extern int setup_arm_irq(int, struct irqaction*);
-
 void __init time_init(void)
 {
 	volatile u_char *timer_en = (volatile u_char *)IQ80310_TIMER_EN;
 
 	gettimeoffset = iq80310_gettimeoffset;
-	setup_arm_irq(IRQ_IQ80310_TIMER, &timer_irq);
+	setup_irq(IRQ_IQ80310_TIMER, &timer_irq);
 	*timer_en = 0;
 	iq80310_write_timer(LATCH);
 	*timer_en |= 2;
diff -urN linux-2.5.6-pre1/arch/arm/mach-iop310/xs80200-irq.c linux-2.5.6-pre2/arch/arm/mach-iop310/xs80200-irq.c
--- linux-2.5.6-pre1/arch/arm/mach-iop310/xs80200-irq.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/mach-iop310/xs80200-irq.c	Thu Feb 28 13:34:18 2002
@@ -20,45 +20,47 @@
 
 #include <asm/mach-types.h>
 
-void
-xs80200_irq_mask (unsigned int irq)
+static void xs80200_irq_mask (unsigned int irq)
 {
-	long INTCTL;
-	asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL));
+	unsigned long intctl;
+	asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (intctl));
 	switch (irq) {
-	    case IRQ_XS80200_BCU:     INTCTL &= ~(1<<3); break;
-	    case IRQ_XS80200_PMU:     INTCTL &= ~(1<<2); break;
-	    case IRQ_XS80200_EXTIRQ:  INTCTL &= ~(1<<1); break;
-	    case IRQ_XS80200_EXTFIQ:  INTCTL &= ~(1<<0); break;
+	    case IRQ_XS80200_BCU:     intctl &= ~(1<<3); break;
+	    case IRQ_XS80200_PMU:     intctl &= ~(1<<2); break;
+	    case IRQ_XS80200_EXTIRQ:  intctl &= ~(1<<1); break;
+	    case IRQ_XS80200_EXTFIQ:  intctl &= ~(1<<0); break;
 	}
-	asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL));
+	asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (intctl));
 }
 
-void
-xs80200_irq_unmask (unsigned int irq)
+static void xs80200_irq_unmask (unsigned int irq)
 {
-	long INTCTL;
-	asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (INTCTL));
+	unsigned long intctl;
+	asm ("mrc p13, 0, %0, c0, c0, 0" : "=r" (intctl));
 	switch (irq) {
-	    case IRQ_XS80200_BCU:	INTCTL |= (1<<3); break;
-	    case IRQ_XS80200_PMU:	INTCTL |= (1<<2); break;
-	    case IRQ_XS80200_EXTIRQ:	INTCTL |= (1<<1); break;
-	    case IRQ_XS80200_EXTFIQ:	INTCTL |= (1<<0); break;
+	    case IRQ_XS80200_BCU:	intctl |= (1<<3); break;
+	    case IRQ_XS80200_PMU:	intctl |= (1<<2); break;
+	    case IRQ_XS80200_EXTIRQ:	intctl |= (1<<1); break;
+	    case IRQ_XS80200_EXTFIQ:	intctl |= (1<<0); break;
 	}
-	asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (INTCTL));
+	asm ("mcr p13, 0, %0, c0, c0, 0" : : "r" (intctl));
 }
 
+static struct irqchip xs80200_chip = {
+	ack:	xs80200_irq_mask,
+	mask:	xs80200_irq_mask,
+	unmask:	xs80200_irq_unmask,
+};
+
 void __init xs80200_init_irq(void)
 {
-	int i;
+	unsigned int i;
+
+	asm("mcr p13, 0, %0, c0, c0, 0" : : "r" (0));
 
 	for (i = 0; i < NR_XS80200_IRQS; i++) {
-		irq_desc[i].valid	= 1;
-		irq_desc[i].probe_ok	= 0;
-		irq_desc[i].mask_ack	= xs80200_irq_mask;
-		irq_desc[i].mask	= xs80200_irq_mask;
-		irq_desc[i].unmask	= xs80200_irq_unmask;
+		set_irq_chip(i, &xs80200_chip);
+		set_irq_handler(i, do_level_IRQ);
+		set_irq_flags(i, IRQF_VALID);
 	}
 }
-
-
diff -urN linux-2.5.6-pre1/arch/arm/mach-rpc/dma.c linux-2.5.6-pre2/arch/arm/mach-rpc/dma.c
--- linux-2.5.6-pre1/arch/arm/mach-rpc/dma.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/arch/arm/mach-rpc/dma.c	Thu Feb 28 13:34:18 2002
@@ -188,7 +188,7 @@
 		 */
 		if (!dma->using_sg) {
 			dma->buf.dma_address = pci_map_single(NULL,
-				dma->buf.address, dma->buf.length,
+				dma->buf.__address, dma->buf.length,
 				dma->dma_mode == DMA_MODE_READ ?
 				PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
 		}
@@ -275,6 +275,9 @@
 	unsigned int fiqhandler_length;
 	struct pt_regs regs;
 
+	if (dma->using_sg)
+		BUG();
+
 	if (dma->dma_mode == DMA_MODE_READ) {
 		extern unsigned char floppy_fiqin_start, floppy_fiqin_end;
 		fiqhandler_start = &floppy_fiqin_start;
@@ -286,7 +289,7 @@
 	}
 
 	regs.ARM_r9  = dma->buf.length;
-	regs.ARM_r10 = (unsigned long)dma->buf.address;
+	regs.ARM_r10 = (unsigned long)dma->buf.__address;
 	regs.ARM_fp  = FLOPPYDMA_BASE;
 
 	if (claim_fiq(&fh)) {
diff -urN linux-2.5.6-pre1/arch/arm/mach-rpc/irq.c linux-2.5.6-pre2/arch/arm/mach-rpc/irq.c
--- linux-2.5.6-pre1/arch/arm/mach-rpc/irq.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/arch/arm/mach-rpc/irq.c	Thu Feb 28 13:34:18 2002
@@ -5,7 +5,7 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 
-static void rpc_mask_irq_ack_a(unsigned int irq)
+static void iomd_ack_irq_a(unsigned int irq)
 {
 	unsigned int val, mask;
 
@@ -15,7 +15,7 @@
 	iomd_writeb(mask, IOMD_IRQCLRA);
 }
 
-static void rpc_mask_irq_a(unsigned int irq)
+static void iomd_mask_irq_a(unsigned int irq)
 {
 	unsigned int val, mask;
 
@@ -24,7 +24,7 @@
 	iomd_writeb(val & ~mask, IOMD_IRQMASKA);
 }
 
-static void rpc_unmask_irq_a(unsigned int irq)
+static void iomd_unmask_irq_a(unsigned int irq)
 {
 	unsigned int val, mask;
 
@@ -33,7 +33,13 @@
 	iomd_writeb(val | mask, IOMD_IRQMASKA);
 }
 
-static void rpc_mask_irq_b(unsigned int irq)
+static struct irqchip iomd_a_chip = {
+	ack:	iomd_ack_irq_a,
+	mask:	iomd_mask_irq_a,
+	unmask:	iomd_unmask_irq_a,
+};
+
+static void iomd_mask_irq_b(unsigned int irq)
 {
 	unsigned int val, mask;
 
@@ -42,7 +48,7 @@
 	iomd_writeb(val & ~mask, IOMD_IRQMASKB);
 }
 
-static void rpc_unmask_irq_b(unsigned int irq)
+static void iomd_unmask_irq_b(unsigned int irq)
 {
 	unsigned int val, mask;
 
@@ -51,7 +57,13 @@
 	iomd_writeb(val | mask, IOMD_IRQMASKB);
 }
 
-static void rpc_mask_irq_dma(unsigned int irq)
+static struct irqchip iomd_b_chip = {
+	ack:	iomd_mask_irq_b,
+	mask:	iomd_mask_irq_b,
+	unmask:	iomd_unmask_irq_b,
+};
+
+static void iomd_mask_irq_dma(unsigned int irq)
 {
 	unsigned int val, mask;
 
@@ -60,7 +72,7 @@
 	iomd_writeb(val & ~mask, IOMD_DMAMASK);
 }
 
-static void rpc_unmask_irq_dma(unsigned int irq)
+static void iomd_unmask_irq_dma(unsigned int irq)
 {
 	unsigned int val, mask;
 
@@ -69,7 +81,13 @@
 	iomd_writeb(val | mask, IOMD_DMAMASK);
 }
 
-static void rpc_mask_irq_fiq(unsigned int irq)
+static struct irqchip iomd_dma_chip = {
+	ack:	iomd_mask_irq_dma,
+	mask:	iomd_mask_irq_dma,
+	unmask:	iomd_unmask_irq_dma,
+};
+
+static void iomd_mask_irq_fiq(unsigned int irq)
 {
 	unsigned int val, mask;
 
@@ -78,7 +96,7 @@
 	iomd_writeb(val & ~mask, IOMD_FIQMASK);
 }
 
-static void rpc_unmask_irq_fiq(unsigned int irq)
+static void iomd_unmask_irq_fiq(unsigned int irq)
 {
 	unsigned int val, mask;
 
@@ -87,9 +105,15 @@
 	iomd_writeb(val | mask, IOMD_FIQMASK);
 }
 
+static struct irqchip iomd_fiq_chip = {
+	ack:	iomd_mask_irq_fiq,
+	mask:	iomd_mask_irq_fiq,
+	unmask:	iomd_unmask_irq_fiq,
+};
+
 void __init rpc_init_irq(void)
 {
-	int irq;
+	unsigned int irq, flags;
 
 	iomd_writeb(0, IOMD_IRQMASKA);
 	iomd_writeb(0, IOMD_IRQMASKB);
@@ -97,46 +121,41 @@
 	iomd_writeb(0, IOMD_DMAMASK);
 
 	for (irq = 0; irq < NR_IRQS; irq++) {
+		flags = IRQF_VALID;
+
+		if (irq <= 6 || (irq >= 9 && irq <= 15))
+			flags |= IRQF_PROBE;
+
+		if (irq == 21 || (irq >= 16 && irq <= 19) ||
+		    irq == IRQ_KEYBOARDTX)
+			flags |= IRQF_NOAUTOEN;
+
 		switch (irq) {
-		case 0 ... 6:
-			irq_desc[irq].probe_ok = 1;
-		case 7:
-			irq_desc[irq].valid    = 1;
-			irq_desc[irq].mask_ack = rpc_mask_irq_ack_a;
-			irq_desc[irq].mask     = rpc_mask_irq_a;
-			irq_desc[irq].unmask   = rpc_unmask_irq_a;
+		case 0 ... 7:
+			set_irq_chip(irq, &iomd_a_chip);
+			set_irq_handler(irq, do_level_IRQ);
+			set_irq_flags(irq, flags);
 			break;
 
-		case 9 ... 15:
-			irq_desc[irq].probe_ok = 1;
-		case 8:
-			irq_desc[irq].valid    = 1;
-			irq_desc[irq].mask_ack = rpc_mask_irq_b;
-			irq_desc[irq].mask     = rpc_mask_irq_b;
-			irq_desc[irq].unmask   = rpc_unmask_irq_b;
+		case 8 ... 15:
+			set_irq_chip(irq, &iomd_b_chip);
+			set_irq_handler(irq, do_level_IRQ);
+			set_irq_flags(irq, flags);
 			break;
 
-		case 16 ... 19:
-		case 21:
-			irq_desc[irq].noautoenable = 1;
-		case 20:
-			irq_desc[irq].valid    = 1;
-			irq_desc[irq].mask_ack = rpc_mask_irq_dma;
-			irq_desc[irq].mask     = rpc_mask_irq_dma;
-			irq_desc[irq].unmask   = rpc_unmask_irq_dma;
+		case 16 ... 21:
+			set_irq_chip(irq, &iomd_dma_chip);
+			set_irq_handler(irq, do_level_IRQ);
+			set_irq_flags(irq, flags);
 			break;
 
 		case 64 ... 71:
-			irq_desc[irq].valid    = 1;
-			irq_desc[irq].mask_ack = rpc_mask_irq_fiq;
-			irq_desc[irq].mask     = rpc_mask_irq_fiq;
-			irq_desc[irq].unmask   = rpc_unmask_irq_fiq;
+			set_irq_chip(irq, &iomd_fiq_chip);
+			set_irq_flags(irq, IRQF_VALID);
 			break;
 		}
 	}
 
-	irq_desc[IRQ_KEYBOARDTX].noautoenable = 1;
-
 	init_FIQ();
 }
 
diff -urN linux-2.5.6-pre1/arch/arm/mach-sa1100/assabet.c linux-2.5.6-pre2/arch/arm/mach-sa1100/assabet.c
--- linux-2.5.6-pre1/arch/arm/mach-sa1100/assabet.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/arch/arm/mach-sa1100/assabet.c	Thu Feb 28 13:34:18 2002
@@ -20,6 +20,7 @@
 #include <linux/serial_core.h>
 
 #include <asm/hardware.h>
+#include <asm/irq.h>
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -89,7 +90,7 @@
 	/*
 	 * Set the IRQ edges
 	 */
-	set_GPIO_IRQ_edge(GPIO_GPIO23, GPIO_RISING_EDGE);	/* UCB1300 */
+	set_irq_type(IRQ_GPIO23, IRQT_RISING);	/* UCB1300 */
 
 	sa1100fb_lcd_power = assabet_lcd_power;
 	sa1100fb_backlight_power = assabet_backlight_power;
diff -urN linux-2.5.6-pre1/arch/arm/mach-sa1100/badge4.c linux-2.5.6-pre2/arch/arm/mach-sa1100/badge4.c
--- linux-2.5.6-pre1/arch/arm/mach-sa1100/badge4.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mach-sa1100/badge4.c	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,211 @@
+/*
+ * linux/arch/arm/mach-sa1100/badge4.c
+ *
+ * BadgePAD 4 specific initialization
+ *
+ *   Tim Connors <connors@hpl.hp.com>
+ *   Christopher Hoover <ch@hpl.hp.com>
+ *
+ * Copyright (C) 2002 Hewlett-Packard Company
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+
+#include <asm/hardware.h>
+#include <asm/setup.h>
+#include <asm/arch/irqs.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/sa1111.h>
+#include <asm/mach/serial_sa1100.h>
+
+#include "generic.h"
+#include "sa1111.h"
+
+static int __init badge4_sa1111_init(void)
+{
+	int ret;
+
+	/*
+	 * Ensure that the memory bus request/grant signals are setup,
+	 * and the grant is held in its inactive state
+	 */
+	sa1110_mb_disable();
+
+	/*
+	 * Probe for SA1111.
+	 */
+	ret = sa1111_probe(BADGE4_SA1111_BASE);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * We found it.  Wake the chip up.
+	 */
+	sa1111_wake();
+
+	/*
+	 * The SDRAM configuration of the SA1110 and the SA1111 must
+	 * match.  This is very important to ensure that SA1111 accesses
+	 * don't corrupt the SDRAM.  Note that this ungates the SA1111's
+	 * MBGNT signal, so we must have called sa1110_mb_disable()
+	 * beforehand.
+	 */
+	sa1111_configure_smc(1,
+			     FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
+			     FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
+
+	/*
+	 * We only need to turn on DCLK whenever we want to use the
+	 * DMA.  It can otherwise be held firmly in the off position.
+	 */
+	SKPCR |= SKPCR_DCLKEN;
+
+	/*
+	 * Enable the SA1110 memory bus request and grant signals.
+	 */
+	sa1110_mb_enable();
+
+	sa1111_init_irq(BADGE4_IRQ_GPIO_SA1111);
+
+	return 0;
+}
+
+static int __init badge4_init(void)
+{
+	int ret;
+
+	if (!machine_is_badge4())
+		return -ENODEV;
+
+	ret = badge4_sa1111_init();
+	if (ret < 0)
+		printk(KERN_ERR __FUNCTION__
+		       ": SA-1111 initialization failed (%d)\n", ret);
+
+	/* N.B, according to rmk this is the singular place that GPDR
+           should be set */
+
+	/* Video expansion */
+	GPCR  = (BADGE4_GPIO_INT_VID | BADGE4_GPIO_LGP2 | BADGE4_GPIO_LGP3 |
+		 BADGE4_GPIO_LGP4 | BADGE4_GPIO_LGP5 | BADGE4_GPIO_LGP6 |
+		 BADGE4_GPIO_LGP7 | BADGE4_GPIO_LGP8 | BADGE4_GPIO_LGP9 |
+		 BADGE4_GPIO_GPA_VID | BADGE4_GPIO_GPB_VID |
+		 BADGE4_GPIO_GPC_VID);
+	GPDR |= (BADGE4_GPIO_INT_VID | BADGE4_GPIO_LGP2 | BADGE4_GPIO_LGP3 |
+		 BADGE4_GPIO_LGP4 | BADGE4_GPIO_LGP5 | BADGE4_GPIO_LGP6 |
+		 BADGE4_GPIO_LGP7 | BADGE4_GPIO_LGP8 | BADGE4_GPIO_LGP9 |
+		 BADGE4_GPIO_GPA_VID | BADGE4_GPIO_GPB_VID |
+		 BADGE4_GPIO_GPC_VID);
+
+	/* SDRAM SPD i2c */
+	GPCR  = (BADGE4_GPIO_SDSDA | BADGE4_GPIO_SDSCL);
+	GPDR |= (BADGE4_GPIO_SDSDA | BADGE4_GPIO_SDSCL);
+
+	/* uart */
+	GPCR  = (BADGE4_GPIO_UART_HS1 | BADGE4_GPIO_UART_HS2);
+	GPDR |= (BADGE4_GPIO_UART_HS1 | BADGE4_GPIO_UART_HS2);
+
+	/* drives CPLD muxsel0 input */
+	GPCR  = BADGE4_GPIO_MUXSEL0;
+	GPDR |= BADGE4_GPIO_MUXSEL0;
+
+	/* test points */
+	GPCR  = (BADGE4_GPIO_TESTPT_J7 | BADGE4_GPIO_TESTPT_J6 |
+		 BADGE4_GPIO_TESTPT_J5);
+	GPDR |= (BADGE4_GPIO_TESTPT_J7 | BADGE4_GPIO_TESTPT_J6 |
+		 BADGE4_GPIO_TESTPT_J5);
+
+	/* drives CPLD sdram type inputs; this shouldn't be needed;
+           bootloader left it this way. */
+	GPDR |= (BADGE4_GPIO_SDTYP0 | BADGE4_GPIO_SDTYP1);
+
+ 	/* 5V supply rail. */
+ 	GPCR  = BADGE4_GPIO_PCMEN5V;		/* initially off */
+  	GPDR |= BADGE4_GPIO_PCMEN5V;
+
+	/* drives SA1111 reset pin; this shouldn't be needed;
+           bootloader left it this way. */
+	GPSR  = BADGE4_GPIO_SA1111_NRST;
+	GPDR |= BADGE4_GPIO_SA1111_NRST;
+
+	return 0;
+}
+
+__initcall(badge4_init);
+
+
+static unsigned badge4_5V_bitmap = 0;
+
+void badge4_set_5V(unsigned subsystem, int on)
+{
+	unsigned long flags;
+	unsigned old_5V_bitmap;
+
+	local_irq_save(flags);
+
+	old_5V_bitmap = badge4_5V_bitmap;
+
+	if (on) {
+		badge4_5V_bitmap |= subsystem;
+	} else {
+		badge4_5V_bitmap &= ~subsystem;
+	}
+
+	/* detect on->off and off->on transitions */
+	if ((!old_5V_bitmap) && (badge4_5V_bitmap)) {
+		/* was off, now on */
+		printk(KERN_INFO __FUNCTION__ ": enabling 5V supply rail\n");
+		GPSR = BADGE4_GPIO_PCMEN5V;
+	} else if ((old_5V_bitmap) && (!badge4_5V_bitmap)) {
+		/* was on, now off */
+		printk(KERN_INFO __FUNCTION__ ": disabling 5V supply rail\n");
+		GPCR = BADGE4_GPIO_PCMEN5V;
+	}
+
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(badge4_set_5V);
+
+
+static void __init
+fixup_badge4(struct machine_desc *desc, struct param_struct *params,
+	    char **cmdline, struct meminfo *mi)
+{
+	/* nothing needed here */
+}
+
+static struct map_desc badge4_io_desc[] __initdata = {
+  /*  virtual    physical    length      domain     r w c b		   */
+  {0xf1000000, 0x08000000, 0x00100000, DOMAIN_IO, 1,1,0,0},/* SRAM  bank 1 */
+  {0xf2000000, 0x10000000, 0x00100000, DOMAIN_IO, 1,1,0,0},/* SRAM  bank 2 */
+  {0xf4000000, 0x48000000, 0x00100000, DOMAIN_IO, 1,1,0,0},/* SA-1111      */
+  LAST_DESC
+};
+
+static void __init badge4_map_io(void)
+{
+	sa1100_map_io();
+	iotable_init(badge4_io_desc);
+
+	sa1100_register_uart(0, 3);
+	sa1100_register_uart(1, 1);
+}
+
+MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	BOOT_PARAMS(0xc0000100)
+	FIXUP(fixup_badge4)
+	MAPIO(badge4_map_io)
+	INITIRQ(sa1100_init_irq)
+MACHINE_END
diff -urN linux-2.5.6-pre1/arch/arm/mach-sa1100/cerf.c linux-2.5.6-pre2/arch/arm/mach-sa1100/cerf.c
--- linux-2.5.6-pre1/arch/arm/mach-sa1100/cerf.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/mach-sa1100/cerf.c	Thu Feb 28 13:34:18 2002
@@ -6,6 +6,7 @@
 #include <linux/kernel.h>
 #include <linux/tty.h>
 
+#include <asm/irq.h>
 #include <asm/hardware.h>
 #include <asm/setup.h>
 
@@ -26,12 +27,12 @@
 	 */
 #ifdef CONFIG_SA1100_CERF_CPLD
 	/* PDA Full serial port */
-	set_GPIO_IRQ_edge(GPIO_GPIO3, GPIO_RISING_EDGE);
+	set_irq_type(IRQ_GPIO3, IRQT_RISING);
 	/* PDA Bluetooth */
-	set_GPIO_IRQ_edge(GPIO_GPIO2, GPIO_RISING_EDGE);
+	set_irq_type(IRQ_GPIO2, IRQT_RISING);
 #endif /* CONFIG_SA1100_CERF_CPLD */
 
-	set_GPIO_IRQ_edge(GPIO_UCB1200_IRQ, GPIO_RISING_EDGE);
+	set_irq_type(IRQ_GPIO_UCB1200_IRQ, IRQT_RISING);
 }
 
 static void __init
diff -urN linux-2.5.6-pre1/arch/arm/mach-sa1100/graphicsclient.c linux-2.5.6-pre2/arch/arm/mach-sa1100/graphicsclient.c
--- linux-2.5.6-pre1/arch/arm/mach-sa1100/graphicsclient.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/mach-sa1100/graphicsclient.c	Thu Feb 28 13:34:18 2002
@@ -25,8 +25,6 @@
 #include <asm/mach/serial_sa1100.h>
 #include <linux/serial_core.h>
 
-#include <asm/arch/irq.h>
-
 #include "generic.h"
 
 
@@ -68,6 +66,12 @@
 	ADS_INT_EN1 |= (1 << (irq - ADS_EXT_IRQ(0)));
 }
 
+static struct irqchip ADS0_chip = {
+	ack:	ADS_mask_and_ack_irq0,
+	mask:	ADS_mask_irq0,
+	unmask:	ADS_unmask_irq0,
+};
+
 static void ADS_mask_and_ack_irq1(unsigned int irq)
 {
 	int mask = (1 << (irq - ADS_EXT_IRQ(8)));
@@ -85,9 +89,15 @@
 	ADS_INT_EN2 |= (1 << (irq - ADS_EXT_IRQ(8)));
 }
 
+static struct irqchip ADS1_chip = {
+	ack:	ADS_mask_and_ack_irq1,
+	mask:	ADS_mask_irq1,
+	unmask:	ADS_unmask_irq1,
+};
+
 static void __init graphicsclient_init_irq(void)
 {
-	int irq;
+	unsigned int irq;
 
 	/* First the standard SA1100 IRQs */
 	sa1100_init_irq();
@@ -100,18 +110,14 @@
 	ADS_INT_ST2 = 0xff;
 
 	for (irq = ADS_EXT_IRQ(0); irq <= ADS_EXT_IRQ(7); irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 1;
-		irq_desc[irq].mask_ack	= ADS_mask_and_ack_irq0;
-		irq_desc[irq].mask	= ADS_mask_irq0;
-		irq_desc[irq].unmask	= ADS_unmask_irq0;
+		set_irq_chip(irq, &ADS0_chip);
+		set_irq_handler(irq, do_level_IRQ);
+		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
 	for (irq = ADS_EXT_IRQ(8); irq <= ADS_EXT_IRQ(15); irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 1;
-		irq_desc[irq].mask_ack	= ADS_mask_and_ack_irq1;
-		irq_desc[irq].mask	= ADS_mask_irq1;
-		irq_desc[irq].unmask	= ADS_unmask_irq1;
+		set_irq_chip(irq, &ADS1_chip);
+		set_irq_handler(irq, do_level_IRQ);
+		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
 	set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE);
 	setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq );
@@ -148,6 +154,8 @@
   { GPIO_GC_UART2_CTS, 0, NULL,NULL }
 };
 
+#error Old code.  Someone needs to decide what to do with this
+#if 0 
 static void
 graphicsclient_cts_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -243,6 +251,7 @@
 
 	return 0;
 }
+#endif
 
 static u_int graphicsclient_get_mctrl(struct uart_port *port)
 {
@@ -296,8 +305,6 @@
 }
 
 static struct sa1100_port_fns graphicsclient_port_fns __initdata = {
-	open:		graphicsclient_uart_open,
-	close:		graphicsclient_uart_close,
 	get_mctrl:	graphicsclient_get_mctrl,
 	set_mctrl:	graphicsclient_set_mctrl,
 	pm:		graphicsclient_uart_pm,
diff -urN linux-2.5.6-pre1/arch/arm/mach-sa1100/graphicsmaster.c linux-2.5.6-pre2/arch/arm/mach-sa1100/graphicsmaster.c
--- linux-2.5.6-pre1/arch/arm/mach-sa1100/graphicsmaster.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/mach-sa1100/graphicsmaster.c	Thu Feb 28 13:34:18 2002
@@ -23,8 +23,6 @@
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
 
-#include <asm/arch/irq.h>
-
 #include "generic.h"
 #include "sa1111.h"
 
@@ -130,6 +128,12 @@
 	ADS_INT_EN1 |= (1 << (irq - ADS_EXT_IRQ(0)));
 }
 
+static struct irqchip ADS0_chip = {
+	ack:	ADS_mask_and_ack_irq0,
+	mask:	ADS_mask_irq0,
+	unmask:	ADS_unmask_irq0,
+};
+
 static void ADS_mask_and_ack_irq1(unsigned int irq)
 {
 	int mask = (1 << (irq - ADS_EXT_IRQ(8)));
@@ -147,9 +151,15 @@
 	ADS_INT_EN2 |= (1 << (irq - ADS_EXT_IRQ(8)));
 }
 
+static struct irqchip ADS1_chip = {
+	ack:	ADS_mask_irq1,
+	mask:	ADS_mask_irq1,
+	unmask:	ADS_mask_irq1,
+};
+
 static void __init graphicsmaster_init_irq(void)
 {
-	int irq;
+	unsigned int irq;
 
 	/* First the standard SA1100 IRQs */
 	sa1100_init_irq();
@@ -162,18 +172,14 @@
 	ADS_INT_ST2 = 0xff;
 
 	for (irq = ADS_EXT_IRQ(0); irq <= ADS_EXT_IRQ(7); irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 1;
-		irq_desc[irq].mask_ack	= ADS_mask_and_ack_irq0;
-		irq_desc[irq].mask	= ADS_mask_irq0;
-		irq_desc[irq].unmask	= ADS_unmask_irq0;
+		set_irq_chip(irq, &ADS0_chip);
+		set_irq_handler(irq, do_level_IRQ);
+		set_irq_flags(irq, IRQF_PROBE | IRQF_VALID);
 	}
 	for (irq = ADS_EXT_IRQ(8); irq <= ADS_EXT_IRQ(15); irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 1;
-		irq_desc[irq].mask_ack	= ADS_mask_and_ack_irq1;
-		irq_desc[irq].mask	= ADS_mask_irq1;
-		irq_desc[irq].unmask	= ADS_unmask_irq1;
+		set_irq_chip(irq, &ADS1_chip);
+		set_irq_handler(irq, do_level_IRQ);
+		set_irq_flags(irq, IRQF_PROBE | IRQF_VALID);
 	}
 	set_GPIO_IRQ_edge(GPIO_GPIO0, GPIO_FALLING_EDGE);
 	setup_arm_irq( IRQ_GPIO0, &ADS_ext_irq );
@@ -206,6 +212,8 @@
   LAST_DESC
 };
 
+#error Old code.  Someone needs to decide what to do about this.
+#if 0
 static int graphicsmaster_uart_open(struct uart_port *port, struct uart_info *info)
 {
 	int	ret = 0;
@@ -226,6 +234,7 @@
 	}
 	return ret;
 }
+#endif
 
 static u_int graphicsmaster_get_mctrl(struct uart_port *port)
 {
@@ -279,7 +288,6 @@
 }
 
 static struct sa1100_port_fns graphicsmaster_port_fns __initdata = {
-	open:		graphicsmaster_uart_open,
 	get_mctrl:	graphicsmaster_get_mctrl,
 	set_mctrl:	graphicsmaster_set_mctrl,
 	pm:		graphicsmaster_uart_pm,
diff -urN linux-2.5.6-pre1/arch/arm/mach-sa1100/h3600.c linux-2.5.6-pre2/arch/arm/mach-sa1100/h3600.c
--- linux-2.5.6-pre1/arch/arm/mach-sa1100/h3600.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/mach-sa1100/h3600.c	Thu Feb 28 13:34:18 2002
@@ -59,7 +59,7 @@
 			  | GPIO_H3100_IR_ON	  \
 			  | GPIO_H3100_IR_FSEL)
 
-void h3100_init_egpio( void )
+static void h3100_init_egpio( void )
 {
 	GPDR |= H3100_DIRECT_EGPIO;
 	GPCR = H3100_DIRECT_EGPIO;   /* Initially all off */
@@ -72,7 +72,7 @@
 	H3600_EGPIO = h3600_egpio;
 }
 
-void h3100_control_egpio( enum ipaq_egpio_type x, int setp )
+static void h3100_control_egpio( enum ipaq_egpio_type x, int setp )
 {
 	unsigned int egpio = 0;
 	long	     gpio = 0;
@@ -138,7 +138,7 @@
 	*/
 }
 
-unsigned long h3100_read_egpio( void )
+static unsigned long h3100_read_egpio( void )
 {
 	return h3600_egpio;
 }
@@ -154,13 +154,13 @@
 
 /************************* H3600 *************************/
 
-void h3600_init_egpio( void )
+static void h3600_init_egpio( void )
 {
 	h3600_egpio = EGPIO_H3600_RS232_ON;
 	H3600_EGPIO = h3600_egpio;
 }
 
-void h3600_control_egpio( enum ipaq_egpio_type x, int setp )
+static void h3600_control_egpio( enum ipaq_egpio_type x, int setp )
 {
 	unsigned int egpio = 0;
 	unsigned long flags;
@@ -217,7 +217,7 @@
 	local_irq_restore(flags);
 }
 
-unsigned long h3600_read_egpio( void )
+static unsigned long h3600_read_egpio( void )
 {
 	return h3600_egpio;
 }
@@ -237,7 +237,7 @@
 static unsigned int h3800_asic1_gpio;
 static unsigned int h3800_asic2_gpio;
 
-void h3800_init_egpio(void)
+static void h3800_init_egpio(void)
 {
 	/* Set up ASIC #1 */
 	H3800_ASIC1_GPIO_Direction    = ASIC1_OUTPUTS;		  /* All outputs */
@@ -271,7 +271,7 @@
 	H3800_ASIC1_FlashWP_VPP_ON = 0;
 }
 
-void h3800_control_egpio( enum ipaq_egpio_type x, int setp )
+static void h3800_control_egpio( enum ipaq_egpio_type x, int setp )
 {
 	unsigned int set_asic1_egpio = 0;
 	unsigned int clear_asic1_egpio = 0;
@@ -325,7 +325,7 @@
 	local_irq_restore(flags);
 }
 
-unsigned long h3800_read_egpio( void )
+static unsigned long h3800_read_egpio( void )
 {
 	return h3800_asic1_gpio | (h3800_asic2_gpio << 16);
 }
diff -urN linux-2.5.6-pre1/arch/arm/mach-sa1100/irq.c linux-2.5.6-pre2/arch/arm/mach-sa1100/irq.c
--- linux-2.5.6-pre1/arch/arm/mach-sa1100/irq.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/mach-sa1100/irq.c	Thu Feb 28 13:34:18 2002
@@ -19,7 +19,6 @@
 #include <asm/hardware.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
-#include <asm/arch/irq.h>
 
 #include "generic.h"
 
@@ -30,156 +29,170 @@
  * This must be called *before* the appropriate IRQ is registered.
  * Use this instead of directly setting GRER/GFER.
  */
-
 static int GPIO_IRQ_rising_edge;
 static int GPIO_IRQ_falling_edge;
+static int GPIO_IRQ_mask = (1 << 11) - 1;
 
-void set_GPIO_IRQ_edge( int gpio_mask, int edge )
+static void sa1100_manual_rerun(unsigned int irq)
 {
-	int flags;
-
-	local_irq_save(flags);
-	if (edge & GPIO_FALLING_EDGE)
-		GPIO_IRQ_falling_edge |= gpio_mask;
-	else
-		GPIO_IRQ_falling_edge &= ~gpio_mask;
-	if (edge & GPIO_RISING_EDGE)
-		GPIO_IRQ_rising_edge |= gpio_mask;
-	else
-		GPIO_IRQ_rising_edge &= ~gpio_mask;
-	GPDR &= ~gpio_mask;
-	GAFR &= ~gpio_mask;
-	restore_flags(flags);
+	struct pt_regs regs;
+	memset(&regs, 0, sizeof(regs));
+	irq_desc[irq].handle(irq, &irq_desc[irq], &regs);
 }
 
-EXPORT_SYMBOL(set_GPIO_IRQ_edge);
+#define GPIO11_27_MASK(irq)	(1 << GPIO_11_27_IRQ(irq))
 
+static int sa1100_gpio_type(unsigned int irq, unsigned int type)
+{
+	unsigned int mask;
 
-/*
- * We don't need to ACK IRQs on the SA1100 unless they're GPIOs
- * this is for internal IRQs i.e. from 11 to 31.
- */
+	printk(KERN_DEBUG "IRQ%d: ", irq);
 
-static void sa1100_mask_irq(unsigned int irq)
-{
-	ICMR &= ~(1 << irq);
-}
+	if (irq <= 10)
+		mask = 1 << irq;
+	else
+		mask = GPIO11_27_MASK(irq);
 
-static void sa1100_unmask_irq(unsigned int irq)
-{
-	ICMR |= (1 << irq);
+	if (type & __IRQT_RISEDGE) {
+		printk("rising ");
+		GPIO_IRQ_rising_edge |= mask;
+	} else
+		GPIO_IRQ_rising_edge &= ~mask;
+	if (type & __IRQT_FALEDGE) {
+		printk("falling ");
+		GPIO_IRQ_falling_edge |= mask;
+	} else
+		GPIO_IRQ_falling_edge &= ~mask;
+
+	printk("edges\n");
+
+	GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
+	GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
+
+	return 0;
 }
 
 /*
  * GPIO IRQs must be acknoledged.  This is for IRQs from 0 to 10.
  */
-
-static void sa1100_mask_and_ack_GPIO0_10_irq(unsigned int irq)
+static void sa1100_low_gpio_ack(unsigned int irq)
 {
-	ICMR &= ~(1 << irq);
 	GEDR = (1 << irq);
 }
 
-static void sa1100_mask_GPIO0_10_irq(unsigned int irq)
+static void sa1100_low_gpio_mask(unsigned int irq)
 {
 	ICMR &= ~(1 << irq);
 }
 
-static void sa1100_unmask_GPIO0_10_irq(unsigned int irq)
+static void sa1100_low_gpio_unmask(unsigned int irq)
 {
-	GRER = (GRER & ~(1 << irq)) | (GPIO_IRQ_rising_edge & (1 << irq));
-	GFER = (GFER & ~(1 << irq)) | (GPIO_IRQ_falling_edge & (1 << irq));
-	ICMR |= (1 << irq);
+	ICMR |= 1 << irq;
 }
 
+static struct irqchip sa1100_low_gpio_chip = {
+	ack:		sa1100_low_gpio_ack,
+	mask:		sa1100_low_gpio_mask,
+	unmask:		sa1100_low_gpio_unmask,
+	rerun:		sa1100_manual_rerun,
+	type:		sa1100_gpio_type,
+};
+
 /*
- * Install handler for GPIO 11-27 edge detect interrupts
+ * IRQ11 (GPIO11 through 27) handler.  We enter here with the
+ * irq_controller_lock held, and IRQs disabled.  Decode the IRQ
+ * and call the handler.
  */
-
-static int GPIO_11_27_enabled;		/* enabled i.e. unmasked GPIO IRQs */
-static int GPIO_11_27_spurious;		/* GPIOs that triggered when masked */
-
-static void sa1100_GPIO11_27_demux(int irq, void *dev_id,
-				   struct pt_regs *regs)
+static void
+sa1100_high_gpio_handler(unsigned int irq, struct irqdesc *desc,
+			 struct pt_regs *regs)
 {
-	int i, spurious;
+	unsigned int mask;
 
-	while ((irq = (GEDR & 0xfffff800))) {
+	mask = GEDR & 0xfffff800;
+	do {
 		/*
-		 * We don't want to clear GRER/GFER when the corresponding
-		 * IRQ is masked because we could miss a level transition
-		 * i.e. an IRQ which need servicing as soon as it is
-		 * unmasked.  However, such situation should happen only
-		 * during the loop below.  Thus all IRQs which aren't
-		 * enabled at this point are considered spurious.  Those
-		 * are cleared but only de-activated if they happen twice.
+		 * clear down all currently active IRQ sources.
+		 * We will be processing them all.
 		 */
-		spurious = irq & ~GPIO_11_27_enabled;
-		if (spurious) {
-			GEDR = spurious;
-			GRER &= ~(spurious & GPIO_11_27_spurious);
-			GFER &= ~(spurious & GPIO_11_27_spurious);
-			GPIO_11_27_spurious |= spurious;
-			irq ^= spurious;
-			if (!irq) continue;
-		}
-
-		for (i = 11; i <= 27; ++i) {
-			if (irq & (1<<i)) {
-				do_IRQ(IRQ_GPIO11 + i - 11, regs);
-			}
-		}
-	}
-}
+		GEDR = mask;
 
-static struct irqaction GPIO11_27_irq = {
-	name:		"GPIO 11-27",
-	handler:	sa1100_GPIO11_27_demux,
-	flags:		SA_INTERRUPT
-};
+		irq = IRQ_GPIO11;
+		desc = irq_desc + irq;
+		mask >>= 11;
+		do {
+			if (mask & 1)
+				desc->handle(irq, desc, regs);
+			mask >>= 1;
+			irq++;
+			desc++;
+		} while (mask);
+
+		mask = GEDR & 0xfffff800;
+	} while (mask);
+}
 
-static void sa1100_mask_and_ack_GPIO11_27_irq(unsigned int irq)
+/*
+ * Like GPIO0 to 10, GPIO11-27 IRQs need to be handled specially.
+ * In addition, the IRQs are all collected up into one bit in the
+ * interrupt controller registers.
+ */
+static void sa1100_high_gpio_ack(unsigned int irq)
 {
-	int mask = (1 << GPIO_11_27_IRQ(irq));
-	GPIO_11_27_spurious &= ~mask;
-	GPIO_11_27_enabled &= ~mask;
+	unsigned int mask = GPIO11_27_MASK(irq);
+
 	GEDR = mask;
 }
 
-static void sa1100_mask_GPIO11_27_irq(unsigned int irq)
+static void sa1100_high_gpio_mask(unsigned int irq)
 {
-	int mask = (1 << GPIO_11_27_IRQ(irq));
-	GPIO_11_27_spurious &= ~mask;
-	GPIO_11_27_enabled &= ~mask;
+	unsigned int mask = GPIO11_27_MASK(irq);
+
+	GPIO_IRQ_mask &= ~mask;
+
+	GRER &= ~mask;
+	GFER &= ~mask;
 }
 
-static void sa1100_unmask_GPIO11_27_irq(unsigned int irq)
+static void sa1100_high_gpio_unmask(unsigned int irq)
 {
-	int mask = (1 << GPIO_11_27_IRQ(irq));
-	if (GPIO_11_27_spurious & mask) {
-		/*
-		 * We don't want to miss an interrupt that would have occurred
-		 * while it was masked.  Simulate it if it is the case.
-		 */
-		int state = GPLR;
-		if (((state & GPIO_IRQ_rising_edge) |
-		     (~state & GPIO_IRQ_falling_edge)) & mask)
-		{
-			/* just in case it gets referenced: */
-			struct pt_regs dummy;
-
-			memzero(&dummy, sizeof(dummy));
-			do_IRQ(irq, &dummy);
-
-			/* we are being called recursively from do_IRQ() */
-			return;
-		}
-	}
-	GPIO_11_27_enabled |= mask;
-	GRER = (GRER & ~mask) | (GPIO_IRQ_rising_edge & mask);
-	GFER = (GFER & ~mask) | (GPIO_IRQ_falling_edge & mask);
+	unsigned int mask = GPIO11_27_MASK(irq);
+
+	GPIO_IRQ_mask |= mask;
+
+	GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
+	GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
 }
 
+static struct irqchip sa1100_high_gpio_chip = {
+	ack:		sa1100_high_gpio_ack,
+	mask:		sa1100_high_gpio_mask,
+	unmask:		sa1100_high_gpio_unmask,
+	rerun:		sa1100_manual_rerun,
+	type:		sa1100_gpio_type,
+};
+
+/*
+ * We don't need to ACK IRQs on the SA1100 unless they're GPIOs
+ * this is for internal IRQs i.e. from 11 to 31.
+ */
+static void sa1100_mask_irq(unsigned int irq)
+{
+	ICMR &= ~(1 << irq);
+}
+
+static void sa1100_unmask_irq(unsigned int irq)
+{
+	ICMR |= (1 << irq);
+}
+
+static struct irqchip sa1100_normal_chip = {
+	ack:		sa1100_mask_irq,
+	mask:		sa1100_mask_irq,
+	unmask:		sa1100_unmask_irq,
+	/* rerun should never be called */
+};
+
 static struct resource irq_resource = {
 	name:	"irqs",
 	start:	0x90050000,
@@ -188,7 +201,7 @@
 
 void __init sa1100_init_irq(void)
 {
-	int irq;
+	unsigned int irq;
 
 	request_resource(&iomem_resource, &irq_resource);
 
@@ -210,33 +223,32 @@
 	ICCR = 1;
 
 	for (irq = 0; irq <= 10; irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 1;
-		irq_desc[irq].mask_ack	= sa1100_mask_and_ack_GPIO0_10_irq;
-		irq_desc[irq].mask	= sa1100_mask_GPIO0_10_irq;
-		irq_desc[irq].unmask	= sa1100_unmask_GPIO0_10_irq;
+		set_irq_chip(irq, &sa1100_low_gpio_chip);
+		set_irq_handler(irq, do_edge_IRQ);
+		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
 
-	for (irq = 11; irq <= 31; irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 0;
-		irq_desc[irq].mask_ack	= sa1100_mask_irq;
-		irq_desc[irq].mask	= sa1100_mask_irq;
-		irq_desc[irq].unmask	= sa1100_unmask_irq;
+	for (irq = 12; irq <= 31; irq++) {
+		set_irq_chip(irq, &sa1100_normal_chip);
+		set_irq_handler(irq, do_level_IRQ);
+		set_irq_flags(irq, IRQF_VALID);
 	}
 
 	for (irq = 32; irq <= 48; irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 1;
-		irq_desc[irq].mask_ack	= sa1100_mask_and_ack_GPIO11_27_irq;
-		irq_desc[irq].mask	= sa1100_mask_GPIO11_27_irq;
-		irq_desc[irq].unmask	= sa1100_unmask_GPIO11_27_irq;
+		set_irq_chip(irq, &sa1100_high_gpio_chip);
+		set_irq_handler(irq, do_edge_IRQ);
+		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
-	setup_arm_irq( IRQ_GPIO11_27, &GPIO11_27_irq );
+
+	/*
+	 * Install handler for GPIO 11-27 edge detect interrupts
+	 */
+	set_irq_chip(IRQ_GPIO11_27, &sa1100_normal_chip);
+	set_irq_chained_handler(IRQ_GPIO11_27, sa1100_high_gpio_handler);
 
 	/*
 	 * We generally don't want the LCD IRQ being
 	 * enabled as soon as we request it.
 	 */
-	irq_desc[IRQ_LCD].noautoenable = 1;
+	set_irq_flags(IRQ_LCD, IRQF_VALID | IRQF_NOAUTOEN);
 }
diff -urN linux-2.5.6-pre1/arch/arm/mach-sa1100/jornada720.c linux-2.5.6-pre2/arch/arm/mach-sa1100/jornada720.c
--- linux-2.5.6-pre1/arch/arm/mach-sa1100/jornada720.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/arch/arm/mach-sa1100/jornada720.c	Thu Feb 28 13:34:18 2002
@@ -48,7 +48,7 @@
 
 	/* initialize extra IRQs */
 	set_GPIO_IRQ_edge(GPIO_GPIO1, GPIO_RISING_EDGE);
-	sa1111_init_irq(IRQ_GPIO1));	/* chained on GPIO 1 */
+	sa1111_init_irq(IRQ_GPIO1);	/* chained on GPIO 1 */
 
 	return 0;
 }
diff -urN linux-2.5.6-pre1/arch/arm/mach-sa1100/neponset.c linux-2.5.6-pre2/arch/arm/mach-sa1100/neponset.c
--- linux-2.5.6-pre1/arch/arm/mach-sa1100/neponset.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/arch/arm/mach-sa1100/neponset.c	Thu Feb 28 13:34:18 2002
@@ -15,7 +15,6 @@
 #include <asm/irq.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
-#include <asm/arch/irq.h>
 #include <asm/mach/serial_sa1100.h>
 #include <asm/arch/assabet.h>
 #include <asm/hardware/sa1111.h>
@@ -24,53 +23,78 @@
 
 
 /*
- * Install handler for Neponset IRQ.  Yes, yes... we are way down the IRQ
- * cascade which is not good for IRQ latency, but the hardware has been
- * designed that way...
+ * Install handler for Neponset IRQ.  Note that we have to loop here
+ * since the ETHERNET and USAR IRQs are level based, and we need to
+ * ensure that the IRQ signal is deasserted before returning.  This
+ * is rather unfortunate.
  */
-
-static void neponset_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs )
+static void
+neponset_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
 {
-	int irr;
+	unsigned int irr;
+
+	while (1) {
+		struct irqdesc *d;
+
+		/*
+		 * Acknowledge the parent IRQ.
+		 */
+		desc->chip->ack(irq);
 
-	for(;;){
-		irr = IRR & (IRR_ETHERNET | IRR_USAR | IRR_SA1111);
-		/* Let's have all active IRQ bits high.
-		 * Note: there is a typo in the Neponset user's guide
-		 * for the SA1111 IRR level.
+		/*
+		 * Read the interrupt reason register.  Let's have all
+		 * active IRQ bits high.  Note: there is a typo in the
+		 * Neponset user's guide for the SA1111 IRR level.
 		 */
-		irr ^= (IRR_ETHERNET | IRR_USAR);
-		if (!irr) break;
+		irr = IRR ^ (IRR_ETHERNET | IRR_USAR);
 
-		if( irr & IRR_ETHERNET )
-			do_IRQ(IRQ_NEPONSET_SMC9196, regs);
+		if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
+			break;
 
-		if( irr & IRR_USAR )
-			do_IRQ(IRQ_NEPONSET_USAR, regs);
+		/*
+		 * Since there is no individual mask, we have to
+		 * mask the parent IRQ.  This is safe, since we'll
+		 * recheck the register for any pending IRQs.
+		 */
+		if (irr & (IRR_ETHERNET | IRR_USAR)) {
+			desc->chip->mask(irq);
 
-		if( irr & IRR_SA1111 )
-			sa1111_IRQ_demux(irq, dev_id, regs);
+			if (irr & IRR_ETHERNET) {
+				d = irq_desc + IRQ_NEPONSET_SMC9196;
+				d->handle(IRQ_NEPONSET_SMC9196, d, regs);
+			}
+
+			if (irr & IRR_USAR) {
+				d = irq_desc + IRQ_NEPONSET_USAR;
+				d->handle(IRQ_NEPONSET_USAR, d, regs);
+			}
+
+			desc->chip->unmask(irq);
+		}
+
+		if (irr & IRR_SA1111) {
+			d = irq_desc + IRQ_NEPONSET_SA1111;
+			d->handle(IRQ_NEPONSET_SA1111, d, regs);
+		}
 	}
 }
 
-static struct irqaction neponset_irq = {
-	name:		"Neponset",
-	handler:	neponset_IRQ_demux,
-	flags:		SA_INTERRUPT
-};
-
 static void __init neponset_init_irq(void)
 {
-	sa1111_init_irq(-1);	/* SA1111 IRQ not routed to a GPIO */
-
-	/* setup extra Neponset IRQs */
-	irq_desc[IRQ_NEPONSET_SMC9196].valid	= 1;
-	irq_desc[IRQ_NEPONSET_SMC9196].probe_ok	= 1;
-	irq_desc[IRQ_NEPONSET_USAR].valid	= 1;
-	irq_desc[IRQ_NEPONSET_USAR].probe_ok	= 1;
+	/*
+	 * Install handler for GPIO25.
+	 */
+	set_irq_type(IRQ_GPIO25, IRQT_RISING);
+	set_irq_chained_handler(IRQ_GPIO25, neponset_irq_handler);
 
-	set_GPIO_IRQ_edge(GPIO_GPIO25, GPIO_RISING_EDGE);
-	setup_arm_irq(IRQ_GPIO25, &neponset_irq);
+	/*
+	 * Setup other Neponset IRQs.  SA1111 will be done by the
+	 * generic SA1111 code.
+	 */
+	set_irq_handler(IRQ_NEPONSET_SMC9196, do_simple_IRQ);
+	set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE);
+	set_irq_handler(IRQ_NEPONSET_USAR, do_simple_IRQ);
+	set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE);
 }
 
 static int __init neponset_init(void)
@@ -101,6 +125,8 @@
 		return -ENODEV;
 	}
 
+	neponset_init_irq();
+
 	/*
 	 * Disable GPIO 0/1 drivers so the buttons work on the module.
 	 */
@@ -146,7 +172,10 @@
 	 */
 	sa1110_mb_enable();
 
-	neponset_init_irq();
+	/*
+	 * Initialise SA1111 IRQs
+	 */
+	sa1111_init_irq(IRQ_NEPONSET_SA1111);
 
 	return 0;
 }
diff -urN linux-2.5.6-pre1/arch/arm/mach-sa1100/pm.c linux-2.5.6-pre2/arch/arm/mach-sa1100/pm.c
--- linux-2.5.6-pre1/arch/arm/mach-sa1100/pm.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/arch/arm/mach-sa1100/pm.c	Thu Feb 28 13:34:18 2002
@@ -51,8 +51,6 @@
 
 int pm_do_suspend(void)
 {
-	int retval;
-
 	/* set up pointer to sleep parameters */
 	sleep_save = kmalloc(SLEEP_SAVE_SIZE*sizeof(long), GFP_ATOMIC);
 	if (!sleep_save)
@@ -107,7 +105,7 @@
 	PSPR = 0;
 
 #ifdef DEBUG
-	printk("*** made it back from resume\n");
+	printk(KERN_DEBUG "*** made it back from resume\n");
 #endif
 
 	/* restore registers */
@@ -171,21 +169,16 @@
 #define ACPI_S1_SLP_TYP 19
 
 /*
- * Send us to sleep.  We must not be called from IRQ context.
+ * Send us to sleep.
  */
 static int sysctl_pm_do_suspend(void)
 {
 	int retval;
 
-	if (in_interrupt()) {
-		printk(KERN_CRIT "pm_do_suspend() called from IRQ\n");
-		return -EINVAL;
-	}
-
 	retval = pm_send_all(PM_SUSPEND, (void *)3);
 
 	if (retval == 0) {
-		retval = __pm_do_suspend();
+		retval = pm_do_suspend();
 
 		pm_send_all(PM_RESUME, (void *)0);
 	}
@@ -193,7 +186,6 @@
 	return retval;
 }
 
-
 static struct ctl_table pm_table[] =
 {
 	{ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_do_suspend},
diff -urN linux-2.5.6-pre1/arch/arm/mach-sa1100/sa1111.c linux-2.5.6-pre2/arch/arm/mach-sa1100/sa1111.c
--- linux-2.5.6-pre1/arch/arm/mach-sa1100/sa1111.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/arch/arm/mach-sa1100/sa1111.c	Thu Feb 28 13:34:18 2002
@@ -27,7 +27,6 @@
 #include <asm/hardware.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
-#include <asm/arch/irq.h>
 
 #include <asm/hardware/sa1111.h>
 
@@ -40,70 +39,104 @@
 EXPORT_SYMBOL(sa1111_resource);
 
 /*
- * SA1111 interrupt support
+ * SA1111 interrupt support.  Since clearing an IRQ while there are
+ * active IRQs causes the interrupt output to pulse, the upper levels
+ * will call us again if there are more interrupts to process.
  */
-void sa1111_IRQ_demux(int irq, void *dev_id, struct pt_regs *regs)
+static void
+sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
 {
-	unsigned long stat0, stat1;
+	unsigned int stat0, stat1, i;
 
-	while (1) {
-		int i;
+	desc->chip->ack(irq);
 
-		stat0 = INTSTATCLR0;
-		stat1 = INTSTATCLR1;
+	stat0 = INTSTATCLR0;
+	stat1 = INTSTATCLR1;
 
-		if (stat0 == 0 && stat1 == 0)
-			break;
-
-		for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1)
-			if (stat0 & 1)
-				do_IRQ(i, regs);
-
-		for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1)
-			if (stat1 & 1)
-				do_IRQ(i, regs);
+	if (stat0 == 0 && stat1 == 0) {
+		do_bad_IRQ(irq, desc, regs);
+		return;
 	}
+
+	for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1)
+		if (stat0 & 1)
+			do_edge_IRQ(i, irq_desc + i, regs);
+
+	for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1)
+		if (stat1 & 1)
+			do_edge_IRQ(i, irq_desc + i, regs);
 }
 
 #define SA1111_IRQMASK_LO(x)	(1 << (x - IRQ_SA1111_START))
 #define SA1111_IRQMASK_HI(x)	(1 << (x - IRQ_SA1111_START - 32))
 
+static void sa1111_ack_lowirq(unsigned int irq)
+{
+	INTSTATCLR0 = SA1111_IRQMASK_LO(irq);
+}
+
+static void sa1111_mask_lowirq(unsigned int irq)
+{
+	INTEN0 &= ~SA1111_IRQMASK_LO(irq);
+}
+
+static void sa1111_unmask_lowirq(unsigned int irq)
+{
+	INTEN0 |= SA1111_IRQMASK_LO(irq);
+}
+
 /*
- * A note about masking IRQs:
- *
- * The GPIO IRQ edge detection only functions while the IRQ itself is
- * enabled; edges are not detected while the IRQ is disabled.
- *
- * This is especially important for the PCMCIA signals, where we must
- * pick up every transition.  We therefore do not disable the IRQs
- * while processing them.
- *
- * However, since we are changed to a GPIO on the host processor,
- * all SA1111 IRQs will be disabled while we're processing any SA1111
- * IRQ.
- *
- * Note also that changing INTPOL while an IRQ is enabled will itself
- * trigger an IRQ.
+ * Attempt to re-trigger the interrupt.  The SA1111 contains a register
+ * (INTSET) which claims to do this.  However, in practice no amount of
+ * manipulation of INTEN and INTSET guarantees that the interrupt will
+ * be triggered.  In fact, its very difficult, if not impossible to get
+ * INTSET to re-trigger the interrupt.
  */
-static void sa1111_mask_and_ack_lowirq(unsigned int irq)
+static void sa1111_rerun_lowirq(unsigned int irq)
 {
 	unsigned int mask = SA1111_IRQMASK_LO(irq);
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		INTPOL0 ^= mask;
+		INTPOL0 ^= mask;
+		if (INTSTATCLR1 & mask)
+			break;
+	}
 
-	//INTEN0 &= ~mask;
-	INTSTATCLR0 = mask;
+	if (i == 8)
+		printk(KERN_ERR "Danger Will Robinson: failed to "
+			"re-trigger IRQ%d\n", irq);
 }
 
-static void sa1111_mask_and_ack_highirq(unsigned int irq)
+static int sa1111_type_lowirq(unsigned int irq, unsigned int flags)
 {
-	unsigned int mask = SA1111_IRQMASK_HI(irq);
+	unsigned int mask = SA1111_IRQMASK_LO(irq);
+
+	if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0)
+		return -EINVAL;
+
+	printk("IRQ%d: %s edge\n", irq, flags & __IRQT_RISEDGE ? "rising" : "falling");
 
-	//INTEN1 &= ~mask;
-	INTSTATCLR1 = mask;
+	if (flags & __IRQT_RISEDGE)
+		INTPOL0 &= ~mask;
+	else
+		INTPOL0 |= mask;
+
+	return 0;
 }
 
-static void sa1111_mask_lowirq(unsigned int irq)
+static struct irqchip sa1111_low_chip = {
+	ack:		sa1111_ack_lowirq,
+	mask:		sa1111_mask_lowirq,
+	unmask:		sa1111_unmask_lowirq,
+	rerun:		sa1111_rerun_lowirq,
+	type:		sa1111_type_lowirq,
+};
+
+static void sa1111_ack_highirq(unsigned int irq)
 {
-	INTEN0 &= ~SA1111_IRQMASK_LO(irq);
+	INTSTATCLR1 = SA1111_IRQMASK_HI(irq);
 }
 
 static void sa1111_mask_highirq(unsigned int irq)
@@ -111,19 +144,63 @@
 	INTEN1 &= ~SA1111_IRQMASK_HI(irq);
 }
 
-static void sa1111_unmask_lowirq(unsigned int irq)
+static void sa1111_unmask_highirq(unsigned int irq)
 {
-	INTEN0 |= SA1111_IRQMASK_LO(irq);
+	INTEN1 |= SA1111_IRQMASK_HI(irq);
 }
 
-static void sa1111_unmask_highirq(unsigned int irq)
+/*
+ * Attempt to re-trigger the interrupt.  The SA1111 contains a register
+ * (INTSET) which claims to do this.  However, in practice no amount of
+ * manipulation of INTEN and INTSET guarantees that the interrupt will
+ * be triggered.  In fact, its very difficult, if not impossible to get
+ * INTSET to re-trigger the interrupt.
+ */
+static void sa1111_rerun_highirq(unsigned int irq)
 {
-	INTEN1 |= SA1111_IRQMASK_HI(irq);
+	unsigned int mask = SA1111_IRQMASK_HI(irq);
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		INTPOL1 ^= mask;
+		INTPOL1 ^= mask;
+		if (INTSTATCLR1 & mask)
+			break;
+	}
+
+	if (i == 8)
+		printk(KERN_ERR "Danger Will Robinson: failed to "
+			"re-trigger IRQ%d\n", irq);
 }
 
+static int sa1111_type_highirq(unsigned int irq, unsigned int flags)
+{
+	unsigned int mask = SA1111_IRQMASK_HI(irq);
+
+	if ((!(flags & __IRQT_RISEDGE) ^ !(flags & __IRQT_FALEDGE)) == 0)
+		return -EINVAL;
+
+	printk("IRQ%d: %s edge\n", irq, flags & __IRQT_RISEDGE ? "rising" : "falling");
+
+	if (flags & __IRQT_RISEDGE)
+		INTPOL1 &= ~mask;
+	else
+		INTPOL1 |= mask;
+
+	return 0;
+}
+
+static struct irqchip sa1111_high_chip = {
+	ack:		sa1111_ack_highirq,
+	mask:		sa1111_mask_highirq,
+	unmask:		sa1111_unmask_highirq,
+	rerun:		sa1111_rerun_highirq,
+	type:		sa1111_type_highirq,
+};
+
 void __init sa1111_init_irq(int irq_nr)
 {
-	int irq, ret;
+	unsigned int irq;
 
 	request_mem_region(_INTTEST0, 512, "irqs");
 
@@ -140,33 +217,26 @@
 		  SA1111_IRQMASK_HI(S1_READY_NINT);
 
 	/* clear all IRQs */
-	INTSTATCLR0 = -1;
-	INTSTATCLR1 = -1;
+	INTSTATCLR0 = ~0;
+	INTSTATCLR1 = ~0;
 
 	for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 0;
-		irq_desc[irq].mask_ack	= sa1111_mask_and_ack_lowirq;
-		irq_desc[irq].mask	= sa1111_mask_lowirq;
-		irq_desc[irq].unmask	= sa1111_unmask_lowirq;
+		set_irq_chip(irq, &sa1111_low_chip);
+		set_irq_handler(irq, do_edge_IRQ);
+		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
+
 	for (irq = AUDXMTDMADONEA; irq <= S1_BVD1_STSCHG; irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 0;
-		irq_desc[irq].mask_ack	= sa1111_mask_and_ack_highirq;
-		irq_desc[irq].mask	= sa1111_mask_highirq;
-		irq_desc[irq].unmask	= sa1111_unmask_highirq;
+		set_irq_chip(irq, &sa1111_high_chip);
+		set_irq_handler(irq, do_edge_IRQ);
+		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
 
-	/* Register SA1111 interrupt */
-	if (irq_nr < 0)
-		return;
-
-	ret = request_irq(irq_nr, sa1111_IRQ_demux, SA_INTERRUPT,
-			  "SA1111", NULL);
-	if (ret < 0)
-		printk(KERN_ERR "SA1111: unable to claim IRQ%d: %d\n",
-		       irq_nr, ret);
+	/*
+	 * Register SA1111 interrupt
+	 */
+	set_irq_type(irq_nr, IRQT_RISING);
+	set_irq_chained_handler(irq_nr, sa1111_irq_handler);
 }
 
 /**
@@ -199,12 +269,12 @@
 	 */
 	id = SBI_SKID;
 	if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
-		printk(KERN_DEBUG "SA-1111 not detected: ID = %08lx\n", id);
+		printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id);
 		ret = -ENODEV;
 		goto release;
 	}
 
-	printk(KERN_INFO "SA-1111 Microprocessor Companion Chip: "
+	printk(KERN_INFO "SA1111 Microprocessor Companion Chip: "
 		"silicon revision %lx, metal revision %lx\n",
 		(id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK));
 
diff -urN linux-2.5.6-pre1/arch/arm/mach-sa1100/simpad.c linux-2.5.6-pre2/arch/arm/mach-sa1100/simpad.c
--- linux-2.5.6-pre1/arch/arm/mach-sa1100/simpad.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/arm/mach-sa1100/simpad.c	Thu Feb 28 13:34:18 2002
@@ -93,7 +93,7 @@
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
 
-	set_GPIO_IRQ_edge(GPIO_UCB1300_IRQ);
+	set_irq_type(IRQ_GPIO_UCB1300_IRQ, IRQT_RISING);
 }
 
 #ifdef CONFIG_PROC_FS
diff -urN linux-2.5.6-pre1/arch/arm/mach-sa1100/stork.c linux-2.5.6-pre2/arch/arm/mach-sa1100/stork.c
--- linux-2.5.6-pre1/arch/arm/mach-sa1100/stork.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mach-sa1100/stork.c	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,361 @@
+/*
+ * linux/arch/arm/mach-sa1100/stork.c
+ *
+ *     Copyright (C) 2001 Ken Gordon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+#include <asm/setup.h>
+#include <asm/keyboard.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/serial_sa1100.h>
+#include <linux/serial_core.h>
+
+#include "generic.h"
+
+
+#define STORK_VM_BASE_CS1 0xf0000000		/* where we get mapped (virtual) */
+#define STORK_VM_OFF_CS1 0x08000000             /* where we started mapping (physical) */
+#define STORK_VM_ADJUST_CS1 (STORK_VM_BASE_CS1-STORK_VM_OFF_CS1) /* add to the phys to get virt */
+
+#define STORK_VM_BASE_CS2 0xf1000000		/* where we get mapped (virtual) */
+#define STORK_VM_OFF_CS2  0x10000000             /* where we started mapping (physical) */
+#define STORK_VM_ADJUST_CS2 (STORK_VM_BASE_CS2-STORK_VM_OFF_CS2) /* add to the phys to get virt */
+
+static int debug = 0;
+
+static int storkLatchA = 0;
+static int storkLatchB = 0;
+static int storkLCDCPLD[4] = { 0, 0, 0, 0};
+
+int
+storkSetLatchA(int bits)
+{
+    int ret = storkLatchA;
+    volatile unsigned int *latch = (unsigned int *)(STORK_LATCH_A_ADDR+STORK_VM_ADJUST_CS1);
+
+    storkLatchA |= bits;
+    *latch = storkLatchA;
+    return ret;
+}
+
+int
+storkClearLatchA(int bits)
+{
+    int ret = storkLatchA;
+    volatile unsigned int *latch = (unsigned int *)(STORK_LATCH_A_ADDR+STORK_VM_ADJUST_CS1);
+
+    storkLatchA &= ~bits;
+    *latch = storkLatchA;
+    return ret;
+}
+
+int
+storkSetLCDCPLD(int which, int bits)
+{
+    int ret = storkLCDCPLD[which];
+    volatile unsigned int *latch = (unsigned int *)(STORK_LCDCPLD_BASE_ADDR+STORK_VM_ADJUST_CS2 + 0x20*which);
+
+    storkLCDCPLD[which] |= bits;
+    *latch = storkLCDCPLD[which];
+    return ret;
+}
+
+
+/* NB we don't shadow these 'cos there is no relation between the data written and the data read */
+/* ie the read registers are read only and the write registers write only */
+
+int
+storkGetLCDCPLD(int which)
+{
+    volatile unsigned int *latch = (unsigned int *)(STORK_LCDCPLD_BASE_ADDR+STORK_VM_ADJUST_CS2 + 0x20*which);
+    return *latch;
+}
+
+int
+storkClearLCDCPLD(int which, int bits)
+{
+    int ret = storkLCDCPLD[which];
+    volatile unsigned int *latch = (unsigned int *)(STORK_LCDCPLD_BASE_ADDR+STORK_VM_ADJUST_CS2 + 0x20*which);
+
+    storkLCDCPLD[which] &= ~bits;
+    *latch = storkLCDCPLD[which];
+    return ret;
+}
+
+int
+storkSetLatchB(int bits)
+{
+    int ret = storkLatchB;
+    char buf[100];
+
+    volatile unsigned int *latch = (unsigned int *)(STORK_LATCH_B_ADDR+STORK_VM_ADJUST_CS1);
+    sprintf(buf, "%s: bits %04x\n", __FUNCTION__, bits);
+    if (debug) printk(buf);
+
+    storkLatchB |= bits;
+    *latch = storkLatchB;
+    return ret;
+}
+
+int
+storkClearLatchB(int bits)
+{
+    int ret = storkLatchB;
+    char buf[100];
+
+    volatile unsigned int *latch = (unsigned int *)(STORK_LATCH_B_ADDR+STORK_VM_ADJUST_CS1);
+    sprintf(buf, "%s: bits %04x\n", __FUNCTION__, bits);
+    if (debug) printk(buf);
+
+    storkLatchB &= ~bits;
+    *latch = storkLatchB;
+    return ret;
+}
+
+void
+storkSetGPIO(int bits)
+{
+    char buf[100];
+
+    sprintf(buf, "%s: bits %04x\n", __FUNCTION__, bits);
+    if (debug) printk(buf);
+    GPSR = bits;
+}
+
+void
+storkClearGPIO(int bits)
+{
+    char buf[100];
+
+    sprintf(buf, "%s: bits %04x\n", __FUNCTION__, bits);
+    if (debug) printk(buf);
+    GPCR = bits;
+}
+
+int
+storkGetGPIO()
+{
+    char buf[100];
+
+    int bits = GPLR;
+
+    sprintf(buf, "%s: bits %04x\n", __FUNCTION__, bits);
+    if (debug) printk(buf);
+
+    return bits;
+}
+
+/* this will return the current state of the hardware ANDED with the given bits
+   so NE => at least one bit was set, but maybe not all of them! */
+
+int
+storkTestGPIO(int bits)
+{
+    int val = storkGetGPIO();
+    char buf[100];
+
+    sprintf(buf, "%s: bits %04x val %04x\n", __FUNCTION__, bits, val);
+    if (debug) printk(buf);
+
+    return (val & bits);
+}
+
+/* NB the touch screen and the d to a use the same data and clock out pins */
+
+static void storkClockTS(void)
+{
+    storkSetLatchB(STORK_TOUCH_SCREEN_DCLK);
+    udelay(10);			 /* hmm wait 200ns (min) - ok this ought to be udelay(1) but that doesn't get */
+				 /* consistant values so I'm using 10 (urgh) */
+    storkClearLatchB(STORK_TOUCH_SCREEN_DCLK);
+    udelay(10);
+}
+
+
+int				/* there is always a 12 bit read after the write! */
+storkClockByteToTS(int byte)
+{
+    int timeout = 10000;   /* stuff is meant to happen in 60ns */
+    int bit;
+    int result = 0;
+
+    if (debug) printk("storkClockByteToTS: %02x\n", byte);
+
+    storkClearLatchB(STORK_TOUCH_SCREEN_CS);  /* slect touch screen */
+
+    while (timeout-- > 0)
+        if (storkTestGPIO(GPIO_STORK_TOUCH_SCREEN_BUSY) == 0)
+            break;
+
+    if (timeout < 0) {
+        printk("storkClockBitToTS: GPIO_STORK_TOUCH_SCREEN_BUSY didn't go low!\n\r");
+/* ignore error for now        return; */
+    }
+
+/* clock out the given byte */
+
+    for (bit = 0x80; bit > 0; bit = bit >> 1) {
+
+        if ((bit & byte) == 0)
+            storkClearLatchB(STORK_TOUCH_SCREEN_DIN);
+        else
+            storkSetLatchB(STORK_TOUCH_SCREEN_DIN);
+
+        storkClockTS();
+    }
+
+    storkClockTS();  /* will be busy for at a clock  (at least) */
+
+    for (timeout = 10000; timeout >= 0; timeout--)
+        if (storkTestGPIO(GPIO_STORK_TOUCH_SCREEN_BUSY) == 0)
+            break;
+
+    if (timeout < 0) {
+        printk("storkClockBitToTS: 2nd GPIO_STORK_TOUCH_SCREEN_BUSY didn't go low!\n\r");
+/* ignore error for now        return; */
+    }
+
+/* clock in the result */
+
+    for (bit = 0x0800; bit > 0; bit = bit >> 1) {
+
+        if (storkTestGPIO(GPIO_STORK_TOUCH_SCREEN_DATA))
+            result |= bit;
+
+        storkClockTS();
+    }
+
+    storkSetLatchB(STORK_TOUCH_SCREEN_CS);  /* unselect touch screen */
+
+    return result;
+}
+
+void
+storkClockShortToDtoA(int word)
+{
+    int bit;
+
+    storkClearLatchB(STORK_DA_CS);  /* select D to A */
+
+/* clock out the given byte */
+
+    for (bit = 0x8000; bit > 0; bit = bit >> 1) {
+
+        if ((bit & word) == 0)
+            storkClearLatchB(STORK_TOUCH_SCREEN_DIN);
+        else
+            storkSetLatchB(STORK_TOUCH_SCREEN_DIN);
+
+        storkClockTS();
+    }
+
+    storkSetLatchB(STORK_DA_CS);  /* unselect D to A */
+
+/* set DTOA#_LOAD low then high (min 20ns) to transfer value to D to A */
+    storkClearLatchB(STORK_DA_LD);
+    storkSetLatchB(STORK_DA_LD);
+}
+
+
+
+void
+storkInitTSandDtoA(void)
+{
+    storkClearLatchB(STORK_TOUCH_SCREEN_DCLK | STORK_TOUCH_SCREEN_DIN);
+    storkSetLatchB(STORK_TOUCH_SCREEN_CS | STORK_DA_CS | STORK_DA_LD);
+    storkClockByteToTS(0xE2);	 	/* turn on the reference */
+    storkClockShortToDtoA(0x8D00);	/* turn on the contrast */
+    storkClockShortToDtoA(0x0A00);	/* turn on the brightness */
+}
+
+/* see asm-arm/keyboard.h - there are a bunch of basically virtual functions required */
+/* we have to fill in for them or else we can't call handle_scancode when we see a button pressed */
+
+static int
+stork_kbd_translate(unsigned char scancode, unsigned char *keycode, char rawmode)
+{
+    if (keycode)
+	*keycode = scancode;
+
+    return 1;
+}
+
+static char
+stork_kbd_unexpected_up(unsigned char code)
+{
+    return 0;
+}
+
+
+struct map_desc stork_io_desc[] __initdata = {
+ /* virtual     physical    length      domain     r  w  c  b */
+  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
+  { STORK_VM_BASE_CS1, STORK_VM_OFF_CS1, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* EGPIO 0 */
+  { 0xf1000000, 0x10000000, 0x02800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 2 */
+  { 0xf3800000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 4 */
+  LAST_DESC
+};
+
+int __init
+stork_map_io(void)
+{
+    sa1100_map_io();
+    iotable_init(stork_io_desc);
+
+    sa1100_register_uart(0, 1);	/* com port */
+    sa1100_register_uart(1, 2);
+    sa1100_register_uart(2, 3);
+
+    printk("Stork driver initing latches\r\n");
+
+    storkClearLatchB(STORK_RED_LED);	/* let's have the red LED on please */
+    storkSetLatchB(STORK_YELLOW_LED);
+    storkSetLatchB(STORK_GREEN_LED);
+    storkSetLatchA(STORK_BATTERY_CHARGER_ON);
+    storkSetLatchA(STORK_LCD_5V_POWER_ON);
+    storkSetLatchA(STORK_LCD_3V3_POWER_ON);
+
+    storkInitTSandDtoA();
+
+    k_translate = stork_kbd_translate;
+    k_unexpected_up = stork_kbd_unexpected_up;
+
+    return 0;
+}
+
+
+MACHINE_START(STORK, "Stork Technologies prototype")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	BOOT_PARAMS(0xc0000100)
+	MAPIO(stork_map_io)
+	INITIRQ(sa1100_init_irq)
+MACHINE_END
+
+
+EXPORT_SYMBOL(storkTestGPIO);
+EXPORT_SYMBOL(storkSetGPIO);
+EXPORT_SYMBOL(storkClearGPIO);
+EXPORT_SYMBOL(storkSetLatchA);
+EXPORT_SYMBOL(storkClearLatchA);
+EXPORT_SYMBOL(storkSetLatchB);
+EXPORT_SYMBOL(storkClearLatchB);
+EXPORT_SYMBOL(storkClockByteToTS);
+EXPORT_SYMBOL(storkClockShortToDtoA);
+EXPORT_SYMBOL(storkGetLCDCPLD);
+EXPORT_SYMBOL(storkSetLCDCPLD);
diff -urN linux-2.5.6-pre1/arch/arm/mach-shark/irq.c linux-2.5.6-pre2/arch/arm/mach-shark/irq.c
--- linux-2.5.6-pre1/arch/arm/mach-shark/irq.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/arch/arm/mach-shark/irq.c	Thu Feb 28 13:34:18 2002
@@ -7,6 +7,12 @@
  * include/asm-arm/arch-ebsa110/irq.h
  * Copyright (C) 1996-1998 Russell King
  */
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/ptrace.h>
+#include <linux/interrupt.h>
+
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/mach/irq.h>
@@ -31,12 +37,12 @@
 	if (irq<8) {
 	  mask = 1 << irq;
 	  cached_irq_mask[0] |= mask;
+	  outb(cached_irq_mask[1],0xA1);
 	} else {
 	  mask = 1 << (irq-8);
 	  cached_irq_mask[1] |= mask;
+	  outb(cached_irq_mask[0],0x21);
 	}
-	outb(cached_irq_mask[1],0xA1);
-	outb(cached_irq_mask[0],0x21);
 }
 
 static void shark_enable_8259A_irq(unsigned int irq)
@@ -45,31 +51,15 @@
 	if (irq<8) {
 	  mask = ~(1 << irq);
 	  cached_irq_mask[0] &= mask;
+	  outb(cached_irq_mask[0],0x21);
 	} else {
 	  mask = ~(1 << (irq-8));
 	  cached_irq_mask[1] &= mask;
+	  outb(cached_irq_mask[1],0xA1);
 	}
-	outb(cached_irq_mask[1],0xA1);
-	outb(cached_irq_mask[0],0x21);
 }
 
-/*
- * Careful! The 8259A is a fragile beast, it pretty
- * much _has_ to be done exactly like this (mask it
- * first, _then_ send the EOI, and the order of EOI
- * to the two 8259s is important!
- */
-static void shark_mask_and_ack_8259A_irq(unsigned int irq)
-{
-        if (irq & 8) {
-                cached_irq_mask[1] |= 1 << (irq-8);
-		inb(0xA1);              /* DUMMY */
-                outb(cached_irq_mask[1],0xA1);
-        } else {
-                cached_irq_mask[0] |= 1 << irq;
-                outb(cached_irq_mask[0],0x21);
-	}
-}
+static void shark_ack_8259A_irq(unsigned int irq){}
 
 static void bogus_int(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -78,32 +68,30 @@
 
 static struct irqaction cascade;
 
+static struct irqchip fb_chip = {
+	ack:	shark_ack_8259A_irq,
+	mask:	shark_disable_8259A_irq,
+	unmask:	shark_enable_8259A_irq,
+};
+
 void __init shark_init_irq(void)
 {
 	int irq;
 
 	for (irq = 0; irq < NR_IRQS; irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 1;
-		irq_desc[irq].mask_ack	= shark_mask_and_ack_8259A_irq;
-		irq_desc[irq].mask	= shark_disable_8259A_irq;
-		irq_desc[irq].unmask	= shark_enable_8259A_irq;
+		set_irq_chip(irq, &fb_chip);
+		set_irq_handler(irq, do_edge_IRQ);
+		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
 
-	/* The PICs are initialized to level triggered and auto eoi!
-	 * If they are set to edge triggered they lose some IRQs,
-	 * if they are set to manual eoi they get locked up after
-	 * a short time
-	 */
-
 	/* init master interrupt controller */
-	outb(0x19, 0x20); /* Start init sequence, level triggered */
+	outb(0x11, 0x20); /* Start init sequence, edge triggered (level: 0x19)*/
 	outb(0x00, 0x21); /* Vector base */
 	outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */
 	outb(0x03, 0x21); /* Select 8086 mode , auto eoi*/
 	outb(0x0A, 0x20);
 	/* init slave interrupt controller */
-	outb(0x19, 0xA0); /* Start init sequence, level triggered */
+	outb(0x11, 0xA0); /* Start init sequence, edge triggered */
 	outb(0x08, 0xA1); /* Vector base */
 	outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */
 	outb(0x03, 0xA1); /* Select 8086 mode, auto eoi */
@@ -119,6 +107,6 @@
 	cascade.name = "cascade";
 	cascade.next = NULL;
 	cascade.dev_id = NULL;
-	setup_arm_irq(2,&cascade);
+	setup_irq(2,&cascade);
 }
 
diff -urN linux-2.5.6-pre1/arch/arm/mach-shark/pci.c linux-2.5.6-pre2/arch/arm/mach-shark/pci.c
--- linux-2.5.6-pre1/arch/arm/mach-shark/pci.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/arch/arm/mach-shark/pci.c	Thu Feb 28 13:34:18 2002
@@ -17,11 +17,14 @@
 	if (dev->bus->number == 0)
 		if (dev->devfn == 0) return 255;
 		else return 11;
-	else return 6;
+	else return 255;
 }
 
 struct hw_pci shark_pci __initdata = {
-	init: via82c505_init,
-	swizzle: no_swizzle,
-	map_irq: shark_map_irq
+	setup:		via82c505_setup,
+	swizzle:       	pci_std_swizzle,
+	map_irq:	shark_map_irq,
+	nr_controllers:	1,
+	scan:		via82c505_scan_bus,
+	preinit:	via82c505_preinit
 };
diff -urN linux-2.5.6-pre1/arch/arm/mm/Makefile linux-2.5.6-pre2/arch/arm/mm/Makefile
--- linux-2.5.6-pre1/arch/arm/mm/Makefile	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/arch/arm/mm/Makefile	Thu Feb 28 13:34:18 2002
@@ -29,16 +29,16 @@
 
 # Select the processor-specific files
 p-$(CONFIG_CPU_26)	+= proc-arm2,3.o
-p-$(CONFIG_CPU_ARM610)	+= proc-arm6,7.o
-p-$(CONFIG_CPU_ARM710)	+= proc-arm6,7.o
-p-$(CONFIG_CPU_ARM720T)	+= proc-arm720.o armv4t-late-abort.o
-p-$(CONFIG_CPU_ARM920T)	+= proc-arm920.o armv4t-early-abort.o
-p-$(CONFIG_CPU_ARM922T)	+= proc-arm922.o armv4t-early-abort.o
-p-$(CONFIG_CPU_ARM926T)	+= proc-arm926.o armv5ej-early-abort.o
-p-$(CONFIG_CPU_ARM1020)	+= proc-arm1020.o armv4t-early-abort.o
-p-$(CONFIG_CPU_SA110)	+= proc-sa110.o armv4-early-abort.o
-p-$(CONFIG_CPU_SA1100)	+= proc-sa110.o armv4-early-abort.o minicache.o
-p-$(CONFIG_CPU_XSCALE)	+= proc-xscale.o armv4t-early-abort.o minicache.o
+p-$(CONFIG_CPU_ARM610)	+= proc-arm6,7.o  tlb-v3.o   copypage-v3.o
+p-$(CONFIG_CPU_ARM710)	+= proc-arm6,7.o  tlb-v3.o   copypage-v3.o
+p-$(CONFIG_CPU_ARM720T)	+= proc-arm720.o  tlb-v4.o   copypage-v4.o   abort-lv4t.o
+p-$(CONFIG_CPU_ARM920T)	+= proc-arm920.o  tlb-v4wb.o copypage-v4.o   abort-ev4t.o
+p-$(CONFIG_CPU_ARM922T)	+= proc-arm922.o  tlb-v4wb.o copypage-v4.o   abort-ev4t.o
+p-$(CONFIG_CPU_ARM926T)	+= proc-arm926.o  tlb-v4wb.o copypage-v4.o   abort-ev5ej.o
+p-$(CONFIG_CPU_ARM1020)	+= proc-arm1020.o tlb-v4wb.o copypage-v4.o   abort-ev4t.o
+p-$(CONFIG_CPU_SA110)	+= proc-sa110.o   tlb-v4wb.o copypage-v4.o   copypage-v4mc.o abort-ev4.o   minicache.o
+p-$(CONFIG_CPU_SA1100)	+= proc-sa110.o   tlb-v4wb.o copypage-v4.o   copypage-v4mc.o abort-ev4.o   minicache.o
+p-$(CONFIG_CPU_XSCALE)	+= proc-xscale.o  tlb-v4wb.o copypage-v5te.o abort-ev4t.o  minicache.o
 
 obj-y		+= $(sort $(p-y))
 
diff -urN linux-2.5.6-pre1/arch/arm/mm/abort-ev4.S linux-2.5.6-pre2/arch/arm/mm/abort-ev4.S
--- linux-2.5.6-pre1/arch/arm/mm/abort-ev4.S	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mm/abort-ev4.S	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,29 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+/*
+ * Function: armv4_early_abort
+ *
+ * Params  : r2 = address of aborted instruction
+ *         : r3 = saved SPSR
+ *
+ * Returns : r0 = address of abort
+ *	   : r1 = FSR, bit 8 = write
+ *	   : r2-r8 = corrupted
+ *	   : r9 = preserved
+ *	   : sp = pointer to registers
+ *
+ * Purpose : obtain information about current aborted instruction.
+ * Note: we read user space.  This means we might cause a data
+ * abort here if the I-TLB and D-TLB aren't seeing the same
+ * picture.  Unfortunately, this does happen.  We live with it.
+ */
+	.align	5
+ENTRY(armv4_early_abort)
+	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+	ldr	r3, [r2]			@ read aborted ARM instruction
+	tst	r3, #1 << 20			@ L = 1 -> write?
+	orreq	r1, r1, #1 << 8			@ yes.
+	mov	pc, lr
+
+
diff -urN linux-2.5.6-pre1/arch/arm/mm/abort-ev4t.S linux-2.5.6-pre2/arch/arm/mm/abort-ev4t.S
--- linux-2.5.6-pre1/arch/arm/mm/abort-ev4t.S	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mm/abort-ev4t.S	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,31 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+/*
+ * Function: armv4t_early_abort
+ *
+ * Params  : r2 = address of aborted instruction
+ *         : r3 = saved SPSR
+ *
+ * Returns : r0 = address of abort
+ *	   : r1 = FSR, bit 8 = write
+ *	   : r2-r8 = corrupted
+ *	   : r9 = preserved
+ *	   : sp = pointer to registers
+ *
+ * Purpose : obtain information about current aborted instruction.
+ * Note: we read user space.  This means we might cause a data
+ * abort here if the I-TLB and D-TLB aren't seeing the same
+ * picture.  Unfortunately, this does happen.  We live with it.
+ */
+	.align	5
+ENTRY(armv4t_early_abort)
+	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+	tst	r3, #PSR_T_BIT
+	ldrneh	r3, [r2]			@ read aborted thumb instruction
+	ldreq	r3, [r2]			@ read aborted ARM instruction
+	bic	r1, r1, #1 << 8
+	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
+	tst	r3, #1 << 20			@ check write
+	orreq	r1, r1, #1 << 8
+	mov	pc, lr
diff -urN linux-2.5.6-pre1/arch/arm/mm/abort-ev5ej.S linux-2.5.6-pre2/arch/arm/mm/abort-ev5ej.S
--- linux-2.5.6-pre1/arch/arm/mm/abort-ev5ej.S	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mm/abort-ev5ej.S	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,35 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+/*
+ * Function: armv5ej_early_abort
+ *
+ * Params  : r2 = address of aborted instruction
+ *         : r3 = saved SPSR
+ *
+ * Returns : r0 = address of abort
+ *	   : r1 = FSR, bit 8 = write
+ *	   : r2-r8 = corrupted
+ *	   : r9 = preserved
+ *	   : sp = pointer to registers
+ *
+ * Purpose : obtain information about current aborted instruction.
+ * Note: we read user space.  This means we might cause a data
+ * abort here if the I-TLB and D-TLB aren't seeing the same
+ * picture.  Unfortunately, this does happen.  We live with it.
+ */
+	.align	5
+ENTRY(armv5ej_early_abort)
+	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+	tst	r3, #PSR_J_BIT
+	orrne	r1, r1, #1 << 8			@ always assume write
+	bne	1f
+	tst	r3, #PSR_T_BIT
+	ldrneh	r3, [r2]			@ read aborted thumb instruction
+	ldreq	r3, [r2]			@ read aborted ARM instruction
+	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
+	tst	r2, #1 << 20			@ L = 1 -> write
+	orreq	r1, r1, #1 << 8			@ yes.
+1:	mov	pc, lr
+
+
diff -urN linux-2.5.6-pre1/arch/arm/mm/abort-lv4t.S linux-2.5.6-pre2/arch/arm/mm/abort-lv4t.S
--- linux-2.5.6-pre1/arch/arm/mm/abort-lv4t.S	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mm/abort-lv4t.S	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,224 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+/*
+ * Function: armv4t_late_abort
+ *
+ * Params  : r2 = address of aborted instruction
+ *         : r3 = saved SPSR
+ *
+ * Returns : r0 = address of abort
+ *	   : r1 = FSR, bit 8 = writing
+ *	   : r2-r8 = corrupted
+ *	   : r9 = preserved
+ *	   : sp = pointer to registers
+ *
+ * Purpose : obtain information about current aborted instruction.
+ * Note: we read user space.  This means we might cause a data
+ * abort here if the I-TLB and D-TLB aren't seeing the same
+ * picture.  Unfortunately, this does happen.  We live with it.
+ */
+ENTRY(armv4t_late_abort)
+	tst	r3, #PSR_T_BIT			@ check for thumb mode
+	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+	ldreq	r8, [r2]			@ read arm instruction
+	bne	.data_thumb_abort
+	tst	r8, #1 << 20			@ L = 1 -> write?
+	orreq	r1, r1, #1 << 8			@ yes.
+	and	r7, r8, #15 << 24
+	add	pc, pc, r7, lsr #22		@ Now branch to the relevant processing routine
+	nop
+
+/* 0 */	b	.data_arm_lateldrhpost		@ ldrh	rd, [rn], #m/rm
+/* 1 */	b	.data_arm_lateldrhpre		@ ldrh	rd, [rn, #m/rm]
+/* 2 */	b	.data_unknown
+/* 3 */	b	.data_unknown
+/* 4 */	b	.data_arm_lateldrpostconst	@ ldr	rd, [rn], #m
+/* 5 */	b	.data_arm_lateldrpreconst	@ ldr	rd, [rn, #m] 
+/* 6 */	b	.data_arm_lateldrpostreg	@ ldr	rd, [rn], rm
+/* 7 */	b	.data_arm_lateldrprereg		@ ldr	rd, [rn, rm]
+/* 8 */	b	.data_arm_ldmstm		@ ldm*a	rn, <rlist>
+/* 9 */	b	.data_arm_ldmstm		@ ldm*b	rn, <rlist>
+/* a */	b	.data_unknown
+/* b */	b	.data_unknown
+/* c */	mov	pc, lr				@ ldc	rd, [rn], #m	@ Same as ldr	rd, [rn], #m
+/* d */	mov	pc, lr				@ ldc	rd, [rn, #m]
+/* e */	b	.data_unknown
+/* f */
+.data_unknown:	@ Part of jumptable
+	mov	r0, r2
+	mov	r1, r8
+	mov	r2, sp
+	bl	baddataabort
+	b	ret_from_exception
+
+.data_arm_ldmstm:
+	tst	r8, #1 << 21			@ check writeback bit
+	moveq	pc, lr				@ no writeback -> no fixup
+	mov	r7, #0x11
+	orr	r7, r7, #0x1100
+	and	r6, r8, r7
+	and	r2, r8, r7, lsl #1
+	add	r6, r6, r2, lsr #1
+	and	r2, r8, r7, lsl #2
+	add	r6, r6, r2, lsr #2
+	and	r2, r8, r7, lsl #3
+	add	r6, r6, r2, lsr #3
+	add	r6, r6, r6, lsr #8
+	add	r6, r6, r6, lsr #4
+	and	r6, r6, #15			@ r7 = no. of registers to transfer.
+	and	r5, r8, #15 << 16		@ Extract 'n' form instruction
+	ldr	r7, [sp, r5, lsr #14]		@ Get register 'Rn'
+	tst	r8, #1 << 23			@ Check U bit
+	subne	r7, r7, r6, lsl #2		@ Undo increment
+	addeq	r7, r7, r6, lsl #2		@ Undo decrement
+	str	r7, [sp, r5, lsr #14]		@ Put register 'Rn'
+	mov	pc, lr
+
+.data_arm_lateldrhpre:
+	tst	r8, #1 << 21			@ Check writeback bit
+	moveq	pc, lr				@ No writeback -> no fixup
+.data_arm_lateldrhpost:
+	and	r5, r8, #0x00f			@ get Rm / low nibble of immediate value
+	tst	r8, #1 << 22			@ if (immediate offset)
+	andne	r6, r8, #0xf00			@ { immediate high nibble
+	orrne	r6, r5, r6, lsr #4		@   combine nibbles } else
+	ldreq	r6, [sp, r5, lsl #2]		@ { load Rm value }
+.data_arm_apply_r6_and_rn:
+	and	r5, r8, #15 << 16		@ Extract 'n' from instruction
+	ldr	r7, [sp, r5, lsr #14]		@ Get register 'Rn'
+	tst	r8, #1 << 23			@ Check U bit
+	subne	r7, r7, r6			@ Undo incrmenet
+	addeq	r7, r7, r6			@ Undo decrement
+	str	r7, [sp, r5, lsr #14]		@ Put register 'Rn'
+	mov	pc, lr
+
+.data_arm_lateldrpreconst:
+	tst	r8, #1 << 21			@ check writeback bit
+	moveq	pc, lr				@ no writeback -> no fixup
+.data_arm_lateldrpostconst:
+	movs	r2, r8, lsl #20			@ Get offset
+	moveq	pc, lr				@ zero -> no fixup
+	and	r5, r8, #15 << 16		@ Extract 'n' from instruction
+	ldr	r7, [sp, r5, lsr #14]		@ Get register 'Rn'
+	tst	r8, #1 << 23			@ Check U bit
+	subne	r7, r7, r2, lsr #20		@ Undo increment
+	addeq	r7, r7, r2, lsr #20		@ Undo decrement
+	str	r7, [sp, r5, lsr #14]		@ Put register 'Rn'
+	mov	pc, lr
+
+.data_arm_lateldrprereg:
+	tst	r8, #1 << 21			@ check writeback bit
+	moveq	pc, lr				@ no writeback -> no fixup
+.data_arm_lateldrpostreg:
+	and	r7, r8, #15			@ Extract 'm' from instruction
+	ldr	r6, [sp, r7, lsl #2]		@ Get register 'Rm'
+	mov	r5, r8, lsr #7			@ get shift count
+	ands	r5, r5, #31
+	and	r7, r8, #0x70			@ get shift type
+	orreq	r7, r7, #8			@ shift count = 0
+	add	pc, pc, r7
+	nop
+
+	mov	r6, r6, lsl r5			@ 0: LSL #!0
+	b	.data_arm_apply_r6_and_rn
+	b	.data_arm_apply_r6_and_rn	@ 1: LSL #0
+	nop
+	b	.data_unknown			@ 2: MUL?
+	nop
+	b	.data_unknown			@ 3: MUL?
+	nop
+	mov	r6, r6, lsr r5			@ 4: LSR #!0
+	b	.data_arm_apply_r6_and_rn
+	mov	r6, r6, lsr #32			@ 5: LSR #32
+	b	.data_arm_apply_r6_and_rn
+	b	.data_unknown			@ 6: MUL?
+	nop
+	b	.data_unknown			@ 7: MUL?
+	nop
+	mov	r6, r6, asr r5			@ 8: ASR #!0
+	b	.data_arm_apply_r6_and_rn
+	mov	r6, r6, asr #32			@ 9: ASR #32
+	b	.data_arm_apply_r6_and_rn
+	b	.data_unknown			@ A: MUL?
+	nop
+	b	.data_unknown			@ B: MUL?
+	nop
+	mov	r6, r6, ror r5			@ C: ROR #!0
+	b	.data_arm_apply_r6_and_rn
+	mov	r6, r6, rrx			@ D: RRX
+	b	.data_arm_apply_r6_and_rn
+	b	.data_unknown			@ E: MUL?
+	nop
+	b	.data_unknown			@ F: MUL?
+
+.data_thumb_abort:
+	ldrh	r8, [r2]			@ read instruction
+	tst	r8, #1 << 11			@ L = 1 -> write?
+	orreq	r1, r1, #1 << 8			@ yes
+	and	r7, r8, #15 << 12
+	add	pc, pc, r7, lsr #10		@ lookup in table
+	nop
+
+/* 0 */	b	.data_unknown
+/* 1 */	b	.data_unknown
+/* 2 */	b	.data_unknown
+/* 3 */	b	.data_unknown
+/* 4 */	b	.data_unknown
+/* 5 */	b	.data_thumb_reg
+/* 6 */	mov	pc, lr
+/* 7 */	mov	pc, lr
+/* 8 */	mov	pc, lr
+/* 9 */	mov	pc, lr
+/* A */	b	.data_unknown
+/* B */	b	.data_thumb_pushpop
+/* C */	b	.data_thumb_ldmstm
+/* D */	b	.data_unknown
+/* E */	b	.data_unknown
+/* F */	b	.data_unknown
+
+.data_thumb_reg:
+	tst	r8, #1 << 9
+	moveq	pc, lr
+	tst	r8, #1 << 10			@ If 'S' (signed) bit is set
+	movne	r1, #0				@ it must be a load instr
+	mov	pc, lr
+
+.data_thumb_pushpop:
+	tst	r8, #1 << 10
+	beq	.data_unknown
+	mov	r7, #0x11
+	and	r6, r8, r7
+	and	r2, r8, r7, lsl #1
+	add	r6, r6, r2, lsr #1
+	and	r2, r8, r7, lsl #2
+	add	r6, r6, r2, lsr #2
+	and	r2, r8, r7, lsl #3
+	add	r6, r6, r2, lsr #3
+	add	r6, r6, r6, lsr #4
+	and	r2, r8, #0x0100			@ catch 'R' bit for push/pop
+	add	r6, r6, r2, lsr #8
+	and	r6, r6, #15			@ number of regs to transfer
+	ldr	r7, [sp, #13 << 2]
+	tst	r8, #1 << 11
+	addne	r7, r7, r6, lsl #2		@ increment SP if PUSH
+	subeq	r7, r7, r6, lsr #2		@ decrement SP if POP
+	str	r7, [sp, #13 << 2]
+	mov	pc, lr
+
+.data_thumb_ldmstm:
+	mov	r7, #0x11
+	and	r6, r8, r7
+	and	r2, r8, r7, lsl #1
+	add	r6, r6, r2, lsr #1
+	and	r2, r8, r7, lsl #2
+	add	r6, r6, r2, lsr #2
+	and	r2, r8, r7, lsl #3
+	add	r6, r6, r2, lsr #3
+	add	r6, r6, r6, lsr #4
+	and	r6, r6, #15			@ number of regs to transfer
+	and	r5, r8, #7 << 8
+	ldr	r7, [sp, r5, lsr #6]
+	sub	r7, r7, r6, lsr #2		@ always decrement
+	str	r7, [sp, r5, lsr #6]
+	mov	pc, lr
diff -urN linux-2.5.6-pre1/arch/arm/mm/armv4-early-abort.S linux-2.5.6-pre2/arch/arm/mm/armv4-early-abort.S
--- linux-2.5.6-pre1/arch/arm/mm/armv4-early-abort.S	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/arch/arm/mm/armv4-early-abort.S	Wed Dec 31 16:00:00 1969
@@ -1,29 +0,0 @@
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-/*
- * Function: armv4_early_abort
- *
- * Params  : r2 = address of aborted instruction
- *         : r3 = saved SPSR
- *
- * Returns : r0 = address of abort
- *	   : r1 = FSR, bit 8 = write
- *	   : r2-r8 = corrupted
- *	   : r9 = preserved
- *	   : sp = pointer to registers
- *
- * Purpose : obtain information about current aborted instruction.
- * Note: we read user space.  This means we might cause a data
- * abort here if the I-TLB and D-TLB aren't seeing the same
- * picture.  Unfortunately, this does happen.  We live with it.
- */
-	.align	5
-ENTRY(armv4_early_abort)
-	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
-	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
-	ldr	r3, [r2]			@ read aborted ARM instruction
-	tst	r3, #1 << 20			@ L = 1 -> write?
-	orreq	r1, r1, #1 << 8			@ yes.
-	mov	pc, lr
-
-
diff -urN linux-2.5.6-pre1/arch/arm/mm/armv4t-early-abort.S linux-2.5.6-pre2/arch/arm/mm/armv4t-early-abort.S
--- linux-2.5.6-pre1/arch/arm/mm/armv4t-early-abort.S	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/arch/arm/mm/armv4t-early-abort.S	Wed Dec 31 16:00:00 1969
@@ -1,31 +0,0 @@
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-/*
- * Function: armv4t_early_abort
- *
- * Params  : r2 = address of aborted instruction
- *         : r3 = saved SPSR
- *
- * Returns : r0 = address of abort
- *	   : r1 = FSR, bit 8 = write
- *	   : r2-r8 = corrupted
- *	   : r9 = preserved
- *	   : sp = pointer to registers
- *
- * Purpose : obtain information about current aborted instruction.
- * Note: we read user space.  This means we might cause a data
- * abort here if the I-TLB and D-TLB aren't seeing the same
- * picture.  Unfortunately, this does happen.  We live with it.
- */
-	.align	5
-ENTRY(armv4t_early_abort)
-	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
-	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
-	tst	r3, #PSR_T_BIT
-	ldrneh	r3, [r2]			@ read aborted thumb instruction
-	ldreq	r3, [r2]			@ read aborted ARM instruction
-	bic	r1, r1, #1 << 8
-	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
-	tst	r3, #1 << 20			@ check write
-	orreq	r1, r1, #1 << 8
-	mov	pc, lr
diff -urN linux-2.5.6-pre1/arch/arm/mm/armv4t-late-abort.S linux-2.5.6-pre2/arch/arm/mm/armv4t-late-abort.S
--- linux-2.5.6-pre1/arch/arm/mm/armv4t-late-abort.S	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre2/arch/arm/mm/armv4t-late-abort.S	Wed Dec 31 16:00:00 1969
@@ -1,224 +0,0 @@
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-/*
- * Function: armv4t_late_abort
- *
- * Params  : r2 = address of aborted instruction
- *         : r3 = saved SPSR
- *
- * Returns : r0 = address of abort
- *	   : r1 = FSR, bit 8 = writing
- *	   : r2-r8 = corrupted
- *	   : r9 = preserved
- *	   : sp = pointer to registers
- *
- * Purpose : obtain information about current aborted instruction.
- * Note: we read user space.  This means we might cause a data
- * abort here if the I-TLB and D-TLB aren't seeing the same
- * picture.  Unfortunately, this does happen.  We live with it.
- */
-ENTRY(armv4t_late_abort)
-	tst	r3, #PSR_T_BIT			@ check for thumb mode
-	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
-	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
-	ldreq	r8, [r2]			@ read arm instruction
-	bne	.data_thumb_abort
-	tst	r8, #1 << 20			@ L = 1 -> write?
-	orreq	r1, r1, #1 << 8			@ yes.
-	and	r7, r8, #15 << 24
-	add	pc, pc, r7, lsr #22		@ Now branch to the relevant processing routine
-	nop
-
-/* 0 */	b	.data_arm_lateldrhpost		@ ldrh	rd, [rn], #m/rm
-/* 1 */	b	.data_arm_lateldrhpre		@ ldrh	rd, [rn, #m/rm]
-/* 2 */	b	.data_unknown
-/* 3 */	b	.data_unknown
-/* 4 */	b	.data_arm_lateldrpostconst	@ ldr	rd, [rn], #m
-/* 5 */	b	.data_arm_lateldrpreconst	@ ldr	rd, [rn, #m] 
-/* 6 */	b	.data_arm_lateldrpostreg	@ ldr	rd, [rn], rm
-/* 7 */	b	.data_arm_lateldrprereg		@ ldr	rd, [rn, rm]
-/* 8 */	b	.data_arm_ldmstm		@ ldm*a	rn, <rlist>
-/* 9 */	b	.data_arm_ldmstm		@ ldm*b	rn, <rlist>
-/* a */	b	.data_unknown
-/* b */	b	.data_unknown
-/* c */	mov	pc, lr				@ ldc	rd, [rn], #m	@ Same as ldr	rd, [rn], #m
-/* d */	mov	pc, lr				@ ldc	rd, [rn, #m]
-/* e */	b	.data_unknown
-/* f */
-.data_unknown:	@ Part of jumptable
-	mov	r0, r2
-	mov	r1, r8
-	mov	r2, sp
-	bl	baddataabort
-	b	ret_from_exception
-
-.data_arm_ldmstm:
-	tst	r8, #1 << 21			@ check writeback bit
-	moveq	pc, lr				@ no writeback -> no fixup
-	mov	r7, #0x11
-	orr	r7, r7, #0x1100
-	and	r6, r8, r7
-	and	r2, r8, r7, lsl #1
-	add	r6, r6, r2, lsr #1
-	and	r2, r8, r7, lsl #2
-	add	r6, r6, r2, lsr #2
-	and	r2, r8, r7, lsl #3
-	add	r6, r6, r2, lsr #3
-	add	r6, r6, r6, lsr #8
-	add	r6, r6, r6, lsr #4
-	and	r6, r6, #15			@ r7 = no. of registers to transfer.
-	and	r5, r8, #15 << 16		@ Extract 'n' form instruction
-	ldr	r7, [sp, r5, lsr #14]		@ Get register 'Rn'
-	tst	r8, #1 << 23			@ Check U bit
-	subne	r7, r7, r6, lsl #2		@ Undo increment
-	addeq	r7, r7, r6, lsl #2		@ Undo decrement
-	str	r7, [sp, r5, lsr #14]		@ Put register 'Rn'
-	mov	pc, lr
-
-.data_arm_lateldrhpre:
-	tst	r8, #1 << 21			@ Check writeback bit
-	moveq	pc, lr				@ No writeback -> no fixup
-.data_arm_lateldrhpost:
-	and	r5, r8, #0x00f			@ get Rm / low nibble of immediate value
-	tst	r8, #1 << 22			@ if (immediate offset)
-	andne	r6, r8, #0xf00			@ { immediate high nibble
-	orrne	r6, r5, r6, lsr #4		@   combine nibbles } else
-	ldreq	r6, [sp, r5, lsl #2]		@ { load Rm value }
-.data_arm_apply_r6_and_rn:
-	and	r5, r8, #15 << 16		@ Extract 'n' from instruction
-	ldr	r7, [sp, r5, lsr #14]		@ Get register 'Rn'
-	tst	r8, #1 << 23			@ Check U bit
-	subne	r7, r7, r6			@ Undo incrmenet
-	addeq	r7, r7, r6			@ Undo decrement
-	str	r7, [sp, r5, lsr #14]		@ Put register 'Rn'
-	mov	pc, lr
-
-.data_arm_lateldrpreconst:
-	tst	r8, #1 << 21			@ check writeback bit
-	moveq	pc, lr				@ no writeback -> no fixup
-.data_arm_lateldrpostconst:
-	movs	r2, r8, lsl #20			@ Get offset
-	moveq	pc, lr				@ zero -> no fixup
-	and	r5, r8, #15 << 16		@ Extract 'n' from instruction
-	ldr	r7, [sp, r5, lsr #14]		@ Get register 'Rn'
-	tst	r8, #1 << 23			@ Check U bit
-	subne	r7, r7, r2, lsr #20		@ Undo increment
-	addeq	r7, r7, r2, lsr #20		@ Undo decrement
-	str	r7, [sp, r5, lsr #14]		@ Put register 'Rn'
-	mov	pc, lr
-
-.data_arm_lateldrprereg:
-	tst	r8, #1 << 21			@ check writeback bit
-	moveq	pc, lr				@ no writeback -> no fixup
-.data_arm_lateldrpostreg:
-	and	r7, r8, #15			@ Extract 'm' from instruction
-	ldr	r6, [sp, r7, lsl #2]		@ Get register 'Rm'
-	mov	r5, r8, lsr #7			@ get shift count
-	ands	r5, r5, #31
-	and	r7, r8, #0x70			@ get shift type
-	orreq	r7, r7, #8			@ shift count = 0
-	add	pc, pc, r7
-	nop
-
-	mov	r6, r6, lsl r5			@ 0: LSL #!0
-	b	.data_arm_apply_r6_and_rn
-	b	.data_arm_apply_r6_and_rn	@ 1: LSL #0
-	nop
-	b	.data_unknown			@ 2: MUL?
-	nop
-	b	.data_unknown			@ 3: MUL?
-	nop
-	mov	r6, r6, lsr r5			@ 4: LSR #!0
-	b	.data_arm_apply_r6_and_rn
-	mov	r6, r6, lsr #32			@ 5: LSR #32
-	b	.data_arm_apply_r6_and_rn
-	b	.data_unknown			@ 6: MUL?
-	nop
-	b	.data_unknown			@ 7: MUL?
-	nop
-	mov	r6, r6, asr r5			@ 8: ASR #!0
-	b	.data_arm_apply_r6_and_rn
-	mov	r6, r6, asr #32			@ 9: ASR #32
-	b	.data_arm_apply_r6_and_rn
-	b	.data_unknown			@ A: MUL?
-	nop
-	b	.data_unknown			@ B: MUL?
-	nop
-	mov	r6, r6, ror r5			@ C: ROR #!0
-	b	.data_arm_apply_r6_and_rn
-	mov	r6, r6, rrx			@ D: RRX
-	b	.data_arm_apply_r6_and_rn
-	b	.data_unknown			@ E: MUL?
-	nop
-	b	.data_unknown			@ F: MUL?
-
-.data_thumb_abort:
-	ldrh	r8, [r2]			@ read instruction
-	tst	r8, #1 << 11			@ L = 1 -> write?
-	orreq	r1, r1, #1 << 8			@ yes
-	and	r7, r8, #15 << 12
-	add	pc, pc, r7, lsr #10		@ lookup in table
-	nop
-
-/* 0 */	b	.data_unknown
-/* 1 */	b	.data_unknown
-/* 2 */	b	.data_unknown
-/* 3 */	b	.data_unknown
-/* 4 */	b	.data_unknown
-/* 5 */	b	.data_thumb_reg
-/* 6 */	mov	pc, lr
-/* 7 */	mov	pc, lr
-/* 8 */	mov	pc, lr
-/* 9 */	mov	pc, lr
-/* A */	b	.data_unknown
-/* B */	b	.data_thumb_pushpop
-/* C */	b	.data_thumb_ldmstm
-/* D */	b	.data_unknown
-/* E */	b	.data_unknown
-/* F */	b	.data_unknown
-
-.data_thumb_reg:
-	tst	r8, #1 << 9
-	moveq	pc, lr
-	tst	r8, #1 << 10			@ If 'S' (signed) bit is set
-	movne	r1, #0				@ it must be a load instr
-	mov	pc, lr
-
-.data_thumb_pushpop:
-	tst	r8, #1 << 10
-	beq	.data_unknown
-	mov	r7, #0x11
-	and	r6, r8, r7
-	and	r2, r8, r7, lsl #1
-	add	r6, r6, r2, lsr #1
-	and	r2, r8, r7, lsl #2
-	add	r6, r6, r2, lsr #2
-	and	r2, r8, r7, lsl #3
-	add	r6, r6, r2, lsr #3
-	add	r6, r6, r6, lsr #4
-	and	r2, r8, #0x0100			@ catch 'R' bit for push/pop
-	add	r6, r6, r2, lsr #8
-	and	r6, r6, #15			@ number of regs to transfer
-	ldr	r7, [sp, #13 << 2]
-	tst	r8, #1 << 11
-	addne	r7, r7, r6, lsl #2		@ increment SP if PUSH
-	subeq	r7, r7, r6, lsr #2		@ decrement SP if POP
-	str	r7, [sp, #13 << 2]
-	mov	pc, lr
-
-.data_thumb_ldmstm:
-	mov	r7, #0x11
-	and	r6, r8, r7
-	and	r2, r8, r7, lsl #1
-	add	r6, r6, r2, lsr #1
-	and	r2, r8, r7, lsl #2
-	add	r6, r6, r2, lsr #2
-	and	r2, r8, r7, lsl #3
-	add	r6, r6, r2, lsr #3
-	add	r6, r6, r6, lsr #4
-	and	r6, r6, #15			@ number of regs to transfer
-	and	r5, r8, #7 << 8
-	ldr	r7, [sp, r5, lsr #6]
-	sub	r7, r7, r6, lsr #2		@ always decrement
-	str	r7, [sp, r5, lsr #6]
-	mov	pc, lr
diff -urN linux-2.5.6-pre1/arch/arm/mm/armv5ej-early-abort.S linux-2.5.6-pre2/arch/arm/mm/armv5ej-early-abort.S
--- linux-2.5.6-pre1/arch/arm/mm/armv5ej-early-abort.S	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/arch/arm/mm/armv5ej-early-abort.S	Wed Dec 31 16:00:00 1969
@@ -1,35 +0,0 @@
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-/*
- * Function: armv5ej_early_abort
- *
- * Params  : r2 = address of aborted instruction
- *         : r3 = saved SPSR
- *
- * Returns : r0 = address of abort
- *	   : r1 = FSR, bit 8 = write
- *	   : r2-r8 = corrupted
- *	   : r9 = preserved
- *	   : sp = pointer to registers
- *
- * Purpose : obtain information about current aborted instruction.
- * Note: we read user space.  This means we might cause a data
- * abort here if the I-TLB and D-TLB aren't seeing the same
- * picture.  Unfortunately, this does happen.  We live with it.
- */
-	.align	5
-ENTRY(armv5ej_early_abort)
-	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
-	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
-	tst	r3, #PSR_J_BIT
-	orrne	r1, r1, #1 << 8			@ always assume write
-	bne	1f
-	tst	r3, #PSR_T_BIT
-	ldrneh	r3, [r2]			@ read aborted thumb instruction
-	ldreq	r3, [r2]			@ read aborted ARM instruction
-	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
-	tst	r2, #1 << 20			@ L = 1 -> write
-	orreq	r1, r1, #1 << 8			@ yes.
-1:	mov	pc, lr
-
-
diff -urN linux-2.5.6-pre1/arch/arm/mm/copypage-v3.S linux-2.5.6-pre2/arch/arm/mm/copypage-v3.S
--- linux-2.5.6-pre1/arch/arm/mm/copypage-v3.S	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mm/copypage-v3.S	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,59 @@
+/*
+ *  linux/arch/arm/lib/copypage.S
+ *
+ *  Copyright (C) 1995-1999 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.
+ *
+ *  ASM optimised string functions
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/constants.h>
+
+		.text
+		.align	5
+/*
+ * ARMv3 optimised copy_user_page
+ *
+ * FIXME: do we need to handle cache stuff...
+ */
+ENTRY(armv3_copy_user_page)
+	stmfd	sp!, {r4, lr}			@	2
+	mov	r2, #PAGE_SZ/64			@	1
+	ldmia	r1!, {r3, r4, ip, lr}		@	4+1
+1:	stmia	r0!, {r3, r4, ip, lr}		@	4
+	ldmia	r1!, {r3, r4, ip, lr}		@	4+1
+	stmia	r0!, {r3, r4, ip, lr}		@	4
+	ldmia	r1!, {r3, r4, ip, lr}		@	4+1
+	stmia	r0!, {r3, r4, ip, lr}		@	4
+	ldmia	r1!, {r3, r4, ip, lr}		@	4
+	subs	r2, r2, #1			@	1
+	stmia	r0!, {r3, r4, ip, lr}		@	4
+	ldmneia	r1!, {r3, r4, ip, lr}		@	4
+	bne	1b				@	1
+	LOADREGS(fd, sp!, {r4, pc})		@	3
+
+	.align	5
+/*
+ * ARMv3 optimised clear_user_page
+ *
+ * FIXME: do we need to handle cache stuff...
+ */
+ENTRY(armv3_clear_user_page)
+	str	lr, [sp, #-4]!
+	mov	r1, #PAGE_SZ/64			@ 1
+	mov	r2, #0				@ 1
+	mov	r3, #0				@ 1
+	mov	ip, #0				@ 1
+	mov	lr, #0				@ 1
+1:	stmia	r0!, {r2, r3, ip, lr}		@ 4
+	stmia	r0!, {r2, r3, ip, lr}		@ 4
+	stmia	r0!, {r2, r3, ip, lr}		@ 4
+	stmia	r0!, {r2, r3, ip, lr}		@ 4
+	subs	r1, r1, #1			@ 1
+	bne	1b				@ 1
+	ldr	pc, [sp], #4
+
diff -urN linux-2.5.6-pre1/arch/arm/mm/copypage-v4.S linux-2.5.6-pre2/arch/arm/mm/copypage-v4.S
--- linux-2.5.6-pre1/arch/arm/mm/copypage-v4.S	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mm/copypage-v4.S	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,70 @@
+/*
+ *  linux/arch/arm/lib/copypage.S
+ *
+ *  Copyright (C) 1995-1999 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.
+ *
+ *  ASM optimised string functions
+ */
+#include <linux/linkage.h>
+#include <asm/constants.h>
+
+	.text
+	.align	5
+/*
+ * ARMv4 optimised copy_user_page
+ *
+ * We flush the destination cache lines just before we write the data into the
+ * corresponding address.  Since the Dcache is read-allocate, this removes the
+ * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
+ * and merged as appropriate.
+ *
+ * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
+ * instruction.  If your processor does not supply this, you have to write your
+ * own copy_user_page that does the right thing.
+ */
+ENTRY(armv4_copy_user_page)
+	stmfd	sp!, {r4, lr}			@ 2
+	mov	r2, #PAGE_SZ/64			@ 1
+	ldmia	r1!, {r3, r4, ip, lr}		@ 4
+1:	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line
+	stmia	r0!, {r3, r4, ip, lr}		@ 4
+	ldmia	r1!, {r3, r4, ip, lr}		@ 4+1
+	stmia	r0!, {r3, r4, ip, lr}		@ 4
+	ldmia	r1!, {r3, r4, ip, lr}		@ 4
+	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line
+	stmia	r0!, {r3, r4, ip, lr}		@ 4
+	ldmia	r1!, {r3, r4, ip, lr}		@ 4
+	subs	r2, r2, #1			@ 1
+	stmia	r0!, {r3, r4, ip, lr}		@ 4
+	ldmneia	r1!, {r3, r4, ip, lr}		@ 4
+	bne	1b				@ 1
+	mcr	p15, 0, r1, c7, c10, 4		@ 1   drain WB
+	ldmfd	 sp!, {r4, pc}			@ 3
+
+	.align	5
+/*
+ * ARMv4 optimised clear_user_page
+ *
+ * Same story as above.
+ */
+ENTRY(armv4_clear_user_page)
+	str	lr, [sp, #-4]!
+	mov	r1, #PAGE_SZ/64			@ 1
+	mov	r2, #0				@ 1
+	mov	r3, #0				@ 1
+	mov	ip, #0				@ 1
+	mov	lr, #0				@ 1
+1:	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line
+	stmia	r0!, {r2, r3, ip, lr}		@ 4
+	stmia	r0!, {r2, r3, ip, lr}		@ 4
+	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line
+	stmia	r0!, {r2, r3, ip, lr}		@ 4
+	stmia	r0!, {r2, r3, ip, lr}		@ 4
+	subs	r1, r1, #1			@ 1
+	bne	1b				@ 1
+	mcr	p15, 0, r1, c7, c10, 4		@ 1   drain WB
+	ldr	pc, [sp], #4
diff -urN linux-2.5.6-pre1/arch/arm/mm/copypage-v4mc.S linux-2.5.6-pre2/arch/arm/mm/copypage-v4mc.S
--- linux-2.5.6-pre1/arch/arm/mm/copypage-v4mc.S	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mm/copypage-v4mc.S	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,71 @@
+/*
+ *  linux/arch/arm/lib/copy_page-armv4mc.S
+ *
+ *  Copyright (C) 1995-2001 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  ASM optimised string functions
+ */
+#include <linux/linkage.h>
+#include <asm/constants.h>
+
+	.text
+	.align	5
+/*
+ * ARMv4 mini-dcache optimised copy_user_page
+ *
+ * We flush the destination cache lines just before we write the data into the
+ * corresponding address.  Since the Dcache is read-allocate, this removes the
+ * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
+ * and merged as appropriate.
+ *
+ * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
+ * instruction.  If your processor does not supply this, you have to write your
+ * own copy_user_page that does the right thing.
+ */
+ENTRY(armv4_mc_copy_user_page)
+	stmfd	sp!, {r4, lr}			@ 2
+	mov	r4, r0
+	mov	r0, r1
+	bl	map_page_minicache
+	mov	r1, #PAGE_SZ/64			@ 1
+	ldmia	r0!, {r2, r3, ip, lr}		@ 4
+1:	mcr	p15, 0, r4, c7, c6, 1		@ 1   invalidate D line
+	stmia	r4!, {r2, r3, ip, lr}		@ 4
+	ldmia	r0!, {r2, r3, ip, lr}		@ 4+1
+	stmia	r4!, {r2, r3, ip, lr}		@ 4
+	ldmia	r0!, {r2, r3, ip, lr}		@ 4
+	mcr	p15, 0, r4, c7, c6, 1		@ 1   invalidate D line
+	stmia	r4!, {r2, r3, ip, lr}		@ 4
+	ldmia	r0!, {r2, r3, ip, lr}		@ 4
+	subs	r1, r1, #1			@ 1
+	stmia	r4!, {r2, r3, ip, lr}		@ 4
+	ldmneia	r0!, {r2, r3, ip, lr}		@ 4
+	bne	1b				@ 1
+	ldmfd	sp!, {r4, pc}			@ 3
+
+	.align	5
+/*
+ * ARMv4 optimised clear_user_page
+ *
+ * Same story as above.
+ */
+ENTRY(armv4_mc_clear_user_page)
+	str	lr, [sp, #-4]!
+	mov	r1, #PAGE_SZ/64			@ 1
+	mov	r2, #0				@ 1
+	mov	r3, #0				@ 1
+	mov	ip, #0				@ 1
+	mov	lr, #0				@ 1
+1:	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line
+	stmia	r0!, {r2, r3, ip, lr}		@ 4
+	stmia	r0!, {r2, r3, ip, lr}		@ 4
+	mcr	p15, 0, r0, c7, c6, 1		@ 1   invalidate D line
+	stmia	r0!, {r2, r3, ip, lr}		@ 4
+	stmia	r0!, {r2, r3, ip, lr}		@ 4
+	subs	r1, r1, #1			@ 1
+	bne	1b				@ 1
+	ldr	pc, [sp], #4
diff -urN linux-2.5.6-pre1/arch/arm/mm/copypage-v5te.S linux-2.5.6-pre2/arch/arm/mm/copypage-v5te.S
--- linux-2.5.6-pre1/arch/arm/mm/copypage-v5te.S	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mm/copypage-v5te.S	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,79 @@
+/*
+ *  linux/arch/arm/lib/copypage-armv5te.S
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/linkage.h>
+#include <asm/constants.h>
+
+/*
+ * General note:
+ *  We don't really want write-allocate cache behaviour for these functions
+ *  since that will just eat through 8K of the cache.
+ */
+
+	.text
+	.align	5
+/*
+ * ARMv5TE optimised copy_user_page
+ *  r0 = destination
+ *  r1 = source
+ *  r2 = virtual user address of ultimate destination page
+ *
+ * The source page may have some clean entries in the cache already, but we
+ * can safely ignore them - break_cow() will flush them out of the cache
+ * if we eventually end up using our copied page.
+ *
+ * What we could do is use the mini-cache to buffer reads from the source
+ * page.  We rely on the mini-cache being smaller than one page, so we'll
+ * cycle through the complete cache anyway.
+ */
+ENTRY(armv5te_copy_user_page)
+	stmfd	sp!, {r4, r5, lr}
+	mov	r5, r0
+	mov	r0, r1
+	bl	map_page_minicache
+	mov	r1, r5
+	mov	lr, #PAGE_SZ/32
+
+1:	mov	ip, r1
+	ldrd	r2, [r0], #8
+	ldrd	r4, [r0], #8
+	strd	r2, [r1], #8
+	ldrd	r2, [r0], #8
+	strd	r4, [r1], #8
+	ldrd	r4, [r0], #8
+	strd	r2, [r1], #8
+	strd	r4, [r1], #8
+	mcr	p15, 0, ip, c7, c10, 1		@ clean D line
+	mcr	p15, 0, ip, c7, c6, 1		@ invalidate D line
+	subs	lr, lr, #1
+	bne	1b
+
+	ldmfd	sp!, {r4, r5, pc}
+
+	.align	5
+/*
+ * ARMv5TE optimised clear_user_page
+ *  r0 = destination
+ *  r1 = virtual user address of ultimate destination page
+ */
+ENTRY(armv5te_clear_user_page)
+	str	lr, [sp, #-4]!
+	mov	r1, #PAGE_SZ/32
+	mov	r2, #0
+	mov	r3, #0
+1:	mov	ip, r0
+	strd	r2, [r0], #8
+	strd	r2, [r0], #8
+	strd	r2, [r0], #8
+	strd	r2, [r0], #8
+	mcr	p15, 0, ip, c7, c10, 1		@ clean D line
+	mcr	p15, 0, ip, c7, c6, 1		@ invalidate D line
+	subs	r1, r1, #1
+	bne	1b
+	ldr	pc, [sp], #4
diff -urN linux-2.5.6-pre1/arch/arm/mm/fault-armv.c linux-2.5.6-pre2/arch/arm/mm/fault-armv.c
--- linux-2.5.6-pre1/arch/arm/mm/fault-armv.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/arch/arm/mm/fault-armv.c	Thu Feb 28 13:34:18 2002
@@ -116,7 +116,7 @@
 	if (!inf->fn(addr, fsr, regs))
 		return;
 
-	printk(KERN_ALERT "Unhandled fault: %s (%X) at 0x%08lx\n",
+	printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
 		inf->name, fsr, addr);
 	force_sig(inf->sig, current);
 	show_pte(current->mm, addr);
@@ -177,38 +177,13 @@
 	return;
 }
 
-/*
- * Take care of architecture specific things when placing a new PTE into
- * a page table, or changing an existing PTE.  Basically, there are two
- * things that we need to take care of:
- *
- *  1. If PG_dcache_dirty is set for the page, we need to ensure
- *     that any cache entries for the kernels virtual memory
- *     range are written back to the page.
- *  2. If we have multiple shared mappings of the same space in
- *     an object, we need to deal with the cache aliasing issues.
- *
- * Note that the page_table_lock will be held.
- */
-void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
+static void
+make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page)
 {
-	struct page *page = pte_page(pte);
 	struct vm_area_struct *mpnt;
-	struct mm_struct *mm;
-	unsigned long pgoff;
-	int aliases;
-
-	if (!VALID_PAGE(page) || !page->mapping)
-		return;
-
-	if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) {
-		unsigned long kvirt = (unsigned long)page_address(page);
-		cpu_cache_clean_invalidate_range(kvirt, kvirt + PAGE_SIZE, 0);
-	}
-
-	mm = vma->vm_mm;
-	pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
-	aliases = 0;
+	struct mm_struct *mm = vma->vm_mm;
+	unsigned long pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
+	int aliases = 0;
 
 	/*
 	 * If we have any shared mappings that are in the same mm
@@ -246,3 +221,30 @@
 	if (aliases)
 		adjust_pte(vma, addr);
 }
+
+/*
+ * Take care of architecture specific things when placing a new PTE into
+ * a page table, or changing an existing PTE.  Basically, there are two
+ * things that we need to take care of:
+ *
+ *  1. If PG_dcache_dirty is set for the page, we need to ensure
+ *     that any cache entries for the kernels virtual memory
+ *     range are written back to the page.
+ *  2. If we have multiple shared mappings of the same space in
+ *     an object, we need to deal with the cache aliasing issues.
+ *
+ * Note that the page_table_lock will be held.
+ */
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
+{
+	struct page *page = pte_page(pte);
+
+	if (VALID_PAGE(page) && page->mapping) {
+		if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) {
+			unsigned long kvirt = (unsigned long)page_address(page);
+			cpu_cache_clean_invalidate_range(kvirt, kvirt + PAGE_SIZE, 0);
+		}
+
+		make_coherent(vma, addr, page);
+	}
+}
diff -urN linux-2.5.6-pre1/arch/arm/mm/fault-common.c linux-2.5.6-pre2/arch/arm/mm/fault-common.c
--- linux-2.5.6-pre1/arch/arm/mm/fault-common.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/arch/arm/mm/fault-common.c	Thu Feb 28 13:34:18 2002
@@ -138,9 +138,10 @@
 	struct siginfo si;
 
 #ifdef CONFIG_DEBUG_USER
-	printk(KERN_DEBUG "%s: unhandled page fault at pc=0x%08lx, "
-	       "lr=0x%08lx (bad address=0x%08lx, code %d)\n",
-	       tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, error_code);
+	printk(KERN_DEBUG "%s: unhandled page fault at 0x%08lx, code 0x%03x\n",
+	       tsk->comm, addr, error_code);
+	show_pte(tsk->mm, addr);
+	show_regs(regs);
 #endif
 
 	tsk->thread.address = addr;
@@ -224,8 +225,7 @@
 	 * If we are out of memory for pid1,
 	 * sleep for a while and retry
 	 */
-	tsk->policy |= SCHED_YIELD;
-	schedule();
+	yield();
 	goto survive;
 
 check_stack:
diff -urN linux-2.5.6-pre1/arch/arm/mm/minicache.c linux-2.5.6-pre2/arch/arm/mm/minicache.c
--- linux-2.5.6-pre1/arch/arm/mm/minicache.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/arch/arm/mm/minicache.c	Thu Feb 28 13:34:18 2002
@@ -16,9 +16,14 @@
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <asm/page.h>
+#include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 
-#define minicache_address (0xffff2000)
+/*
+ * 0xffff8000 to 0xffffffff is reserved for any ARM architecture
+ * specific hacks for copying pages efficiently.
+ */
+#define minicache_address (0xffff8000)
 #define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
 				  L_PTE_CACHEABLE)
 
@@ -39,7 +44,7 @@
 unsigned long map_page_minicache(unsigned long virt)
 {
 	set_pte(minicache_pte, mk_pte_phys(__pa(virt), minicache_pgprot));
-	cpu_tlb_invalidate_page(minicache_address, 0);
+	flush_kern_tlb_page(minicache_address);
 
 	return minicache_address;
 }
diff -urN linux-2.5.6-pre1/arch/arm/mm/proc-arm1020.S linux-2.5.6-pre2/arch/arm/mm/proc-arm1020.S
--- linux-2.5.6-pre1/arch/arm/mm/proc-arm1020.S	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/arch/arm/mm/proc-arm1020.S	Thu Feb 28 13:34:18 2002
@@ -420,71 +420,6 @@
 #endif
 	mov	pc, lr
 
-/* ================================== TLB ================================= */
-
-/*
- * cpu_arm1020_tlb_invalidate_all()
- *
- * Invalidate all TLB entries
- */
-	.align	5
-ENTRY(cpu_arm1020_tlb_invalidate_all)
-	mov	r0, #0
-	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
-	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I & D tlbs
-#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION
-	mov	r0, r0
-	mov	r0, r0
-#endif
-	mov	pc, lr
-
-/*
- * cpu_arm1020_tlb_invalidate_range(start, end)
- *
- * invalidate TLB entries covering the specified range
- *
- * start: range start address
- * end:   range end address
- */
-	.align	5
-ENTRY(cpu_arm1020_tlb_invalidate_range)
-	mov	r3, #0
-	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
-1:	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	mcr	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
-	add	r0, r0, #PAGESIZE
-#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION
-	mov	r0, r0
-#endif
-	cmp	r0, r1
-	blt	1b
-	mov	pc, lr
-
-/*
- * cpu_arm1020_tlb_invalidate_page(page, flags)
- *
- * invalidate the TLB entries for the specified page.
- *
- * page:  page to invalidate
- * flags: non-zero if we include the I TLB
- */
-	.align	5
-ENTRY(cpu_arm1020_tlb_invalidate_page)
-	mov	r3, #0
-	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
-#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION
-	mov	r0, r0
-	mov	r0, r0
-#endif
-	teq	r1, #0
-	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	mcrne	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
-#ifdef CONFIG_CPU_ARM1020_BRANCH_PREDICTION
-	mov	r0, r0
-	mov	r0, r0
-#endif
-	mov	pc, lr
-
 /* =============================== PageTable ============================== */
 
 /*
@@ -695,11 +630,6 @@
 	.word	cpu_arm1020_icache_invalidate_range
 	.word	cpu_arm1020_icache_invalidate_page
 
-	/* tlb */
-	.word	cpu_arm1020_tlb_invalidate_all
-	.word	cpu_arm1020_tlb_invalidate_range
-	.word	cpu_arm1020_tlb_invalidate_page
-
 	/* pgtable */
 	.word	cpu_arm1020_set_pgd
 	.word	cpu_arm1020_set_pmd
@@ -741,4 +671,5 @@
 	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
 	.long	cpu_arm1020_info
 	.long	arm1020_processor_functions
+	.long	v4wbi_tlb_fns
 	.size	__arm1020_proc_info, . - __arm1020_proc_info
diff -urN linux-2.5.6-pre1/arch/arm/mm/proc-arm2,3.S linux-2.5.6-pre2/arch/arm/mm/proc-arm2,3.S
--- linux-2.5.6-pre1/arch/arm/mm/proc-arm2,3.S	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/arch/arm/mm/proc-arm2,3.S	Thu Feb 28 13:34:18 2002
@@ -341,6 +341,7 @@
 		.long	0
 		.long	cpu_arm2_info
 		.long	SYMBOL_NAME(arm2_processor_functions)
+		.long	0
 
 		.long	0x41560250
 		.long	0xfffffff0
@@ -351,6 +352,7 @@
 		.long	0
 		.long	cpu_arm250_info
 		.long	SYMBOL_NAME(arm250_processor_functions)
+		.long	0
 
 		.long	0x41560300
 		.long	0xfffffff0
@@ -361,4 +363,4 @@
 		.long	0
 		.long	cpu_arm3_info
 		.long	SYMBOL_NAME(arm3_processor_functions)
-
+		.long	0
diff -urN linux-2.5.6-pre1/arch/arm/mm/proc-arm6,7.S linux-2.5.6-pre2/arch/arm/mm/proc-arm6,7.S
--- linux-2.5.6-pre1/arch/arm/mm/proc-arm6,7.S	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/arch/arm/mm/proc-arm6,7.S	Thu Feb 28 13:34:18 2002
@@ -48,47 +48,6 @@
 		mov	pc, lr
 
 /*
- * Function: arm6_7_tlb_invalidate_all (void)
- *
- * Purpose : flush all TLB entries in all caches
- */
-ENTRY(cpu_arm6_tlb_invalidate_all)
-ENTRY(cpu_arm7_tlb_invalidate_all)
-		mov	r0, #0
-		mcr	p15, 0, r0, c5, c0, 0		@ flush TLB
-		mov	pc, lr
-
-/*
- * Function: arm6_7_tlb_invalidate_page (unsigned long address, int end, int flags)
- *
- * Params  : address	Area start address
- *	   : end	Area end address
- *	   : flags	b0 = I cache as well
- *
- * Purpose : flush a TLB entry
- */
-ENTRY(cpu_arm6_tlb_invalidate_range)
-ENTRY(cpu_arm7_tlb_invalidate_range)
-1:		mcr	p15, 0, r0, c6, c0, 0		@ flush TLB
-		add	r0, r0, #4096
-		cmp	r0, r1
-		blt	1b
-		mov	pc, lr
-
-/*
- * Function: arm6_7_tlb_invalidate_page (unsigned long address, int flags)
- *
- * Params  : address	Address
- *	   : flags	b0 = I-TLB as well
- *
- * Purpose : flush a TLB entry
- */
-ENTRY(cpu_arm6_tlb_invalidate_page)
-ENTRY(cpu_arm7_tlb_invalidate_page)
-		mcr	p15, 0, r0, c6, c0, 0		@ flush TLB
-		mov	pc, lr
-
-/*
  * Function: arm6_7_data_abort ()
  *
  * Params  : r0 = address of aborted instruction
@@ -409,11 +368,6 @@
 		.word	cpu_arm6_icache_invalidate_range
 		.word	cpu_arm6_icache_invalidate_page
 
-		/* tlb */
-		.word	cpu_arm6_tlb_invalidate_all
-		.word	cpu_arm6_tlb_invalidate_range
-		.word	cpu_arm6_tlb_invalidate_page
-
 		/* pgtable */
 		.word	cpu_arm6_set_pgd
 		.word	cpu_arm6_set_pmd
@@ -453,11 +407,6 @@
 		.word	cpu_arm7_icache_invalidate_range
 		.word	cpu_arm7_icache_invalidate_page
 
-		/* tlb */
-		.word	cpu_arm7_tlb_invalidate_all
-		.word	cpu_arm7_tlb_invalidate_range
-		.word	cpu_arm7_tlb_invalidate_page
-
 		/* pgtable */
 		.word	cpu_arm7_set_pgd
 		.word	cpu_arm7_set_pmd
@@ -515,6 +464,7 @@
 		.long	HWCAP_SWP | HWCAP_26BIT
 		.long	cpu_arm6_info
 		.long	arm6_processor_functions
+		.long	v3_tlb_fns
 		.size	__arm6_proc_info, . - __arm6_proc_info
 
 		.type	__arm610_proc_info, #object
@@ -528,6 +478,7 @@
 		.long	HWCAP_SWP | HWCAP_26BIT
 		.long	cpu_arm610_info
 		.long	arm6_processor_functions
+		.long	v3_tlb_fns
 		.size	__arm610_proc_info, . - __arm610_proc_info
 
 		.type	__arm7_proc_info, #object
@@ -541,6 +492,7 @@
 		.long	HWCAP_SWP | HWCAP_26BIT
 		.long	cpu_arm7_info
 		.long	arm7_processor_functions
+		.long	v3_tlb_fns
 		.size	__arm7_proc_info, . - __arm7_proc_info
 
 		.type	__arm710_proc_info, #object
@@ -554,4 +506,5 @@
 		.long	HWCAP_SWP | HWCAP_26BIT
 		.long	cpu_arm710_info
 		.long	arm7_processor_functions
+		.long	v3_tlb_fns
 		.size	__arm710_proc_info, . - __arm710_proc_info
diff -urN linux-2.5.6-pre1/arch/arm/mm/proc-arm720.S linux-2.5.6-pre2/arch/arm/mm/proc-arm720.S
--- linux-2.5.6-pre1/arch/arm/mm/proc-arm720.S	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/arch/arm/mm/proc-arm720.S	Thu Feb 28 13:34:18 2002
@@ -67,44 +67,6 @@
 		mov	pc, lr
 
 /*
- * Function: arm720_tlb_invalidate_all (void)
- *
- * Purpose : flush all TLB entries in all caches
- */
-ENTRY(cpu_arm720_tlb_invalidate_all)
-		mov	r0, #0
-		mcr	p15, 0, r0, c8, c7, 0		@ flush TLB (v4)
-		mov	pc, lr
-
-/*
- * Function: arm720_tlb_invalidate_page (unsigned long address, int end, int flags)
- *
- * Params  : address	Area start address
- *	   : end	Area end address
- *	   : flags	b0 = I cache as well
- *
- * Purpose : flush a TLB entry
- */
-ENTRY(cpu_arm720_tlb_invalidate_range)
-1:		mcr	p15, 0, r0, c8, c7, 1		@ flush TLB (v4)
-		add	r0, r0, #4096
-		cmp	r0, r1
-		blt	1b
-		mov	pc, lr
-
-/*
- * Function: arm720_tlb_invalidate_page (unsigned long address, int flags)
- *
- * Params  : address	Address
- *	   : flags	b0 = I-TLB as well
- *
- * Purpose : flush a TLB entry
- */
-ENTRY(cpu_arm720_tlb_invalidate_page)
-		mcr	p15, 0, r0, c8, c7, 1		@ flush TLB (v4)
-		mov	pc, lr
-
-/*
  * Function: arm720_check_bugs (void)
  *	   : arm720_proc_init (void)
  *	   : arm720_proc_fin (void)
@@ -259,11 +221,6 @@
 		.word	cpu_arm720_icache_invalidate_range
 		.word	cpu_arm720_icache_invalidate_page
 
-		/* tlb */
-		.word	cpu_arm720_tlb_invalidate_all
-		.word	cpu_arm720_tlb_invalidate_range
-		.word	cpu_arm720_tlb_invalidate_page
-
 		/* pgtable */
 		.word	cpu_arm720_set_pgd
 		.word	cpu_arm720_set_pmd
@@ -307,4 +264,5 @@
 		.long	HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | HWCAP_26BIT	@ elf_hwcap
 		.long	cpu_arm720_info				@ info
 		.long	arm720_processor_functions
+		.long	v4_tlb_fns
 		.size	__arm720_proc_info, . - __arm720_proc_info
diff -urN linux-2.5.6-pre1/arch/arm/mm/proc-arm920.S linux-2.5.6-pre2/arch/arm/mm/proc-arm920.S
--- linux-2.5.6-pre1/arch/arm/mm/proc-arm920.S	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/arch/arm/mm/proc-arm920.S	Thu Feb 28 13:34:18 2002
@@ -358,62 +358,6 @@
 	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
 	mov	pc, lr
 
-/* ================================== TLB ================================= */
-
-/*
- * cpu_arm920_tlb_invalidate_all()
- *
- * Invalidate all TLB entries
- */
-	.align	5
-ENTRY(cpu_arm920_tlb_invalidate_all)
-	mov	r0, #0
-	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
-	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I & D TLBs
-	mov	pc, lr
-
-/*
- * cpu_arm920_tlb_invalidate_range(start, end)
- *
- * invalidate TLB entries covering the specified range
- *
- * start: range start address
- * end:   range end address
- */
-	.align	5
-ENTRY(cpu_arm920_tlb_invalidate_range)
-	mov	r3, #0
-	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
-
-	mov	r3, #PAGESIZE
-	sub	r3, r3, #1
-	bic 	r0, r0, r3
-	bic	r1, r1, r3
-
-1:	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	mcr	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
-	add	r0, r0, #PAGESIZE
-	cmp	r0, r1
-	blt	1b
-	mov	pc, lr
-
-/*
- * cpu_arm920_tlb_invalidate_page(page, flags)
- *
- * invalidate the TLB entries for the specified page.
- *
- * page:  page to invalidate
- * flags: non-zero if we include the I TLB
- */
-	.align	5
-ENTRY(cpu_arm920_tlb_invalidate_page)
-	mov	r3, #0
-	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
-	teq	r1, #0
-	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	mcrne	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
-	mov	pc, lr
-
 /* =============================== PageTable ============================== */
 
 /*
@@ -589,11 +533,6 @@
 	.word	cpu_arm920_icache_invalidate_range
 	.word	cpu_arm920_icache_invalidate_page
 
-	/* tlb */
-	.word	cpu_arm920_tlb_invalidate_all
-	.word	cpu_arm920_tlb_invalidate_range
-	.word	cpu_arm920_tlb_invalidate_page
-
 	/* pgtable */
 	.word	cpu_arm920_set_pgd
 	.word	cpu_arm920_set_pmd
@@ -635,4 +574,5 @@
 	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
 	.long	cpu_arm920_info
 	.long	arm920_processor_functions
+	.long	v4wbi_tlb_fns
 	.size	__arm920_proc_info, . - __arm920_proc_info
diff -urN linux-2.5.6-pre1/arch/arm/mm/proc-arm922.S linux-2.5.6-pre2/arch/arm/mm/proc-arm922.S
--- linux-2.5.6-pre1/arch/arm/mm/proc-arm922.S	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/arch/arm/mm/proc-arm922.S	Thu Feb 28 13:34:18 2002
@@ -359,62 +359,6 @@
 	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
 	mov	pc, lr
 
-/* ================================== TLB ================================= */
-
-/*
- * cpu_arm922_tlb_invalidate_all()
- *
- * Invalidate all TLB entries
- */
-	.align	5
-ENTRY(cpu_arm922_tlb_invalidate_all)
-	mov	r0, #0
-	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
-	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I & D TLBs
-	mov	pc, lr
-
-/*
- * cpu_arm922_tlb_invalidate_range(start, end)
- *
- * invalidate TLB entries covering the specified range
- *
- * start: range start address
- * end:   range end address
- */
-	.align	5
-ENTRY(cpu_arm922_tlb_invalidate_range)
-	mov	r3, #0
-	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
-
-	mov	r3, #PAGESIZE
-	sub	r3, r3, #1
-	bic 	r0, r0, r3
-	bic	r1, r1, r3
-
-1:	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	mcr	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
-	add	r0, r0, #PAGESIZE
-	cmp	r0, r1
-	blt	1b
-	mov	pc, lr
-
-/*
- * cpu_arm922_tlb_invalidate_page(page, flags)
- *
- * invalidate the TLB entries for the specified page.
- *
- * page:  page to invalidate
- * flags: non-zero if we include the I TLB
- */
-	.align	5
-ENTRY(cpu_arm922_tlb_invalidate_page)
-	mov	r3, #0
-	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
-	teq	r1, #0
-	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	mcrne	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
-	mov	pc, lr
-
 /* =============================== PageTable ============================== */
 
 /*
@@ -590,11 +534,6 @@
 	.word	cpu_arm922_icache_invalidate_range
 	.word	cpu_arm922_icache_invalidate_page
 
-	/* tlb */
-	.word	cpu_arm922_tlb_invalidate_all
-	.word	cpu_arm922_tlb_invalidate_range
-	.word	cpu_arm922_tlb_invalidate_page
-
 	/* pgtable */
 	.word	cpu_arm922_set_pgd
 	.word	cpu_arm922_set_pmd
@@ -636,4 +575,5 @@
 	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
 	.long	cpu_arm922_info
 	.long	arm922_processor_functions
+	.long	v4wbi_tlb_fns
 	.size	__arm922_proc_info, . - __arm922_proc_info
diff -urN linux-2.5.6-pre1/arch/arm/mm/proc-arm926.S linux-2.5.6-pre2/arch/arm/mm/proc-arm926.S
--- linux-2.5.6-pre1/arch/arm/mm/proc-arm926.S	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/arch/arm/mm/proc-arm926.S	Thu Feb 28 13:34:18 2002
@@ -387,62 +387,6 @@
 	mov	pc, lr
 
 
-/* ================================== TLB ================================= */
-
-/*
- * cpu_arm926_tlb_invalidate_all()
- *
- * Invalidate all TLB entries
- */
-	.align	5
-ENTRY(cpu_arm926_tlb_invalidate_all)
-	mov	r0, #0
-	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
-	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I & D TLBs
-	mov	pc, lr
-
-/*
- * cpu_arm926_tlb_invalidate_range(start, end)
- *
- * invalidate TLB entries covering the specified range
- *
- * start: range start address
- * end:   range end address
- */
-	.align	5
-ENTRY(cpu_arm926_tlb_invalidate_range)
-	mov	r3, #0
-	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
-
-	mov	r3, #PAGESIZE
-	sub	r3, r3, #1
-	bic	r0, r0, r3
-	bic	r1, r1, r3
-
-1:	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	mcr	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
-	add	r0, r0, #PAGESIZE
-	cmp	r0, r1
-	blt	1b
-	mov	pc, lr
-
-/*
- * cpu_arm926_tlb_invalidate_page(page, flags)
- *
- * invalidate the TLB entries for the specified page.
- *
- * page:  page to invalidate
- * flags: non-zero if we include the I TLB
- */
-	.align	5
-ENTRY(cpu_arm926_tlb_invalidate_page)
-	mov	r3, #0
-	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
-	teq	r1, #0
-	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	mcrne	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
-	mov	pc, lr
-
 /* =============================== PageTable ============================== */
 
 /*
@@ -627,11 +571,6 @@
 	.word	cpu_arm926_icache_invalidate_range
 	.word	cpu_arm926_icache_invalidate_page
 
-	/* tlb */
-	.word	cpu_arm926_tlb_invalidate_all
-	.word	cpu_arm926_tlb_invalidate_range
-	.word	cpu_arm926_tlb_invalidate_page
-
 	/* pgtable */
 	.word	cpu_arm926_set_pgd
 	.word	cpu_arm926_set_pmd
@@ -673,4 +612,5 @@
 	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
 	.long	cpu_arm926_info
 	.long	arm926_processor_functions
+	.long	v4wbi_tlb_fns
 	.size	__arm926_proc_info, . - __arm926_proc_info
diff -urN linux-2.5.6-pre1/arch/arm/mm/proc-macros.S linux-2.5.6-pre2/arch/arm/mm/proc-macros.S
--- linux-2.5.6-pre1/arch/arm/mm/proc-macros.S	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mm/proc-macros.S	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,25 @@
+#include <asm/thread_info.h>
+
+/*
+ * vma_vm_mm - get mm pointer from vma pointer (vma->vm_mm)
+ */
+	.macro	vma_vm_mm, rd, rn
+	ldr	\rd, [\rn, #VMA_VM_MM]
+	.endm
+
+/*
+ * vma_vm_flags - get vma->vm_flags
+ */
+	.macro	vma_vm_flags, rd, rn
+	ldr	\rd, [\rn, #VMA_VM_FLAGS]
+	.endm
+
+/*
+ * act_mm - get current->active_mm
+ */
+	.macro	act_mm, rd
+	bic	\rd, sp, #8128
+	bic	\rd, \rd, #63
+	ldr	\rd, [\rd, #TI_TASK]
+	ldr	\rd, [\rd, #TSK_ACTIVE_MM]
+	.endm
diff -urN linux-2.5.6-pre1/arch/arm/mm/proc-sa110.S linux-2.5.6-pre2/arch/arm/mm/proc-sa110.S
--- linux-2.5.6-pre1/arch/arm/mm/proc-sa110.S	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/arch/arm/mm/proc-sa110.S	Thu Feb 28 13:34:18 2002
@@ -406,61 +406,6 @@
 	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
 	mov	pc, lr
 
-/* ================================== TLB ================================= */
-
-/*
- * cpu_sa110_tlb_invalidate_all()
- *
- * Invalidate all TLB entries
- */
-	.align	5
-ENTRY(cpu_sa110_tlb_invalidate_all)
-ENTRY(cpu_sa1100_tlb_invalidate_all)
-	mov	r0, #0
-	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
-	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I & D TLBs
-	mov	pc, lr
-
-/*
- * cpu_sa110_tlb_invalidate_range(start, end)
- *
- * invalidate TLB entries covering the specified range
- *
- * start: range start address
- * end:   range end address
- */
-	.align	5
-ENTRY(cpu_sa110_tlb_invalidate_range)
-ENTRY(cpu_sa1100_tlb_invalidate_range)
-	bic	r0, r0, #0x0ff
-	bic	r0, r0, #0xf00
-	mov	r3, #0
-	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
-1:	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	add	r0, r0, #PAGESIZE
-	cmp	r0, r1
-	blo	1b
-	mcr	p15, 0, r3, c8, c5, 0		@ invalidate I TLB
-	mov	pc, lr
-
-/*
- * cpu_sa110_tlb_invalidate_page(page, flags)
- *
- * invalidate the TLB entries for the specified page.
- *
- * page:  page to invalidate
- * flags: non-zero if we include the I TLB
- */
-	.align	5
-ENTRY(cpu_sa110_tlb_invalidate_page)
-ENTRY(cpu_sa1100_tlb_invalidate_page)
-	mov	r3, #0
-	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
-	teq	r1, #0
-	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	mcrne	p15, 0, r3, c8, c5, 0		@ invalidate I TLB
-	mov	pc, lr
-
 /* =============================== PageTable ============================== */
 
 /*
@@ -615,11 +560,6 @@
 	.word	cpu_sa110_icache_invalidate_range
 	.word	cpu_sa110_icache_invalidate_page
 
-	/* tlb */
-	.word	cpu_sa110_tlb_invalidate_all
-	.word	cpu_sa110_tlb_invalidate_range
-	.word	cpu_sa110_tlb_invalidate_page
-
 	/* pgtable */
 	.word	cpu_sa110_set_pgd
 	.word	cpu_sa110_set_pmd
@@ -665,19 +605,14 @@
 	.word	cpu_sa1100_icache_invalidate_range
 	.word	cpu_sa1100_icache_invalidate_page
 
-	/* tlb */
-	.word	cpu_sa1100_tlb_invalidate_all
-	.word	cpu_sa1100_tlb_invalidate_range
-	.word	cpu_sa1100_tlb_invalidate_page
-
 	/* pgtable */
 	.word	cpu_sa1100_set_pgd
 	.word	cpu_sa1100_set_pmd
 	.word	cpu_sa1100_set_pte
 
 	/* misc */
-	.word	armv4_clear_user_page
-	.word	armv4_copy_user_page
+	.word	armv4_mc_clear_user_page
+	.word	armv4_mc_copy_user_page
 
 	.size	sa1100_processor_functions, . - sa1100_processor_functions
 
@@ -715,6 +650,7 @@
 	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
 	.long	cpu_sa110_info
 	.long	sa110_processor_functions
+	.long	v4wb_tlb_fns
 	.size	__sa110_proc_info, . - __sa110_proc_info
 
 	.type	__sa1100_proc_info,#object
@@ -728,6 +664,7 @@
 	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
 	.long	cpu_sa1100_info
 	.long	sa1100_processor_functions
+	.long	v4wb_tlb_fns
 	.size	__sa1100_proc_info, . - __sa1100_proc_info
 
 	.type	__sa1110_proc_info,#object
@@ -741,4 +678,5 @@
 	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
 	.long	cpu_sa1110_info
 	.long	sa1100_processor_functions
+	.long	v4wb_tlb_fns
 	.size	__sa1110_proc_info, . - __sa1110_proc_info
diff -urN linux-2.5.6-pre1/arch/arm/mm/proc-syms.c linux-2.5.6-pre2/arch/arm/mm/proc-syms.c
--- linux-2.5.6-pre1/arch/arm/mm/proc-syms.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/arch/arm/mm/proc-syms.c	Thu Feb 28 13:34:18 2002
@@ -8,6 +8,9 @@
  * published by the Free Software Foundation.
  */
 #include <linux/module.h>
+#include <linux/mm.h>
+
+#include <asm/pgalloc.h>
 #include <asm/proc-fns.h>
 
 #ifndef MULTI_CPU
@@ -20,12 +23,18 @@
 EXPORT_SYMBOL(cpu_dcache_invalidate_range);
 EXPORT_SYMBOL(cpu_icache_invalidate_range);
 EXPORT_SYMBOL(cpu_icache_invalidate_page);
-EXPORT_SYMBOL(cpu_tlb_invalidate_all);
-EXPORT_SYMBOL(cpu_tlb_invalidate_range);
-EXPORT_SYMBOL(cpu_tlb_invalidate_page);
 EXPORT_SYMBOL(cpu_set_pgd);
 EXPORT_SYMBOL(cpu_set_pmd);
 EXPORT_SYMBOL(cpu_set_pte);
 #else
 EXPORT_SYMBOL(processor);
 #endif
+
+#ifndef MULTI_TLB
+EXPORT_SYMBOL_NOVERS(__cpu_flush_kern_tlb_all);
+EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_mm);
+EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_range);
+EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_page);
+#else
+EXPORT_SYMBOL(cpu_tlb);
+#endif
diff -urN linux-2.5.6-pre1/arch/arm/mm/proc-xscale.S linux-2.5.6-pre2/arch/arm/mm/proc-xscale.S
--- linux-2.5.6-pre1/arch/arm/mm/proc-xscale.S	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/arch/arm/mm/proc-xscale.S	Thu Feb 28 13:34:18 2002
@@ -494,55 +494,6 @@
 ENTRY(xscale_cache_dummy)
 	mov	pc, lr
 
-/* ================================== TLB ================================= */
-
-/*
- * cpu_xscale_tlb_invalidate_all()
- *
- * Invalidate all TLB entries
- */
-	.align	5
-ENTRY(cpu_xscale_tlb_invalidate_all)
-	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
-	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
-	cpwait_ret lr, ip
-
-/*
- * cpu_xscale_tlb_invalidate_range(start, end)
- *
- * invalidate TLB entries covering the specified range
- *
- * start: range start address
- * end:   range end address
- */
-	.align	5
-ENTRY(cpu_xscale_tlb_invalidate_range)
-	bic	r0, r0, #(PAGESIZE - 1) & 0x00ff
-	bic	r0, r0, #(PAGESIZE - 1) & 0xff00
-	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
-1:	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	mcr	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
-	add	r0, r0, #PAGESIZE
-	cmp	r0, r1
-	blo	1b
-	cpwait_ret lr, ip
-
-/*
- * cpu_xscale_tlb_invalidate_page(page, flags)
- *
- * invalidate the TLB entries for the specified page.
- *
- * page:  page to invalidate
- * flags: non-zero if we include the I TLB
- */
-	.align	5
-ENTRY(cpu_xscale_tlb_invalidate_page)
-	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
-	teq	r1, #0
-	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	mcrne	p15, 0, r3, c8, c5, 1		@ invalidate I TLB entry
-	cpwait_ret lr, ip
-
 /* ================================ TLB LOCKING==============================
  *
  * The XScale MicroArchitecture implements support for locking entries into
@@ -637,6 +588,7 @@
 	orreq	r1, r1, #PMD_SECT_TEX(1)
 #endif
 	str	r1, [r0]
+	mov	ip, #0
 	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
 	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
 	mov	pc, lr
@@ -645,6 +597,8 @@
  * cpu_xscale_set_pte(ptep, pte)
  *
  * Set a PTE and flush it out
+ *
+ * Errata 40: must set memory to write-through for user read-only pages.
  */
 	.align	5
 ENTRY(cpu_xscale_set_pte)
@@ -653,29 +607,49 @@
 	bic	r2, r1, #0xff0
 	orr	r2, r2, #PTE_TYPE_EXT		@ extended page
 
-	eor	r1, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
+	eor	r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
 
-	tst	r1, #L_PTE_USER | L_PTE_EXEC	@ User or Exec?
+	tst	r3, #L_PTE_USER | L_PTE_EXEC	@ User or Exec?
 	orrne	r2, r2, #PTE_EXT_AP_URO_SRW	@ yes -> user r/o, system r/w
 
-	tst	r1, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
+	tst	r3, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
 	orreq	r2, r2, #PTE_EXT_AP_UNO_SRW	@ yes -> user n/a, system r/w
 						@ combined with user -> user r/w
 
+	@
+	@ Handle the X bit.  We want to set this bit for the minicache
+	@ (U = E = B = W = 0, C = 1) or when write allocate is enabled,
+	@ and we have a writeable, cacheable region.  If we ignore the
+	@ U and E bits, we can allow user space to use the minicache as
+	@ well.
+	@
+	@  X = (C & ~W & ~B) | (C & W & B & write_allocate)
+	@
+	eor	ip, r1, #L_PTE_CACHEABLE
+	tst	ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE
 #if PTE_CACHE_WRITE_ALLOCATE
-	tst	r1, #L_PTE_CACHEABLE		@ cacheable?
-	orrne	r2, r2, #PTE_EXT_TEX(1)
-#else
-	eor	r1, r1, #L_PTE_CACHEABLE
-	tst	r1, #L_PTE_CACHEABLE | L_PTE_BUFFERABLE @ C = 1 B = 0?
-	orreq	r2, r2, #PTE_EXT_TEX(1)		@ yes -> set X (minicache)
+	eorne	ip, r1, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE
+	tstne	ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE
 #endif
+	orreq	r2, r2, #PTE_EXT_TEX(1)
+
+	@
+	@ Erratum 40: The B bit must be cleared for a user read-only
+	@ cacheable page.
+	@
+	@  B = B & ~((U|E) & C & ~W)
+	@
+	and	ip, r1, #L_PTE_USER | L_PTE_EXEC | L_PTE_WRITE | L_PTE_CACHEABLE
+	teq	ip, #L_PTE_USER | L_PTE_CACHEABLE
+	teqne	ip, #L_PTE_EXEC | L_PTE_CACHEABLE
+	teqne	ip, #L_PTE_USER | L_PTE_EXEC | L_PTE_CACHEABLE
+	biceq	r2, r2, #PTE_BUFFERABLE
 
-	tst	r1, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
+	tst	r3, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
 	movne	r2, #0				@ no -> fault
 
 	str	r2, [r0]			@ hardware version
-	mov	r0, r0
+	mov	ip, #0
 	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
 	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
 	mov	pc, lr
@@ -743,11 +717,6 @@
 	.word	cpu_xscale_icache_invalidate_range
 	.word	cpu_xscale_icache_invalidate_page
 
-	/* tlb */
-	.word	cpu_xscale_tlb_invalidate_all
-	.word	cpu_xscale_tlb_invalidate_range
-	.word	cpu_xscale_tlb_invalidate_page
-
 	/* pgtable */
 	.word	cpu_xscale_set_pgd
 	.word	cpu_xscale_set_pmd
@@ -795,6 +764,7 @@
 	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
 	.long	cpu_80200_info
 	.long	xscale_processor_functions
+	.long	v4wbi_tlb_fns
 	.size	__80200_proc_info, . - __80200_proc_info
 
 	.type	__cotulla_proc_info,#object
@@ -808,5 +778,6 @@
 	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
 	.long	cpu_cotulla_info
 	.long	xscale_processor_functions
+	.long	v4wbi_tlb_fns
 	.size	__cotulla_proc_info, . - __cotulla_proc_info
 
diff -urN linux-2.5.6-pre1/arch/arm/mm/tlb-v3.S linux-2.5.6-pre2/arch/arm/mm/tlb-v3.S
--- linux-2.5.6-pre1/arch/arm/mm/tlb-v3.S	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mm/tlb-v3.S	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,88 @@
+/*
+ *  linux/arch/arm/mm/tlbv3.S
+ *
+ *  Copyright (C) 1997-2002 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  ARM architecture version 3 TLB handling functions.
+ *
+ * Processors: ARM610, ARM710.
+ */
+#include <linux/linkage.h>
+#include <asm/constants.h>
+#include "proc-macros.S"
+
+	.align	5
+/*
+ *	v3_flush_user_tlb_mm(mm)
+ *
+ *	Invalidate all TLB entries in a particular address space
+ *
+ *	- mm    - mm_struct describing address space
+ */
+ENTRY(v3_flush_user_tlb_mm)
+	act_mm	r1				@ get current->active_mm
+	teq	r0, r1				@ == mm ?
+	movne	pc, lr				@ no, we dont do anything
+
+/*
+ *	v3_flush_kern_tlb_all()
+ *
+ *	Invalidate the entire TLB
+ */
+ENTRY(v3_flush_kern_tlb_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c5, c0, 0		@ invalidate TLB
+	mov	pc, lr
+
+/*
+ *	v3_flush_user_tlb_range(start, end, mm)
+ *
+ *	Invalidate a range of TLB entries in the specified address space.
+ *
+ *	- start - range start address
+ *	- end   - range end address
+ *	- mm    - mm_struct describing address space
+ */
+	.align	5
+ENTRY(v3_flush_user_tlb_range)
+	vma_vm_mm r2, r2
+	act_mm	r3				@ get current->active_mm
+	teq	r2, r3				@ == mm ?
+	movne	pc, lr				@ no, we dont do anything
+	bic	r0, r0, #0x0ff
+	bic	r0, r0, #0xf00
+1:	mcr	p15, 0, r0, c6, c0, 0		@ invalidate TLB entry
+	add	r0, r0, #PAGE_SZ
+	cmp	r0, r1
+	blo	1b
+	mov	pc, lr
+
+/*
+ *	v3_flush_user_tlb_page(vaddr,vma)
+ *
+ *	Invalidate the specified page in the specified address space.
+ *
+ *	- vaddr - virtual address (may not be aligned)
+ *	- vma   - vma_struct describing address range
+ */
+	.align	5
+ENTRY(v3_flush_user_tlb_page)
+	vma_vm_mm r2, r1			@ get vma->vm_mm
+	act_mm	r3				@ get current->active_mm
+	teq	r2, r3				@ equal
+	movne	pc, lr				@ no
+ENTRY(v3_flush_kern_tlb_page)
+	mcr	p15, 0, r0, c6, c0, 0		@ invalidate TLB entry
+	mov	pc, lr
+
+ENTRY(v3_tlb_fns)
+	.word	v3_flush_kern_tlb_all
+	.word	v3_flush_user_tlb_mm
+	.word	v3_flush_user_tlb_range
+	.word	v3_flush_user_tlb_page
+	.word	v3_flush_kern_tlb_page
+
diff -urN linux-2.5.6-pre1/arch/arm/mm/tlb-v4.S linux-2.5.6-pre2/arch/arm/mm/tlb-v4.S
--- linux-2.5.6-pre1/arch/arm/mm/tlb-v4.S	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mm/tlb-v4.S	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,106 @@
+/*
+ *  linux/arch/arm/mm/tlbv4.S
+ *
+ *  Copyright (C) 1997-2002 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  ARM architecture version 4 TLB handling functions.
+ *  These assume a split I/D TLBs, and no write buffer.
+ *
+ * Processors: ARM720T
+ */
+#include <linux/linkage.h>
+#include <asm/constants.h>
+#include "proc-macros.S"
+
+	.align	5
+/*
+ *	v4_flush_user_tlb_mm(mm)
+ *
+ *	Invalidate all TLB entries in a particular address space
+ *
+ *	- mm    - mm_struct describing address space
+ */
+ENTRY(v4_flush_user_tlb_mm)
+	act_mm	r1				@ get current->active_mm
+	teq	r0, r1				@ == mm ?
+	movne	pc, lr				@ no, we dont do anything
+
+/*
+ *	v4_flush_kern_tlb_all()
+ *
+ *	Invalidate the entire TLB
+ */
+ENTRY(v4_flush_kern_tlb_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I + D TLBs
+	mov	pc, lr
+
+/*
+ *	v4_flush_user_tlb_range(start, end, mm)
+ *
+ *	Invalidate a range of TLB entries in the specified address space.
+ *
+ *	- start - range start address
+ *	- end   - range end address
+ *	- mm    - mm_struct describing address space
+ */
+	.align	5
+ENTRY(v4_flush_user_tlb_range)
+	vma_vm_mm ip, r2
+	act_mm	r3				@ get current->active_mm
+	eors	r3, ip, r3				@ == mm ?
+	movne	pc, lr				@ no, we dont do anything
+	vma_vm_flags ip, r2
+	bic	r0, r0, #0x0ff
+	bic	r0, r0, #0xf00
+1:	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
+	add	r0, r0, #PAGE_SZ
+	cmp	r0, r1
+	blo	1b
+	tst	ip, #VM_EXEC
+	mcrne	p15, 0, r3, c8, c5, 0		@ invalidate I TLB
+	mov	pc, lr
+
+/*
+ *	v4_flush_user_tlb_page(vaddr,vma)
+ *
+ *	Invalidate the specified page in the specified address space.
+ *
+ *	- vaddr - virtual address (may not be aligned)
+ *	- vma   - vma_struct describing address range
+ */
+	.align	5
+ENTRY(v4_flush_user_tlb_page)
+	vma_vm_mm r2, r1			@ get vma->vm_mm
+	act_mm	r3				@ get current->active_mm
+	teq	r2, r3				@ equal
+	movne	pc, lr				@ no
+	vma_vm_flags r2, r1
+	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
+	tst	r2, #VM_EXEC
+	mcrne	p15, 0, r3, c8, c5, 0		@ invalidate I TLB
+	mov	pc, lr
+
+/*
+ *	v4_flush_kern_tlb_page(kaddr)
+ *
+ *	Invalidate the TLB entry for the specified page.  The address
+ *	will be in the kernels virtual memory space.  Current uses
+ *	only require the D-TLB to be invalidated.
+ *
+ *	- kaddr - Kernel virtual memory address
+ */
+ENTRY(v4_flush_kern_tlb_page)
+	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
+	mov	pc, lr
+
+ENTRY(v4_tlb_fns)
+	.word	v4_flush_kern_tlb_all
+	.word	v4_flush_user_tlb_mm
+	.word	v4_flush_user_tlb_range
+	.word	v4_flush_user_tlb_page
+	.word	v4_flush_kern_tlb_page
diff -urN linux-2.5.6-pre1/arch/arm/mm/tlb-v4wb.S linux-2.5.6-pre2/arch/arm/mm/tlb-v4wb.S
--- linux-2.5.6-pre1/arch/arm/mm/tlb-v4wb.S	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/arch/arm/mm/tlb-v4wb.S	Thu Feb 28 13:34:18 2002
@@ -0,0 +1,160 @@
+/*
+ *  linux/arch/arm/mm/tlbv4wb.S
+ *
+ *  Copyright (C) 1997-2002 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  ARM architecture version 4 and version 5 TLB handling functions.
+ *  These assume a split I/D TLBs, with a write buffer.
+ *
+ *  Processors: ARM920 ARM922 ARM926 SA110 SA1100 SA1110 XScale
+ */
+#include <linux/linkage.h>
+#include <asm/constants.h>
+#include "proc-macros.S"
+
+	.align	5
+/*
+ *	v4wb_flush_user_tlb_mm(mm)
+ *
+ *	Invalidate all TLB entries in a particular address space
+ *
+ *	- mm    - mm_struct describing address space
+ */
+ENTRY(v4wb_flush_user_tlb_mm)
+ENTRY(v4wbi_flush_user_tlb_mm)
+	act_mm	r1				@ get current->active_mm
+	teq	r0, r1				@ == mm ?
+	movne	pc, lr				@ no, we dont do anything
+
+/*
+ *	v4wb_flush_tlb_all()
+ *
+ *	Invalidate the entire TLB
+ */
+ENTRY(v4wb_flush_kern_tlb_all)
+ENTRY(v4wbi_flush_kern_tlb_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
+	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I + D TLBs
+	mov	pc, lr
+
+/*
+ *	v4wb_flush_user_tlb_range(start, end, mm)
+ *
+ *	Invalidate a range of TLB entries in the specified address space.
+ *
+ *	- start - range start address
+ *	- end   - range end address
+ *	- mm    - mm_struct describing address space
+ */
+	.align	5
+ENTRY(v4wb_flush_user_tlb_range)
+	vma_vm_mm ip, r2
+	act_mm	r3				@ get current->active_mm
+	eors	r3, ip, r3				@ == mm ?
+	movne	pc, lr				@ no, we dont do anything
+	vma_vm_flags r2, r2
+	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
+	tst	r2, #VM_EXEC
+	mcrne	p15, 0, r3, c8, c5, 0		@ invalidate I TLB
+	bic	r0, r0, #0x0ff
+	bic	r0, r0, #0xf00
+1:	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
+	add	r0, r0, #PAGE_SZ
+	cmp	r0, r1
+	blo	1b
+	mov	pc, lr
+
+/*
+ *	v4wb_flush_user_tlb_page(vaddr,vma)
+ *
+ *	Invalidate the specified page in the specified address space.
+ *
+ *	- vaddr - virtual address (may not be aligned)
+ *	- vma   - vma_struct describing address range
+ */
+	.align	5
+ENTRY(v4wb_flush_user_tlb_page)
+	vma_vm_mm r2, r1			@ get vma->vm_mm
+	act_mm	r3				@ get current->active_mm
+	teq	r2, r3				@ equal
+	movne	pc, lr				@ no
+	vma_vm_flags r2, r1
+	mov	r3, #0
+	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
+	tst	r2, #VM_EXEC
+	mcrne	p15, 0, r3, c8, c5, 0		@ invalidate I TLB
+ENTRY(v4wb_flush_kern_tlb_page)
+	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
+	mov	pc, lr
+
+/*
+ * These two are optimised for ARM920, ARM922, ARM926, Xscale
+ */
+
+/*
+ *	v4wb_flush_user_tlb_range(start, end, mm)
+ *
+ *	Invalidate a range of TLB entries in the specified address space.
+ *
+ *	- start - range start address
+ *	- end   - range end address
+ *	- mm    - mm_struct describing address space
+ */
+	.align	5
+ENTRY(v4wbi_flush_user_tlb_range)
+	act_mm	r3				@ get current->active_mm
+	teq	r2, r3				@ == mm ?
+	movne	pc, lr				@ no, we dont do anything
+	mov	r3, #0
+	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
+	bic	r0, r0, #0x0ff
+	bic	r0, r0, #0xf00
+1:	mcr	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
+	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
+	add	r0, r0, #PAGE_SZ
+	cmp	r0, r1
+	blo	1b
+	mov	pc, lr
+
+/*
+ *	v4wb_flush_tlb_page(vaddr,vma)
+ *
+ *	Invalidate the specified page in the specified address space.
+ *
+ *	- vaddr - virtual address (may not be aligned)
+ *	- vma   - vma_struct describing address range
+ */
+	.align	5
+ENTRY(v4wbi_flush_user_tlb_page)
+	vma_vm_mm r2, r1			@ get vma->vm_mm
+	act_mm	r3				@ get current->active_mm
+	teq	r2, r3				@ equal
+	movne	pc, lr				@ no
+	vma_vm_flags r2, r1
+	mov	r3, #0
+	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
+	tst	r2, #VM_EXEC
+	mcrne	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
+ENTRY(v4wbi_flush_kern_tlb_page)
+	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
+	mov	pc, lr
+
+ENTRY(v4wb_tlb_fns)
+	.word	v4wb_flush_kern_tlb_all
+	.word	v4wb_flush_user_tlb_mm
+	.word	v4wb_flush_user_tlb_range
+	.word	v4wb_flush_user_tlb_page
+	.word	v4wb_flush_kern_tlb_page
+
+ENTRY(v4wbi_tlb_fns)
+	.word	v4wbi_flush_kern_tlb_all
+	.word	v4wbi_flush_user_tlb_mm
+	.word	v4wbi_flush_user_tlb_range
+	.word	v4wbi_flush_user_tlb_page
+	.word	v4wbi_flush_kern_tlb_page
+
diff -urN linux-2.5.6-pre1/arch/arm/nwfpe/ChangeLog linux-2.5.6-pre2/arch/arm/nwfpe/ChangeLog
--- linux-2.5.6-pre1/arch/arm/nwfpe/ChangeLog	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/arch/arm/nwfpe/ChangeLog	Thu Feb 28 13:34:18 2002
@@ -1,3 +1,26 @@
+2002-01-19  Russell King <rmk@arm.linux.org.uk>
+
+	* fpa11.h - Add documentation
+	          - remove userRegisters pointer from this structure.
+	          - add new method to obtain integer register values.
+	* softfloat.c - Remove float128
+	* softfloat.h - Remove float128
+	* softfloat-specialize - Remove float128
+
+	* The FPA11 structure is not a kernel-specific data structure.
+	  It is used by users of ptrace to examine the values of the
+	  floating point registers.  Therefore, any changes to the
+	  FPA11 structure (size or position of elements contained
+	  within) have to be well thought out.
+
+	* Since 128-bit float requires the FPA11 structure to change
+	  size, it has been removed.  128-bit float is currently unused,
+	  and needs various things to be re-worked so that we won't
+	  overflow the available space in the task structure.
+
+	* The changes are designed to break any patch that goes on top
+	  of this code, so that the authors properly review their changes.
+
 1999-08-19  Scott Bambrough  <scottb@netwinder.org>
 
 	* fpmodule.c - Changed version number to 0.95
diff -urN linux-2.5.6-pre1/arch/arm/nwfpe/double_cpdo.c linux-2.5.6-pre2/arch/arm/nwfpe/double_cpdo.c
--- linux-2.5.6-pre1/arch/arm/nwfpe/double_cpdo.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/arch/arm/nwfpe/double_cpdo.c	Thu Feb 28 13:34:18 2002
@@ -19,9 +19,9 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include "fpa11.h"
 #include "softfloat.h"
 #include "fpopcode.h"
-#include "fpa11.h"
 
 float64 float64_exp(float64 Fm);
 float64 float64_ln(float64 Fm);
@@ -165,8 +165,7 @@
 
       case RND_CODE:
       case URD_CODE:
-         fpa11->fpreg[Fd].fDouble = 
-             int32_to_float64(float64_to_int32(rFm));
+         fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm);
       break;
 
       case SQT_CODE:
diff -urN linux-2.5.6-pre1/arch/arm/nwfpe/entry.S linux-2.5.6-pre2/arch/arm/nwfpe/entry.S
--- linux-2.5.6-pre1/arch/arm/nwfpe/entry.S	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/arch/arm/nwfpe/entry.S	Thu Feb 28 13:34:18 2002
@@ -52,8 +52,6 @@
 
 1) The kernel has created a struct pt_regs on the stack and saved the
 user registers into it.  See /usr/include/asm/proc/ptrace.h for details.
-The emulator code uses userRegisters as the base of an array of words
-from which the contents of the registers can be extracted.
 
 2) It calls EmulateAll to emulate a floating point instruction.
 EmulateAll returns 1 if the emulation was successful, or 0 if not.
@@ -72,14 +70,9 @@
 
 	.globl	nwfpe_enter
 nwfpe_enter:
-	/* ?? Could put userRegisters and fpa11 into fixed regs during
-	   emulation.  This would reduce load/store overhead at the expense
-	   of stealing two regs from the register allocator.  Not sure if
-	   it's worth it.  */
-	str sp, [r10]                   @ Store the user registers pointer in the fpa11 structure.
         mov r4, lr			@ save the failure-return addresses
+	mov sl, sp
 
-	mov r0, r10
 	bl FPA11_CheckInit		@ check to see if we are initialised
 
         ldr r5, [sp, #60]	 	@ get contents of PC;
diff -urN linux-2.5.6-pre1/arch/arm/nwfpe/entry26.S linux-2.5.6-pre2/arch/arm/nwfpe/entry26.S
--- linux-2.5.6-pre1/arch/arm/nwfpe/entry26.S	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/arch/arm/nwfpe/entry26.S	Thu Feb 28 13:34:18 2002
@@ -65,18 +65,10 @@
 
 	.globl	nwfpe_enter
 nwfpe_enter:
-	ldr	r4, =userRegisters
-	str	sp, [r4]		@ save pointer to user regs
+	mov	sl, sp
+	bl	FPA11_CheckInit		@ check to see if we are initialised
 
-	mov	r10, sp, lsr #13	@ find workspace
-	mov	r10, r10, lsl #13
-	add	r10, r10, #TSS_FPESAVE
-
-	ldr	r4, =fpa11
-	str	r10, [r4]		@ store pointer to our state
-	mov	r4, sp			@ use r4 for local pointer
-
-	ldr	r5, [r4, #60]		@ get contents of PC
+	ldr	r5, [sp, #60]		@ get contents of PC
 	bic	r5, r5, #0xfc000003
 	ldr	r0, [r5, #-4]		@ get actual instruction into r0
 	bl	EmulateAll		@ emulate the instruction
@@ -93,10 +85,10 @@
 	teqne	r2, #0x0E000000
 	bne	ret_from_exception	@ return ok if not a fp insn
 
-	ldr	r9, [r4, #60]		@ get new condition codes
+	ldr	r9, [sp, #60]		@ get new condition codes
 	and	r9, r9, #0xfc000003
 	orr	r7, r5, r9
-	str	r7, [r4, #60]		@ update PC copy in regs
+	str	r7, [sp, #60]		@ update PC copy in regs
 
 	mov	r0, r6			@ save a copy
 	mov	r1, r9			@ fetch the condition codes
diff -urN linux-2.5.6-pre1/arch/arm/nwfpe/extended_cpdo.c linux-2.5.6-pre2/arch/arm/nwfpe/extended_cpdo.c
--- linux-2.5.6-pre1/arch/arm/nwfpe/extended_cpdo.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/arch/arm/nwfpe/extended_cpdo.c	Thu Feb 28 13:34:18 2002
@@ -19,9 +19,9 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include "fpa11.h"
 #include "softfloat.h"
 #include "fpopcode.h"
-#include "fpa11.h"
 
 floatx80 floatx80_exp(floatx80 Fm);
 floatx80 floatx80_ln(floatx80 Fm);
@@ -157,8 +157,7 @@
 
       case RND_CODE:
       case URD_CODE:
-         fpa11->fpreg[Fd].fExtended = 
-             int32_to_floatx80(floatx80_to_int32(rFm));
+         fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm);
       break;
 
       case SQT_CODE:
diff -urN linux-2.5.6-pre1/arch/arm/nwfpe/fpa11.c linux-2.5.6-pre2/arch/arm/nwfpe/fpa11.c
--- linux-2.5.6-pre1/arch/arm/nwfpe/fpa11.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/arch/arm/nwfpe/fpa11.c	Thu Feb 28 13:34:18 2002
@@ -18,8 +18,6 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
-#include <linux/compiler.h>
-#include <asm/system.h>
 
 #include "fpa11.h"
 #include "fpopcode.h"
@@ -27,6 +25,9 @@
 #include "fpmodule.h"
 #include "fpmodule.inl"
 
+#include <linux/compiler.h>
+#include <asm/system.h>
+
 /* forward declarations */
 unsigned int EmulateCPDO(const unsigned int);
 unsigned int EmulateCPDT(const unsigned int);
@@ -56,6 +57,7 @@
 void SetRoundingMode(const unsigned int opcode)
 {
 #if MAINTAIN_FPCR
+   FPA11 *fpa11 = GET_FPA11();
    fpa11->fpcr &= ~MASK_ROUNDING_MODE;
 #endif   
    switch (opcode & MASK_ROUNDING_MODE)
@@ -94,6 +96,7 @@
 void SetRoundingPrecision(const unsigned int opcode)
 {
 #if MAINTAIN_FPCR
+   FPA11 *fpa11 = GET_FPA11();
    fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
 #endif   
    switch (opcode & MASK_ROUNDING_PRECISION)
@@ -123,8 +126,9 @@
   }
 }
 
-void FPA11_CheckInit(FPA11 *fpa11)
+void FPA11_CheckInit(void)
 {
+  FPA11 *fpa11 = GET_FPA11();
   if (unlikely(fpa11->initflag == 0))
   {
     resetFPA11();
diff -urN linux-2.5.6-pre1/arch/arm/nwfpe/fpa11.h linux-2.5.6-pre2/arch/arm/nwfpe/fpa11.h
--- linux-2.5.6-pre1/arch/arm/nwfpe/fpa11.h	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/arch/arm/nwfpe/fpa11.h	Thu Feb 28 13:34:18 2002
@@ -22,45 +22,66 @@
 #ifndef __FPA11_H__
 #define __FPA11_H__
 
+#define GET_FPA11() ((FPA11 *)(&current_thread_info()->fpstate))
+
+/*
+ * The processes registers are always at the very top of the 8K
+ * stack+task struct.  Use the same method as 'current' uses to
+ * reach them.
+ */
+register unsigned int *user_registers asm("sl");
+
+#define GET_USERREG() (user_registers)
+
+#include <linux/thread_info.h>
+
 /* includes */
 #include "fpsr.h"		/* FP control and status register definitions */
 #include "softfloat.h"
 
-/* Need task_struct */
-#include <linux/sched.h>
-
 #define		typeNone		0x00
 #define		typeSingle		0x01
 #define		typeDouble		0x02
 #define		typeExtended		0x03
 
+/*
+ * This must be no more and no less than 12 bytes.
+ */
 typedef union tagFPREG {
-   float32  fSingle;
-   float64  fDouble;
    floatx80 fExtended;
+   float64  fDouble;
+   float32  fSingle;
 } FPREG;
 
-/* FPA11 device model */
+/*
+ * FPA11 device model.
+ *
+ * This structure is exported to user space.  Do not re-order.
+ * Only add new stuff to the end, and do not change the size of
+ * any element.  Elements of this structure are used by user
+ * space, and must match struct user_fp in include/asm-arm/user.h.
+ * We include the byte offsets below for documentation purposes.
+ *
+ * The size of this structure and FPREG are checked by fpmodule.c
+ * on initialisation.  If the rules have been broken, NWFPE will
+ * not initialise.
+ */
 typedef struct tagFPA11 {
-  unsigned int *userRegisters;
-  FPREG fpreg[8];		/* 8 floating point registers */
-  FPSR fpsr;			/* floating point status register */
-  FPCR fpcr;			/* floating point control register */
-  unsigned char fType[8];	/* type of floating point value held in
-				   floating point registers.  One of none
-				   single, double or extended. */
-  int initflag;			/* this is special.  The kernel guarantees
-				   to set it to 0 when a thread is launched,
-				   so we can use it to detect whether this
-				   instance of the emulator needs to be
-				   initialised. */
+/*   0 */  FPREG fpreg[8];		/* 8 floating point registers */
+/*  96 */  FPSR fpsr;			/* floating point status register */
+/* 100 */  FPCR fpcr;			/* floating point control register */
+/* 104 */  unsigned char fType[8];	/* type of floating point value held in
+					   floating point registers.  One of none
+					   single, double or extended. */
+/* 112 */  int initflag;		/* this is special.  The kernel guarantees
+					   to set it to 0 when a thread is launched,
+					   so we can use it to detect whether this
+					   instance of the emulator needs to be
+					   initialised. */
 } FPA11;
 
 extern void resetFPA11(void);
 extern void SetRoundingMode(const unsigned int);
 extern void SetRoundingPrecision(const unsigned int);
 
-#define GET_FPA11() ((FPA11 *)(&current->thread.fpstate))
-#define GET_USERREG() (GET_FPA11()->userRegisters)
-
 #endif
diff -urN linux-2.5.6-pre1/arch/arm/nwfpe/fpa11_cpdt.c linux-2.5.6-pre2/arch/arm/nwfpe/fpa11_cpdt.c
--- linux-2.5.6-pre1/arch/arm/nwfpe/fpa11_cpdt.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre2/arch/arm/nwfpe/fpa11_cpdt.c	Thu Feb 28 13:34:18 2002
@@ -20,9 +20,9 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include "fpa11.h"
 #include "softfloat.h"
 #include "fpopcode.h"
-#include "fpa11.h"
 #include "fpmodule.h"
 #include "fpmodule.inl"
 
diff -urN linux-2.5.6-pre1/arch/arm/nwfpe/fpa11_cprt.c linux-2.5.6-pre2/arch/arm/nwfpe/fpa11_cprt.c
--- linux-2.5.6-pre1/arch/arm/nwfpe/fpa11_cprt.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/arch/arm/nwfpe/fpa11_cprt.c	Thu Feb 28 13:34:18 2002
@@ -20,10 +20,10 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include "fpa11.h"
 #include "milieu.h"
 #include "softfloat.h"
 #include "fpopcode.h"
-#include "fpa11.h"
 #include "fpa11.inl"
 #include "fpmodule.h"
 #include "fpmodule.inl"
@@ -82,8 +82,7 @@
    
    unsigned int nRc = 1;
    SetRoundingMode(opcode);
-   SetRoundingPrecision(opcode);
-   
+
    switch (opcode & MASK_ROUNDING_PRECISION)
    {
       case ROUND_SINGLE:
diff -urN linux-2.5.6-pre1/arch/arm/nwfpe/fpmodule.c linux-2.5.6-pre2/arch/arm/nwfpe/fpmodule.c
--- linux-2.5.6-pre1/arch/arm/nwfpe/fpmodule.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/arch/arm/nwfpe/fpmodule.c	Thu Feb 28 13:34:18 2002
@@ -21,6 +21,8 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include "fpa11.h"
+
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/config.h>
@@ -36,7 +38,6 @@
 #include "softfloat.h"
 #include "fpopcode.h"
 #include "fpmodule.h"
-#include "fpa11.h"
 #include "fpa11.inl"
 
 /* kernel symbols required for signal handling */
@@ -86,6 +87,11 @@
     return -EINVAL;
   }
 
+  if (sizeof(FPREG) != 12) {
+    printk(KERN_ERR "nwfpe: bad register size\n");
+    return -EINVAL;
+  }
+
 #ifdef MODULE
   if (!mod_member_present(&__this_module, can_unload))
     return -EINVAL;
diff -urN linux-2.5.6-pre1/arch/arm/nwfpe/fpopcode.c linux-2.5.6-pre2/arch/arm/nwfpe/fpopcode.c
--- linux-2.5.6-pre1/arch/arm/nwfpe/fpopcode.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/arch/arm/nwfpe/fpopcode.c	Thu Feb 28 13:34:18 2002
@@ -19,10 +19,10 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include "fpa11.h"
 #include "softfloat.h"
 #include "fpopcode.h"
 #include "fpsr.h"
-#include "fpa11.h"
 #include "fpmodule.h"
 #include "fpmodule.inl"
 
diff -urN linux-2.5.6-pre1/arch/arm/nwfpe/single_cpdo.c linux-2.5.6-pre2/arch/arm/nwfpe/single_cpdo.c
--- linux-2.5.6-pre1/arch/arm/nwfpe/single_cpdo.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/arch/arm/nwfpe/single_cpdo.c	Thu Feb 28 13:34:18 2002
@@ -19,9 +19,9 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include "fpa11.h"
 #include "softfloat.h"
 #include "fpopcode.h"
-#include "fpa11.h"
 
 float32 float32_exp(float32 Fm);
 float32 float32_ln(float32 Fm);
@@ -139,8 +139,7 @@
 
       case RND_CODE:
       case URD_CODE:
-         fpa11->fpreg[Fd].fSingle = 
-             int32_to_float32(float32_to_int32(rFm));
+         fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm);
       break;
 
       case SQT_CODE:
diff -urN linux-2.5.6-pre1/arch/arm/nwfpe/softfloat-specialize linux-2.5.6-pre2/arch/arm/nwfpe/softfloat-specialize
--- linux-2.5.6-pre1/arch/arm/nwfpe/softfloat-specialize	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre2/arch/arm/nwfpe/softfloat-specialize	Thu Feb 28 13:34:18 2002
@@ -364,108 +364,3 @@
 }
 
 #endif
-
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-The pattern for a default generated quadruple-precision NaN.  The `high' and
-`low' values hold the most- and least-significant bits, respectively.
--------------------------------------------------------------------------------
-*/
-#define float128_default_nan_high LIT64( 0xFFFFFFFFFFFFFFFF )
-#define float128_default_nan_low  LIT64( 0xFFFFFFFFFFFFFFFF )
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
-otherwise returns 0.
--------------------------------------------------------------------------------
-*/
-flag float128_is_nan( float128 a )
-{
-
-    return
-           ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
-        && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is a
-signaling NaN; otherwise returns 0.
--------------------------------------------------------------------------------
-*/
-flag float128_is_signaling_nan( float128 a )
-{
-
-    return
-           ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
-        && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the quadruple-precision floating-point NaN
-`a' to the canonical NaN format.  If `a' is a signaling NaN, the invalid
-exception is raised.
--------------------------------------------------------------------------------
-*/
-static commonNaNT float128ToCommonNaN( float128 a )
-{
-    commonNaNT z;
-
-    if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
-    z.sign = a.high>>63;
-    shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
-    return z;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the canonical NaN `a' to the quadruple-
-precision floating-point format.
--------------------------------------------------------------------------------
-*/
-static float128 commonNaNToFloat128( commonNaNT a )
-{
-    float128 z;
-
-    shift128Right( a.high, a.low, 16, &z.high, &z.low );
-    z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF800000000000 );
-    return z;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Takes two quadruple-precision floating-point values `a' and `b', one of
-which is a NaN, and returns the appropriate NaN result.  If either `a' or
-`b' is a signaling NaN, the invalid exception is raised.
--------------------------------------------------------------------------------
-*/
-static float128 propagateFloat128NaN( float128 a, float128 b )
-{
-    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
-
-    aIsNaN = float128_is_nan( a );
-    aIsSignalingNaN = float128_is_signaling_nan( a );
-    bIsNaN = float128_is_nan( b );
-    bIsSignalingNaN = float128_is_signaling_nan( b );
-    a.high |= LIT64( 0x0000800000000000 );
-    b.high |= LIT64( 0x0000800000000000 );
-    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
-    if ( aIsNaN ) {
-        return ( aIsSignalingNaN & bIsNaN ) ? b : a;
-    }
-    else {
-        return b;
-    }
-
-}
-
-#endif
-
diff -urN linux-2.5.6-pre1/arch/arm/nwfpe/softfloat.c linux-2.5.6-pre2/arch/arm/nwfpe/softfloat.c
--- linux-2.5.6-pre1/arch/arm/nwfpe/softfloat.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/arch/arm/nwfpe/softfloat.c	Thu Feb 28 13:34:18 2002
@@ -28,6 +28,7 @@
 ===============================================================================
 */
 
+#include "fpa11.h"
 #include "milieu.h"
 #include "softfloat.h"
 
@@ -753,277 +754,6 @@
 
 #endif
 
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-Returns the least-significant 64 fraction bits of the quadruple-precision
-floating-point value `a'.
--------------------------------------------------------------------------------
-*/
-INLINE bits64 extractFloat128Frac1( float128 a )
-{
-
-    return a.low;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the most-significant 48 fraction bits of the quadruple-precision
-floating-point value `a'.
--------------------------------------------------------------------------------
-*/
-INLINE bits64 extractFloat128Frac0( float128 a )
-{
-
-    return a.high & LIT64( 0x0000FFFFFFFFFFFF );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the exponent bits of the quadruple-precision floating-point value
-`a'.
--------------------------------------------------------------------------------
-*/
-INLINE int32 extractFloat128Exp( float128 a )
-{
-
-    return ( a.high>>48 ) & 0x7FFF;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the sign bit of the quadruple-precision floating-point value `a'.
--------------------------------------------------------------------------------
-*/
-INLINE flag extractFloat128Sign( float128 a )
-{
-
-    return a.high>>63;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Normalizes the subnormal quadruple-precision floating-point value
-represented by the denormalized significand formed by the concatenation of
-`aSig0' and `aSig1'.  The normalized exponent is stored at the location
-pointed to by `zExpPtr'.  The most significant 49 bits of the normalized
-significand are stored at the location pointed to by `zSig0Ptr', and the
-least significant 64 bits of the normalized significand are stored at the
-location pointed to by `zSig1Ptr'.
--------------------------------------------------------------------------------
-*/
-static void
- normalizeFloat128Subnormal(
-     bits64 aSig0,
-     bits64 aSig1,
-     int32 *zExpPtr,
-     bits64 *zSig0Ptr,
-     bits64 *zSig1Ptr
- )
-{
-    int8 shiftCount;
-
-    if ( aSig0 == 0 ) {
-        shiftCount = countLeadingZeros64( aSig1 ) - 15;
-        if ( shiftCount < 0 ) {
-            *zSig0Ptr = aSig1>>( - shiftCount );
-            *zSig1Ptr = aSig1<<( shiftCount & 63 );
-        }
-        else {
-            *zSig0Ptr = aSig1<<shiftCount;
-            *zSig1Ptr = 0;
-        }
-        *zExpPtr = - shiftCount - 63;
-    }
-    else {
-        shiftCount = countLeadingZeros64( aSig0 ) - 15;
-        shortShift128Left( aSig0, aSig1, shiftCount, zSig0Ptr, zSig1Ptr );
-        *zExpPtr = 1 - shiftCount;
-    }
-
-}
-
-/*
--------------------------------------------------------------------------------
-Packs the sign `zSign', the exponent `zExp', and the significand formed
-by the concatenation of `zSig0' and `zSig1' into a quadruple-precision
-floating-point value, returning the result.  After being shifted into the
-proper positions, the three fields `zSign', `zExp', and `zSig0' are simply
-added together to form the most significant 32 bits of the result.  This
-means that any integer portion of `zSig0' will be added into the exponent.
-Since a properly normalized significand will have an integer portion equal
-to 1, the `zExp' input should be 1 less than the desired result exponent
-whenever `zSig0' and `zSig1' concatenated form a complete, normalized
-significand.
--------------------------------------------------------------------------------
-*/
-INLINE float128
- packFloat128( flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
-{
-    float128 z;
-
-    z.low = zSig1;
-    z.high = ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<48 ) + zSig0;
-    return z;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Takes an abstract floating-point value having sign `zSign', exponent `zExp',
-and extended significand formed by the concatenation of `zSig0', `zSig1',
-and `zSig2', and returns the proper quadruple-precision floating-point value
-corresponding to the abstract input.  Ordinarily, the abstract value is
-simply rounded and packed into the quadruple-precision format, with the
-inexact exception raised if the abstract input cannot be represented
-exactly.  If the abstract value is too large, however, the overflow and
-inexact exceptions are raised and an infinity or maximal finite value is
-returned.  If the abstract value is too small, the input value is rounded to
-a subnormal number, and the underflow and inexact exceptions are raised if
-the abstract input cannot be represented exactly as a subnormal quadruple-
-precision floating-point number.
-    The input significand must be normalized or smaller.  If the input
-significand is not normalized, `zExp' must be 0; in that case, the result
-returned is a subnormal number, and it must not require rounding.  In the
-usual case that the input significand is normalized, `zExp' must be 1 less
-than the ``true'' floating-point exponent.  The handling of underflow and
-overflow follows the IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-static float128
- roundAndPackFloat128(
-     flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1, bits64 zSig2 )
-{
-    int8 roundingMode;
-    flag roundNearestEven, increment, isTiny;
-
-    roundingMode = float_rounding_mode;
-    roundNearestEven = ( roundingMode == float_round_nearest_even );
-    increment = ( (sbits64) zSig2 < 0 );
-    if ( ! roundNearestEven ) {
-        if ( roundingMode == float_round_to_zero ) {
-            increment = 0;
-        }
-        else {
-            if ( zSign ) {
-                increment = ( roundingMode == float_round_down ) && zSig2;
-            }
-            else {
-                increment = ( roundingMode == float_round_up ) && zSig2;
-            }
-        }
-    }
-    if ( 0x7FFD <= (bits32) zExp ) {
-        if (    ( 0x7FFD < zExp )
-             || (    ( zExp == 0x7FFD )
-                  && eq128(
-                         LIT64( 0x0001FFFFFFFFFFFF ),
-                         LIT64( 0xFFFFFFFFFFFFFFFF ),
-                         zSig0,
-                         zSig1
-                     )
-                  && increment
-                )
-           ) {
-            float_raise( float_flag_overflow | float_flag_inexact );
-            if (    ( roundingMode == float_round_to_zero )
-                 || ( zSign && ( roundingMode == float_round_up ) )
-                 || ( ! zSign && ( roundingMode == float_round_down ) )
-               ) {
-                return
-                    packFloat128(
-                        zSign,
-                        0x7FFE,
-                        LIT64( 0x0000FFFFFFFFFFFF ),
-                        LIT64( 0xFFFFFFFFFFFFFFFF )
-                    );
-            }
-            return packFloat128( zSign, 0x7FFF, 0, 0 );
-        }
-        if ( zExp < 0 ) {
-            isTiny =
-                   ( float_detect_tininess == float_tininess_before_rounding )
-                || ( zExp < -1 )
-                || ! increment
-                || lt128(
-                       zSig0,
-                       zSig1,
-                       LIT64( 0x0001FFFFFFFFFFFF ),
-                       LIT64( 0xFFFFFFFFFFFFFFFF )
-                   );
-            shift128ExtraRightJamming(
-                zSig0, zSig1, zSig2, - zExp, &zSig0, &zSig1, &zSig2 );
-            zExp = 0;
-            if ( isTiny && zSig2 ) float_raise( float_flag_underflow );
-            if ( roundNearestEven ) {
-                increment = ( (sbits64) zSig2 < 0 );
-            }
-            else {
-                if ( zSign ) {
-                    increment = ( roundingMode == float_round_down ) && zSig2;
-                }
-                else {
-                    increment = ( roundingMode == float_round_up ) && zSig2;
-                }
-            }
-        }
-    }
-    if ( zSig2 ) float_exception_flags |= float_flag_inexact;
-    if ( increment ) {
-        add128( zSig0, zSig1, 0, 1, &zSig0, &zSig1 );
-        zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven );
-    }
-    else {
-        if ( ( zSig0 | zSig1 ) == 0 ) zExp = 0;
-    }
-    return packFloat128( zSign, zExp, zSig0, zSig1 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Takes an abstract floating-point value having sign `zSign', exponent `zExp',
-and significand formed by the concatenation of `zSig0' and `zSig1', and
-returns the proper quadruple-precision floating-point value corresponding to
-the abstract input.  This routine is just like `roundAndPackFloat128' except
-that the input significand has fewer bits and does not have to be normalized
-in any way.  In all cases, `zExp' must be 1 less than the ``true'' floating-
-point exponent.
--------------------------------------------------------------------------------
-*/
-static float128
- normalizeRoundAndPackFloat128(
-     flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
-{
-    int8 shiftCount;
-    bits64 zSig2;
-
-    if ( zSig0 == 0 ) {
-        zSig0 = zSig1;
-        zSig1 = 0;
-        zExp -= 64;
-    }
-    shiftCount = countLeadingZeros64( zSig0 ) - 15;
-    if ( 0 <= shiftCount ) {
-        zSig2 = 0;
-        shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
-    }
-    else {
-        shift128ExtraRightJamming(
-            zSig0, zSig1, 0, - shiftCount, &zSig0, &zSig1, &zSig2 );
-    }
-    zExp -= shiftCount;
-    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
-
-}
-
-#endif
-
 /*
 -------------------------------------------------------------------------------
 Returns the result of converting the 32-bit two's complement integer `a' to
@@ -1093,33 +823,6 @@
 
 #endif
 
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the 32-bit two's complement integer `a' to
-the quadruple-precision floating-point format.  The conversion is performed
-according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 int32_to_float128( int32 a )
-{
-    flag zSign;
-    uint32 absA;
-    int8 shiftCount;
-    bits64 zSig0;
-
-    if ( a == 0 ) return packFloat128( 0, 0, 0, 0 );
-    zSign = ( a < 0 );
-    absA = zSign ? - a : a;
-    shiftCount = countLeadingZeros32( absA ) + 17;
-    zSig0 = absA;
-    return packFloat128( zSign, 0x402E - shiftCount, zSig0<<shiftCount, 0 );
-
-}
-
-#endif
-
 /*
 -------------------------------------------------------------------------------
 Returns the result of converting the single-precision floating-point value
@@ -1256,40 +959,6 @@
 
 #endif
 
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the single-precision floating-point value
-`a' to the double-precision floating-point format.  The conversion is
-performed according to the IEC/IEEE Standard for Binary Floating-point
-Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float32_to_float128( float32 a )
-{
-    flag aSign;
-    int16 aExp;
-    bits32 aSig;
-
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
-    if ( aExp == 0xFF ) {
-        if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a ) );
-        return packFloat128( aSign, 0x7FFF, 0, 0 );
-    }
-    if ( aExp == 0 ) {
-        if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 );
-        normalizeFloat32Subnormal( aSig, &aExp, &aSig );
-        --aExp;
-    }
-    return packFloat128( aSign, aExp + 0x3F80, ( (bits64) aSig )<<25, 0 );
-
-}
-
-#endif
-
 /*
 -------------------------------------------------------------------------------
 Rounds the single-precision floating-point value `a' to an integer, and
@@ -2183,41 +1852,6 @@
 
 #endif
 
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the double-precision floating-point value
-`a' to the quadruple-precision floating-point format.  The conversion is
-performed according to the IEC/IEEE Standard for Binary Floating-point
-Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float64_to_float128( float64 a )
-{
-    flag aSign;
-    int16 aExp;
-    bits64 aSig, zSig0, zSig1;
-
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    aSign = extractFloat64Sign( a );
-    if ( aExp == 0x7FF ) {
-        if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a ) );
-        return packFloat128( aSign, 0x7FFF, 0, 0 );
-    }
-    if ( aExp == 0 ) {
-        if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 );
-        normalizeFloat64Subnormal( aSig, &aExp, &aSig );
-        --aExp;
-    }
-    shift128Right( aSig, 0, 4, &zSig0, &zSig1 );
-    return packFloat128( aSign, aExp + 0x3C00, zSig0, zSig1 );
-
-}
-
-#endif
-
 /*
 -------------------------------------------------------------------------------
 Rounds the double-precision floating-point value `a' to an integer, and
@@ -3029,35 +2663,6 @@
 
 }
 
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the extended double-precision floating-
-point value `a' to the quadruple-precision floating-point format.  The
-conversion is performed according to the IEC/IEEE Standard for Binary
-Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 floatx80_to_float128( floatx80 a )
-{
-    flag aSign;
-    int16 aExp;
-    bits64 aSig, zSig0, zSig1;
-
-    aSig = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    aSign = extractFloatx80Sign( a );
-    if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) {
-        return commonNaNToFloat128( floatx80ToCommonNaN( a ) );
-    }
-    shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 );
-    return packFloat128( aSign, aExp, zSig0, zSig1 );
-
-}
-
-#endif
-
 /*
 -------------------------------------------------------------------------------
 Rounds the extended double-precision floating-point value `a' to an integer,
@@ -3825,1048 +3430,6 @@
                  != 0 );
     }
     return
-          aSign ? lt128( b.high, b.low, a.high, a.low )
-        : lt128( a.high, a.low, b.high, b.low );
-
-}
-
-#endif
-
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the quadruple-precision floating-point
-value `a' to the 32-bit two's complement integer format.  The conversion
-is performed according to the IEC/IEEE Standard for Binary Floating-point
-Arithmetic---which means in particular that the conversion is rounded
-according to the current rounding mode.  If `a' is a NaN, the largest
-positive integer is returned.  Otherwise, if the conversion overflows, the
-largest integer with the same sign as `a' is returned.
--------------------------------------------------------------------------------
-*/
-int32 float128_to_int32( float128 a )
-{
-    flag aSign;
-    int32 aExp, shiftCount;
-    bits64 aSig0, aSig1;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0;
-    if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
-    aSig0 |= ( aSig1 != 0 );
-    shiftCount = 0x4028 - aExp;
-    if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 );
-    return roundAndPackInt32( aSign, aSig0 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the quadruple-precision floating-point
-value `a' to the 32-bit two's complement integer format.  The conversion
-is performed according to the IEC/IEEE Standard for Binary Floating-point
-Arithmetic, except that the conversion is always rounded toward zero.  If
-`a' is a NaN, the largest positive integer is returned.  Otherwise, if the
-conversion overflows, the largest integer with the same sign as `a' is
-returned.
--------------------------------------------------------------------------------
-*/
-int32 float128_to_int32_round_to_zero( float128 a )
-{
-    flag aSign;
-    int32 aExp, shiftCount;
-    bits64 aSig0, aSig1, savedASig;
-    int32 z;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    aSig0 |= ( aSig1 != 0 );
-    shiftCount = 0x402F - aExp;
-    if ( shiftCount < 17 ) {
-        if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0;
-        goto invalid;
-    }
-    else if ( 48 < shiftCount ) {
-        if ( aExp || aSig0 ) float_exception_flags |= float_flag_inexact;
-        return 0;
-    }
-    aSig0 |= LIT64( 0x0001000000000000 );
-    savedASig = aSig0;
-    aSig0 >>= shiftCount;
-    z = aSig0;
-    if ( aSign ) z = - z;
-    if ( ( z < 0 ) ^ aSign ) {
- invalid:
-        float_exception_flags |= float_flag_invalid;
-        return aSign ? 0x80000000 : 0x7FFFFFFF;
-    }
-    if ( ( aSig0<<shiftCount ) != savedASig ) {
-        float_exception_flags |= float_flag_inexact;
-    }
-    return z;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the quadruple-precision floating-point
-value `a' to the single-precision floating-point format.  The conversion
-is performed according to the IEC/IEEE Standard for Binary Floating-point
-Arithmetic.
--------------------------------------------------------------------------------
-*/
-float32 float128_to_float32( float128 a )
-{
-    flag aSign;
-    int32 aExp;
-    bits64 aSig0, aSig1;
-    bits32 zSig;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    if ( aExp == 0x7FFF ) {
-        if ( aSig0 | aSig1 ) {
-            return commonNaNToFloat32( float128ToCommonNaN( a ) );
-        }
-        return packFloat32( aSign, 0xFF, 0 );
-    }
-    aSig0 |= ( aSig1 != 0 );
-    shift64RightJamming( aSig0, 18, &aSig0 );
-    zSig = aSig0;
-    if ( aExp || zSig ) {
-        zSig |= 0x40000000;
-        aExp -= 0x3F81;
-    }
-    return roundAndPackFloat32( aSign, aExp, zSig );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the quadruple-precision floating-point
-value `a' to the double-precision floating-point format.  The conversion
-is performed according to the IEC/IEEE Standard for Binary Floating-point
-Arithmetic.
--------------------------------------------------------------------------------
-*/
-float64 float128_to_float64( float128 a )
-{
-    flag aSign;
-    int32 aExp;
-    bits64 aSig0, aSig1;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    if ( aExp == 0x7FFF ) {
-        if ( aSig0 | aSig1 ) {
-            return commonNaNToFloat64( float128ToCommonNaN( a ) );
-        }
-        return packFloat64( aSign, 0x7FF, 0 );
-    }
-    shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
-    aSig0 |= ( aSig1 != 0 );
-    if ( aExp || aSig0 ) {
-        aSig0 |= LIT64( 0x4000000000000000 );
-        aExp -= 0x3C01;
-    }
-    return roundAndPackFloat64( aSign, aExp, aSig0 );
-
-}
-
-#ifdef FLOATX80
-
-/*
--------------------------------------------------------------------------------
-Returns the result of converting the quadruple-precision floating-point
-value `a' to the extended double-precision floating-point format.  The
-conversion is performed according to the IEC/IEEE Standard for Binary
-Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-floatx80 float128_to_floatx80( float128 a )
-{
-    flag aSign;
-    int32 aExp;
-    bits64 aSig0, aSig1;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    if ( aExp == 0x7FFF ) {
-        if ( aSig0 | aSig1 ) {
-            return commonNaNToFloatx80( float128ToCommonNaN( a ) );
-        }
-        return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
-    }
-    if ( aExp == 0 ) {
-        if ( ( aSig0 | aSig1 ) == 0 ) return packFloatx80( aSign, 0, 0 );
-        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
-    }
-    else {
-        aSig0 |= LIT64( 0x0001000000000000 );
-    }
-    shortShift128Left( aSig0, aSig1, 15, &aSig0, &aSig1 );
-    return roundAndPackFloatx80( 80, aSign, aExp, aSig0, aSig1 );
-
-}
-
-#endif
-
-/*
--------------------------------------------------------------------------------
-Rounds the quadruple-precision floating-point value `a' to an integer, and
-returns the result as a quadruple-precision floating-point value.  The
-operation is performed according to the IEC/IEEE Standard for Binary
-Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float128_round_to_int( float128 a )
-{
-    flag aSign;
-    int32 aExp;
-    bits64 lastBitMask, roundBitsMask;
-    int8 roundingMode;
-    float128 z;
-
-    aExp = extractFloat128Exp( a );
-    if ( 0x402F <= aExp ) {
-        if ( 0x406F <= aExp ) {
-            if (    ( aExp == 0x7FFF )
-                 && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) )
-               ) {
-                return propagateFloat128NaN( a, a );
-            }
-            return a;
-        }
-        lastBitMask = 1;
-        lastBitMask = ( lastBitMask<<( 0x406E - aExp ) )<<1;
-        roundBitsMask = lastBitMask - 1;
-        z = a;
-        roundingMode = float_rounding_mode;
-        if ( roundingMode == float_round_nearest_even ) {
-            if ( lastBitMask ) {
-                add128( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low );
-                if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
-            }
-            else {
-                if ( (sbits64) z.low < 0 ) {
-                    ++z.high;
-                    if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1;
-                }
-            }
-        }
-        else if ( roundingMode != float_round_to_zero ) {
-            if (   extractFloat128Sign( z )
-                 ^ ( roundingMode == float_round_up ) ) {
-                add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low );
-            }
-        }
-        z.low &= ~ roundBitsMask;
-    }
-    else {
-        if ( aExp <= 0x3FFE ) {
-            if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a;
-            float_exception_flags |= float_flag_inexact;
-            aSign = extractFloat128Sign( a );
-            switch ( float_rounding_mode ) {
-             case float_round_nearest_even:
-                if (    ( aExp == 0x3FFE )
-                     && (   extractFloat128Frac0( a )
-                          | extractFloat128Frac1( a ) )
-                   ) {
-                    return packFloat128( aSign, 0x3FFF, 0, 0 );
-                }
-                break;
-             case float_round_down:
-                return
-                      aSign ? packFloat128( 1, 0x3FFF, 0, 0 )
-                    : packFloat128( 0, 0, 0, 0 );
-             case float_round_up:
-                return
-                      aSign ? packFloat128( 1, 0, 0, 0 )
-                    : packFloat128( 0, 0x3FFF, 0, 0 );
-            }
-            return packFloat128( aSign, 0, 0, 0 );
-        }
-        lastBitMask = 1;
-        lastBitMask <<= 0x402F - aExp;
-        roundBitsMask = lastBitMask - 1;
-        z.low = 0;
-        z.high = a.high;
-        roundingMode = float_rounding_mode;
-        if ( roundingMode == float_round_nearest_even ) {
-            z.high += lastBitMask>>1;
-            if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) {
-                z.high &= ~ lastBitMask;
-            }
-        }
-        else if ( roundingMode != float_round_to_zero ) {
-            if (   extractFloat128Sign( z )
-                 ^ ( roundingMode == float_round_up ) ) {
-                z.high |= ( a.low != 0 );
-                z.high += roundBitsMask;
-            }
-        }
-        z.high &= ~ roundBitsMask;
-    }
-    if ( ( z.low != a.low ) || ( z.high != a.high ) ) {
-        float_exception_flags |= float_flag_inexact;
-    }
-    return z;
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of adding the absolute values of the quadruple-precision
-floating-point values `a' and `b'.  If `zSign' is true, the sum is negated
-before being returned.  `zSign' is ignored if the result is a NaN.  The
-addition is performed according to the IEC/IEEE Standard for Binary
-Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-static float128 addFloat128Sigs( float128 a, float128 b, flag zSign )
-{
-    int32 aExp, bExp, zExp;
-    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
-    int32 expDiff;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    bSig1 = extractFloat128Frac1( b );
-    bSig0 = extractFloat128Frac0( b );
-    bExp = extractFloat128Exp( b );
-    expDiff = aExp - bExp;
-    if ( 0 < expDiff ) {
-        if ( aExp == 0x7FFF ) {
-            if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
-            return a;
-        }
-        if ( bExp == 0 ) {
-            --expDiff;
-        }
-        else {
-            bSig0 |= LIT64( 0x0001000000000000 );
-        }
-        shift128ExtraRightJamming(
-            bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 );
-        zExp = aExp;
-    }
-    else if ( expDiff < 0 ) {
-        if ( bExp == 0x7FFF ) {
-            if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
-            return packFloat128( zSign, 0x7FFF, 0, 0 );
-        }
-        if ( aExp == 0 ) {
-            ++expDiff;
-        }
-        else {
-            aSig0 |= LIT64( 0x0001000000000000 );
-        }
-        shift128ExtraRightJamming(
-            aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 );
-        zExp = bExp;
-    }
-    else {
-        if ( aExp == 0x7FFF ) {
-            if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
-                return propagateFloat128NaN( a, b );
-            }
-            return a;
-        }
-        add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
-        if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 );
-        zSig2 = 0;
-        zSig0 |= LIT64( 0x0002000000000000 );
-        zExp = aExp;
-        goto shiftRight1;
-    }
-    aSig0 |= LIT64( 0x0001000000000000 );
-    add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
-    --zExp;
-    if ( zSig0 < LIT64( 0x0002000000000000 ) ) goto roundAndPack;
-    ++zExp;
- shiftRight1:
-    shift128ExtraRightJamming(
-        zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
- roundAndPack:
-    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of subtracting the absolute values of the quadruple-
-precision floating-point values `a' and `b'.  If `zSign' is true, the
-difference is negated before being returned.  `zSign' is ignored if the
-result is a NaN.  The subtraction is performed according to the IEC/IEEE
-Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-static float128 subFloat128Sigs( float128 a, float128 b, flag zSign )
-{
-    int32 aExp, bExp, zExp;
-    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
-    int32 expDiff;
-    float128 z;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    bSig1 = extractFloat128Frac1( b );
-    bSig0 = extractFloat128Frac0( b );
-    bExp = extractFloat128Exp( b );
-    expDiff = aExp - bExp;
-    shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
-    shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 );
-    if ( 0 < expDiff ) goto aExpBigger;
-    if ( expDiff < 0 ) goto bExpBigger;
-    if ( aExp == 0x7FFF ) {
-        if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
-            return propagateFloat128NaN( a, b );
-        }
-        float_raise( float_flag_invalid );
-        z.low = float128_default_nan_low;
-        z.high = float128_default_nan_high;
-        return z;
-    }
-    if ( aExp == 0 ) {
-        aExp = 1;
-        bExp = 1;
-    }
-    if ( bSig0 < aSig0 ) goto aBigger;
-    if ( aSig0 < bSig0 ) goto bBigger;
-    if ( bSig1 < aSig1 ) goto aBigger;
-    if ( aSig1 < bSig1 ) goto bBigger;
-    return packFloat128( float_rounding_mode == float_round_down, 0, 0, 0 );
- bExpBigger:
-    if ( bExp == 0x7FFF ) {
-        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
-        return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 );
-    }
-    if ( aExp == 0 ) {
-        ++expDiff;
-    }
-    else {
-        aSig0 |= LIT64( 0x4000000000000000 );
-    }
-    shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
-    bSig0 |= LIT64( 0x4000000000000000 );
- bBigger:
-    sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 );
-    zExp = bExp;
-    zSign ^= 1;
-    goto normalizeRoundAndPack;
- aExpBigger:
-    if ( aExp == 0x7FFF ) {
-        if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
-        return a;
-    }
-    if ( bExp == 0 ) {
-        --expDiff;
-    }
-    else {
-        bSig0 |= LIT64( 0x4000000000000000 );
-    }
-    shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 );
-    aSig0 |= LIT64( 0x4000000000000000 );
- aBigger:
-    sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
-    zExp = aExp;
- normalizeRoundAndPack:
-    --zExp;
-    return normalizeRoundAndPackFloat128( zSign, zExp - 14, zSig0, zSig1 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of adding the quadruple-precision floating-point values
-`a' and `b'.  The operation is performed according to the IEC/IEEE Standard
-for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float128_add( float128 a, float128 b )
-{
-    flag aSign, bSign;
-
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
-    if ( aSign == bSign ) {
-        return addFloat128Sigs( a, b, aSign );
-    }
-    else {
-        return subFloat128Sigs( a, b, aSign );
-    }
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of subtracting the quadruple-precision floating-point
-values `a' and `b'.  The operation is performed according to the IEC/IEEE
-Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float128_sub( float128 a, float128 b )
-{
-    flag aSign, bSign;
-
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
-    if ( aSign == bSign ) {
-        return subFloat128Sigs( a, b, aSign );
-    }
-    else {
-        return addFloat128Sigs( a, b, aSign );
-    }
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of multiplying the quadruple-precision floating-point
-values `a' and `b'.  The operation is performed according to the IEC/IEEE
-Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float128_mul( float128 a, float128 b )
-{
-    flag aSign, bSign, zSign;
-    int32 aExp, bExp, zExp;
-    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
-    float128 z;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    bSig1 = extractFloat128Frac1( b );
-    bSig0 = extractFloat128Frac0( b );
-    bExp = extractFloat128Exp( b );
-    bSign = extractFloat128Sign( b );
-    zSign = aSign ^ bSign;
-    if ( aExp == 0x7FFF ) {
-        if (    ( aSig0 | aSig1 )
-             || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
-            return propagateFloat128NaN( a, b );
-        }
-        if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid;
-        return packFloat128( zSign, 0x7FFF, 0, 0 );
-    }
-    if ( bExp == 0x7FFF ) {
-        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
-        if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
- invalid:
-            float_raise( float_flag_invalid );
-            z.low = float128_default_nan_low;
-            z.high = float128_default_nan_high;
-            return z;
-        }
-        return packFloat128( zSign, 0x7FFF, 0, 0 );
-    }
-    if ( aExp == 0 ) {
-        if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
-        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
-    }
-    if ( bExp == 0 ) {
-        if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
-        normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
-    }
-    zExp = aExp + bExp - 0x4000;
-    aSig0 |= LIT64( 0x0001000000000000 );
-    shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 );
-    mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 );
-    add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 );
-    zSig2 |= ( zSig3 != 0 );
-    if ( LIT64( 0x0002000000000000 ) <= zSig0 ) {
-        shift128ExtraRightJamming(
-            zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
-        ++zExp;
-    }
-    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the result of dividing the quadruple-precision floating-point value
-`a' by the corresponding value `b'.  The operation is performed according to
-the IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float128_div( float128 a, float128 b )
-{
-    flag aSign, bSign, zSign;
-    int32 aExp, bExp, zExp;
-    bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
-    bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
-    float128 z;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    bSig1 = extractFloat128Frac1( b );
-    bSig0 = extractFloat128Frac0( b );
-    bExp = extractFloat128Exp( b );
-    bSign = extractFloat128Sign( b );
-    zSign = aSign ^ bSign;
-    if ( aExp == 0x7FFF ) {
-        if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
-        if ( bExp == 0x7FFF ) {
-            if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
-            goto invalid;
-        }
-        return packFloat128( zSign, 0x7FFF, 0, 0 );
-    }
-    if ( bExp == 0x7FFF ) {
-        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
-        return packFloat128( zSign, 0, 0, 0 );
-    }
-    if ( bExp == 0 ) {
-        if ( ( bSig0 | bSig1 ) == 0 ) {
-            if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
- invalid:
-                float_raise( float_flag_invalid );
-                z.low = float128_default_nan_low;
-                z.high = float128_default_nan_high;
-                return z;
-            }
-            float_raise( float_flag_divbyzero );
-            return packFloat128( zSign, 0x7FFF, 0, 0 );
-        }
-        normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
-    }
-    if ( aExp == 0 ) {
-        if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
-        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
-    }
-    zExp = aExp - bExp + 0x3FFD;
-    shortShift128Left(
-        aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15, &aSig0, &aSig1 );
-    shortShift128Left(
-        bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 );
-    if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) {
-        shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 );
-        ++zExp;
-    }
-    zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 );
-    mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 );
-    sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 );
-    while ( (sbits64) rem0 < 0 ) {
-        --zSig0;
-        add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 );
-    }
-    zSig1 = estimateDiv128To64( rem1, rem2, bSig0 );
-    if ( ( zSig1 & 0x3FFF ) <= 4 ) {
-        mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 );
-        sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 );
-        while ( (sbits64) rem1 < 0 ) {
-            --zSig1;
-            add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 );
-        }
-        zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
-    }
-    shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 );
-    return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the remainder of the quadruple-precision floating-point value `a'
-with respect to the corresponding value `b'.  The operation is performed
-according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float128_rem( float128 a, float128 b )
-{
-    flag aSign, bSign, zSign;
-    int32 aExp, bExp, expDiff;
-    bits64 aSig0, aSig1, bSig0, bSig1;
-    bits64 q, term0, term1, term2, allZero, alternateASig0, alternateASig1;
-    bits64 sigMean1;
-    sbits64 sigMean0;
-    float128 z;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    bSig1 = extractFloat128Frac1( b );
-    bSig0 = extractFloat128Frac0( b );
-    bExp = extractFloat128Exp( b );
-    bSign = extractFloat128Sign( b );
-    if ( aExp == 0x7FFF ) {
-        if (    ( aSig0 | aSig1 )
-             || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
-            return propagateFloat128NaN( a, b );
-        }
-        goto invalid;
-    }
-    if ( bExp == 0x7FFF ) {
-        if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
-        return a;
-    }
-    if ( bExp == 0 ) {
-        if ( ( bSig0 | bSig1 ) == 0 ) {
- invalid:
-            float_raise( float_flag_invalid );
-            z.low = float128_default_nan_low;
-            z.high = float128_default_nan_high;
-            return z;
-        }
-        normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
-    }
-    if ( aExp == 0 ) {
-        if ( ( aSig0 | aSig1 ) == 0 ) return a;
-        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
-    }
-    expDiff = aExp - bExp;
-    if ( expDiff < -1 ) return a;
-    shortShift128Left(
-        aSig0 | LIT64( 0x0001000000000000 ),
-        aSig1,
-        15 - ( expDiff < 0 ),
-        &aSig0,
-        &aSig1
-    );
-    shortShift128Left(
-        bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 );
-    q = le128( bSig0, bSig1, aSig0, aSig1 );
-    if ( q ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
-    expDiff -= 64;
-    while ( 0 < expDiff ) {
-        q = estimateDiv128To64( aSig0, aSig1, bSig0 );
-        q = ( 4 < q ) ? q - 4 : 0;
-        mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 );
-        shortShift192Left( term0, term1, term2, 61, &term1, &term2, &allZero );
-        shortShift128Left( aSig0, aSig1, 61, &aSig0, &allZero );
-        sub128( aSig0, 0, term1, term2, &aSig0, &aSig1 );
-        expDiff -= 61;
-    }
-    if ( -64 < expDiff ) {
-        q = estimateDiv128To64( aSig0, aSig1, bSig0 );
-        q = ( 4 < q ) ? q - 4 : 0;
-        q >>= - expDiff;
-        shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 );
-        expDiff += 52;
-        if ( expDiff < 0 ) {
-            shift128Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
-        }
-        else {
-            shortShift128Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 );
-        }
-        mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 );
-        sub128( aSig0, aSig1, term1, term2, &aSig0, &aSig1 );
-    }
-    else {
-        shift128Right( aSig0, aSig1, 12, &aSig0, &aSig1 );
-        shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 );
-    }
-    do {
-        alternateASig0 = aSig0;
-        alternateASig1 = aSig1;
-        ++q;
-        sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
-    } while ( 0 <= (sbits64) aSig0 );
-    add128(
-        aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 );
-    if (    ( sigMean0 < 0 )
-         || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) {
-        aSig0 = alternateASig0;
-        aSig1 = alternateASig1;
-    }
-    zSign = ( (sbits64) aSig0 < 0 );
-    if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 );
-    return
-        normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns the square root of the quadruple-precision floating-point value `a'.
-The operation is performed according to the IEC/IEEE Standard for Binary
-Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-float128 float128_sqrt( float128 a )
-{
-    flag aSign;
-    int32 aExp, zExp;
-    bits64 aSig0, aSig1, zSig0, zSig1, zSig2;
-    bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
-    bits64 shiftedRem0, shiftedRem1;
-    float128 z;
-
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    if ( aExp == 0x7FFF ) {
-        if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a );
-        if ( ! aSign ) return a;
-        goto invalid;
-    }
-    if ( aSign ) {
-        if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a;
- invalid:
-        float_raise( float_flag_invalid );
-        z.low = float128_default_nan_low;
-        z.high = float128_default_nan_high;
-        return z;
-    }
-    if ( aExp == 0 ) {
-        if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 );
-        normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
-    }
-    zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFE;
-    aSig0 |= LIT64( 0x0001000000000000 );
-    zSig0 = estimateSqrt32( aExp, aSig0>>17 );
-    zSig0 <<= 31;
-    shortShift128Left( aSig0, aSig1, 13 - ( aExp & 1 ), &aSig0, &aSig1 );
-    zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0 ) + zSig0 + 4;
-    if ( 0 <= (sbits64) zSig0 ) zSig0 = LIT64( 0xFFFFFFFFFFFFFFFF );
-    shortShift128Left( aSig0, aSig1, 2, &aSig0, &aSig1 );
-    mul64To128( zSig0, zSig0, &term0, &term1 );
-    sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 );
-    while ( (sbits64) rem0 < 0 ) {
-        --zSig0;
-        shortShift128Left( 0, zSig0, 1, &term0, &term1 );
-        term1 |= 1;
-        add128( rem0, rem1, term0, term1, &rem0, &rem1 );
-    }
-    shortShift128Left( rem0, rem1, 63, &shiftedRem0, &shiftedRem1 );
-    zSig1 = estimateDiv128To64( shiftedRem0, shiftedRem1, zSig0 );
-    if ( ( zSig1 & 0x3FFF ) <= 5 ) {
-        if ( zSig1 == 0 ) zSig1 = 1;
-        mul64To128( zSig0, zSig1, &term1, &term2 );
-        shortShift128Left( term1, term2, 1, &term1, &term2 );
-        sub128( rem1, 0, term1, term2, &rem1, &rem2 );
-        mul64To128( zSig1, zSig1, &term2, &term3 );
-        sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
-        while ( (sbits64) rem1 < 0 ) {
-            --zSig1;
-            shortShift192Left( 0, zSig0, zSig1, 1, &term1, &term2, &term3 );
-            term3 |= 1;
-            add192(
-                rem1, rem2, rem3, term1, term2, term3, &rem1, &rem2, &rem3 );
-        }
-        zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
-    }
-    shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 );
-    return roundAndPackFloat128( 0, zExp, zSig0, zSig1, zSig2 );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is equal to
-the corresponding value `b', and 0 otherwise.  The comparison is performed
-according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-flag float128_eq( float128 a, float128 b )
-{
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
-       ) {
-        if (    float128_is_signaling_nan( a )
-             || float128_is_signaling_nan( b ) ) {
-            float_raise( float_flag_invalid );
-        }
-        return 0;
-    }
-    return
-           ( a.low == b.low )
-        && (    ( a.high == b.high )
-             || (    ( a.low == 0 )
-                  && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) )
-           );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is less than
-or equal to the corresponding value `b', and 0 otherwise.  The comparison
-is performed according to the IEC/IEEE Standard for Binary Floating-point
-Arithmetic.
--------------------------------------------------------------------------------
-*/
-flag float128_le( float128 a, float128 b )
-{
-    flag aSign, bSign;
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
-       ) {
-        float_raise( float_flag_invalid );
-        return 0;
-    }
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
-    if ( aSign != bSign ) {
-        return
-               aSign
-            || (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
-                 == 0 );
-    }
-    return
-          aSign ? le128( b.high, b.low, a.high, a.low )
-        : le128( a.high, a.low, b.high, b.low );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is less than
-the corresponding value `b', and 0 otherwise.  The comparison is performed
-according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-flag float128_lt( float128 a, float128 b )
-{
-    flag aSign, bSign;
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
-       ) {
-        float_raise( float_flag_invalid );
-        return 0;
-    }
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
-    if ( aSign != bSign ) {
-        return
-               aSign
-            && (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
-                 != 0 );
-    }
-    return
-          aSign ? lt128( b.high, b.low, a.high, a.low )
-        : lt128( a.high, a.low, b.high, b.low );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is equal to
-the corresponding value `b', and 0 otherwise.  The invalid exception is
-raised if either operand is a NaN.  Otherwise, the comparison is performed
-according to the IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-flag float128_eq_signaling( float128 a, float128 b )
-{
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
-       ) {
-        float_raise( float_flag_invalid );
-        return 0;
-    }
-    return
-           ( a.low == b.low )
-        && (    ( a.high == b.high )
-             || (    ( a.low == 0 )
-                  && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) )
-           );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is less than
-or equal to the corresponding value `b', and 0 otherwise.  Quiet NaNs do not
-cause an exception.  Otherwise, the comparison is performed according to the
-IEC/IEEE Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-flag float128_le_quiet( float128 a, float128 b )
-{
-    flag aSign, bSign;
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
-       ) {
-        if (    float128_is_signaling_nan( a )
-             || float128_is_signaling_nan( b ) ) {
-            float_raise( float_flag_invalid );
-        }
-        return 0;
-    }
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
-    if ( aSign != bSign ) {
-        return
-               aSign
-            || (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
-                 == 0 );
-    }
-    return
-          aSign ? le128( b.high, b.low, a.high, a.low )
-        : le128( a.high, a.low, b.high, b.low );
-
-}
-
-/*
--------------------------------------------------------------------------------
-Returns 1 if the quadruple-precision floating-point value `a' is less than
-the corresponding value `b', and 0 otherwise.  Quiet NaNs do not cause an
-exception.  Otherwise, the comparison is performed according to the IEC/IEEE
-Standard for Binary Floating-point Arithmetic.
--------------------------------------------------------------------------------
-*/
-flag float128_lt_quiet( float128 a, float128 b )
-{
-    flag aSign, bSign;
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
-       ) {
-        if (    float128_is_signaling_nan( a )
-             || float128_is_signaling_nan( b ) ) {
-            float_raise( float_flag_invalid );
-        }
-        return 0;
-    }
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
-    if ( aSign != bSign ) {
-        return
-               aSign
-            && (    ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
-                 != 0 );
-    }
-    return
           aSign ? lt128( b.high, b.low, a.high, a.low )
         : lt128( a.high, a.low, b.high, b.low );
 
diff -urN linux-2.5.6-pre1/arch/arm/nwfpe/softfloat.h linux-2.5.6-pre2/arch/arm/nwfpe/softfloat.h
--- linux-2.5.6-pre1/arch/arm/nwfpe/softfloat.h	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/arch/arm/nwfpe/softfloat.h	Thu Feb 28 13:34:18 2002
@@ -37,12 +37,10 @@
 The macro `FLOATX80' must be defined to enable the extended double-precision
 floating-point format `floatx80'.  If this macro is not defined, the
 `floatx80' type will not be defined, and none of the functions that either
-input or output the `floatx80' type will be defined.  The same applies to
-the `FLOAT128' macro and the quadruple-precision format `float128'.
+input or output the `floatx80' type will be defined.
 -------------------------------------------------------------------------------
 */
 #define FLOATX80
-/* #define FLOAT128 */
 
 /*
 -------------------------------------------------------------------------------
@@ -51,17 +49,10 @@
 */
 typedef unsigned long int float32;
 typedef unsigned long long float64;
-#ifdef FLOATX80
 typedef struct {
     unsigned short high;
     unsigned long long low;
 } floatx80;
-#endif
-#ifdef FLOAT128
-typedef struct {
-    unsigned long long high, low;
-} float128;
-#endif
 
 /*
 -------------------------------------------------------------------------------
@@ -131,9 +122,6 @@
 #ifdef FLOATX80
 floatx80 int32_to_floatx80( signed int );
 #endif
-#ifdef FLOAT128
-float128 int32_to_float128( signed int );
-#endif
 
 /*
 -------------------------------------------------------------------------------
@@ -146,9 +134,6 @@
 #ifdef FLOATX80
 floatx80 float32_to_floatx80( float32 );
 #endif
-#ifdef FLOAT128
-float128 float32_to_float128( float32 );
-#endif
 
 /*
 -------------------------------------------------------------------------------
@@ -181,9 +166,6 @@
 #ifdef FLOATX80
 floatx80 float64_to_floatx80( float64 );
 #endif
-#ifdef FLOAT128
-float128 float64_to_float128( float64 );
-#endif
 
 /*
 -------------------------------------------------------------------------------
@@ -216,9 +198,6 @@
 signed int floatx80_to_int32_round_to_zero( floatx80 );
 float32 floatx80_to_float32( floatx80 );
 float64 floatx80_to_float64( floatx80 );
-#ifdef FLOAT128
-float128 floatx80_to_float128( floatx80 );
-#endif
 
 /*
 -------------------------------------------------------------------------------
@@ -250,41 +229,4 @@
 
 #endif
 
-#ifdef FLOAT128
-
-/*
--------------------------------------------------------------------------------
-Software IEC/IEEE quadruple-precision conversion routines.
--------------------------------------------------------------------------------
-*/
-signed int float128_to_int32( float128 );
-signed int float128_to_int32_round_to_zero( float128 );
-float32 float128_to_float32( float128 );
-float64 float128_to_float64( float128 );
-#ifdef FLOATX80
-floatx80 float128_to_floatx80( float128 );
-#endif
-
-/*
--------------------------------------------------------------------------------
-Software IEC/IEEE quadruple-precision operations.
--------------------------------------------------------------------------------
-*/
-float128 float128_round_to_int( float128 );
-float128 float128_add( float128, float128 );
-float128 float128_sub( float128, float128 );
-float128 float128_mul( float128, float128 );
-float128 float128_div( float128, float128 );
-float128 float128_rem( float128, float128 );
-float128 float128_sqrt( float128 );
-char float128_eq( float128, float128 );
-char float128_le( float128, float128 );
-char float128_lt( float128, float128 );
-char float128_eq_signaling( float128, float128 );
-char float128_le_quiet( float128, float128 );
-char float128_lt_quiet( float128, float128 );
-char float128_is_signaling_nan( float128 );
-
-#endif
-
 #endif
diff -urN linux-2.5.6-pre1/arch/arm/tools/mach-types linux-2.5.6-pre2/arch/arm/tools/mach-types
--- linux-2.5.6-pre1/arch/arm/tools/mach-types	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/arch/arm/tools/mach-types	Thu Feb 28 13:34:18 2002
@@ -6,7 +6,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Fri Jan 4 10:27:21 2002
+# Last update: Sun Feb 24 17:43:42 2002
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -118,10 +118,10 @@
 cdb89712		ARCH_CDB89712		CDB89712		107
 graphicsmaster		SA1100_GRAPHICSMASTER	GRAPHICSMASTER		108
 adsbitsy		SA1100_ADSBITSY		ADSBITSY		109
-cotulla_idp		ARCH_COTULLA_IDP	COTULLA_IDP		110
+pxa_idp			ARCH_PXA_IDP		PXA_IDP			110
 plce			ARCH_PLCE		PLCE			111
 pt_system3		SA1100_PT_SYSTEM3	PT_SYSTEM3		112
-medalb			ARCH_MEDALB		MEDALB			113
+murphy			ARCH_MEDALB		MEDALB			113
 eagle			ARCH_EAGLE		EAGLE			114
 dsc21			ARCH_DSC21		DSC21			115
 dsc24			ARCH_DSC24		DSC24			116
@@ -162,3 +162,15 @@
 cep			SA1100_CEP		CEP			151
 fortunet		ARCH_FORTUNET		FORTUNET		152
 vc547x			ARCH_VC547X		VC547X			153
+filewalker		SA1100_FILEWALKER	FILEWALKER		154
+netgateway		SA1100_NETGATEWAY	NETGATEWAY		155
+symbol2800		SA1100_SYMBOL2800	SYMBOL2800		156
+suns			SA1100_SUNS		SUNS			157
+frodo			SA1100_FRODO		FRODO			158
+ms301			SA1100_MACH_TYTE_MS301	MACH_TYTE_MS301		159
+mx1ads			ARCH_MX1ADS		MX1ADS			160
+h7201			ARCH_H7201		H7201			161
+h7202			ARCH_H7202		H7202			162
+amico			ARCH_AMICO		AMICO			163
+iam			SA1100_IAM		IAM			164
+tt530			SA1100_TT530		TT530			165
diff -urN linux-2.5.6-pre1/arch/i386/defconfig linux-2.5.6-pre2/arch/i386/defconfig
--- linux-2.5.6-pre1/arch/i386/defconfig	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/arch/i386/defconfig	Thu Feb 28 13:34:18 2002
@@ -105,6 +105,7 @@
 # CONFIG_HOTPLUG_PCI is not set
 # CONFIG_HOTPLUG_PCI_COMPAQ is not set
 # CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+# CONFIG_HOTPLUG_PCI_IBM is not set
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
 CONFIG_BINFMT_AOUT=y
@@ -132,7 +133,7 @@
 # CONFIG_PARPORT_GSC is not set
 # CONFIG_PARPORT_SUNBPP is not set
 # CONFIG_PARPORT_OTHER is not set
-CONFIG_PARPORT_1284=y
+# CONFIG_PARPORT_1284 is not set
 
 #
 # Plug and Play configuration
@@ -685,6 +686,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
@@ -727,13 +729,14 @@
 # Advanced Linux Sound Architecture
 #
 CONFIG_SND=y
-# CONFIG_SND_RTCTIMER is not set
 CONFIG_SND_SEQUENCER=y
 # CONFIG_SND_SEQ_DUMMY is not set
 CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=y
 CONFIG_SND_PCM_OSS=y
 CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_RTCTIMER is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 
 #
diff -urN linux-2.5.6-pre1/arch/i386/kernel/time.c linux-2.5.6-pre2/arch/i386/kernel/time.c
--- linux-2.5.6-pre1/arch/i386/kernel/time.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/arch/i386/kernel/time.c	Thu Feb 28 13:34:18 2002
@@ -115,6 +115,7 @@
 #define TICK_SIZE tick
 
 spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
+EXPORT_SYMBOL(i8253_lock);
 
 extern spinlock_t i8259A_lock;
 
diff -urN linux-2.5.6-pre1/arch/ppc64/kernel/sys_ppc32.c linux-2.5.6-pre2/arch/ppc64/kernel/sys_ppc32.c
--- linux-2.5.6-pre1/arch/ppc64/kernel/sys_ppc32.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/arch/ppc64/kernel/sys_ppc32.c	Thu Feb 28 13:34:18 2002
@@ -924,143 +924,65 @@
 
 
 
-static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf)
+static int cp_new_stat32(struct kstat *stat, struct stat32 *statbuf)
 {
-	unsigned long ino, blksize, blocks;
-	kdev_t dev, rdev;
-	umode_t mode;
-	nlink_t nlink;
-	uid_t uid;
-	gid_t gid;
-	off_t size;
-	time_t atime, mtime, ctime;
 	int err;
 
-	/* Stream the loads of inode data into the load buffer,
-	 * then we push it all into the store buffer below.  This
-	 * should give optimal cache performance.
-	 */
-	ino = inode->i_ino;
-	dev = inode->i_dev;
-	mode = inode->i_mode;
-	nlink = inode->i_nlink;
-	uid = inode->i_uid;
-	gid = inode->i_gid;
-	rdev = inode->i_rdev;
-	size = inode->i_size;
-	atime = inode->i_atime;
-	mtime = inode->i_mtime;
-	ctime = inode->i_ctime;
-	blksize = inode->i_blksize;
-	blocks = inode->i_blocks;
-
-	err  = put_user(kdev_t_to_nr(dev), &statbuf->st_dev);
-	err |= put_user(ino, &statbuf->st_ino);
-	err |= put_user(mode, &statbuf->st_mode);
-	err |= put_user(nlink, &statbuf->st_nlink);
-	err |= put_user(uid, &statbuf->st_uid);
-	err |= put_user(gid, &statbuf->st_gid);
-	err |= put_user(kdev_t_to_nr(rdev), &statbuf->st_rdev);
-	err |= put_user(size, &statbuf->st_size);
-	err |= put_user(atime, &statbuf->st_atime);
+	err  = put_user(stat->dev, &statbuf->st_dev);
+	err |= put_user(stat->ino, &statbuf->st_ino);
+	err |= put_user(stat->mode, &statbuf->st_mode);
+	err |= put_user(stat->nlink, &statbuf->st_nlink);
+	err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
+	err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
+	err |= put_user(stat->rdev, &statbuf->st_rdev);
+	if (stat->size > MAX_NON_LFS)
+		return -EOVERFLOW;
+	err |= put_user(stat->size, &statbuf->st_size);
+	err |= put_user(stat->atime, &statbuf->st_atime);
 	err |= put_user(0, &statbuf->__unused1);
-	err |= put_user(mtime, &statbuf->st_mtime);
+	err |= put_user(stat->mtime, &statbuf->st_mtime);
 	err |= put_user(0, &statbuf->__unused2);
-	err |= put_user(ctime, &statbuf->st_ctime);
+	err |= put_user(stat->ctime, &statbuf->st_ctime);
 	err |= put_user(0, &statbuf->__unused3);
-	if (blksize) {
-		err |= put_user(blksize, &statbuf->st_blksize);
-		err |= put_user(blocks, &statbuf->st_blocks);
-	} else {
-		unsigned int tmp_blocks;
-
-#define D_B   7
-#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
-		tmp_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
-		if (tmp_blocks > D_B) {
-			unsigned int indirect;
-
-			indirect = (tmp_blocks - D_B + I_B - 1) / I_B;
-			tmp_blocks += indirect;
-			if (indirect > 1) {
-				indirect = (indirect - 1 + I_B - 1) / I_B;
-				tmp_blocks += indirect;
-				if (indirect > 1)
-					tmp_blocks++;
-			}
-		}
-		err |= put_user(BLOCK_SIZE, &statbuf->st_blksize);
-		err |= put_user((BLOCK_SIZE / 512) * tmp_blocks, &statbuf->st_blocks);
-#undef D_B
-#undef I_B
-	}
+	err |= put_user(stat->blksize, &statbuf->st_blksize);
+	err |= put_user(stat->blocks, &statbuf->st_blocks);
 	err |= put_user(0, &statbuf->__unused4[0]);
 	err |= put_user(0, &statbuf->__unused4[1]);
 
 	return err;
 }
 
-static __inline__ int
-do_revalidate(struct dentry *dentry)
-{
-	struct inode * inode = dentry->d_inode;
-	if (inode->i_op && inode->i_op->revalidate)
-		return inode->i_op->revalidate(dentry);
-	return 0;
-}
-
 asmlinkage long sys32_newstat(char* filename, struct stat32* statbuf)
 {
-	struct nameidata nd;
-	int error;
+	struct kstat stat;
+	int error = vfs_stat(filename, &stat);
 	
-	PPCDBG(PPCDBG_SYS32X, "sys32_newstat - running - filename=%s, statbuf=%p, pid=%ld, comm=%s\n", filename, statbuf, current->pid, current->comm);
+	if (!error)
+		error = cp_new_stat32(&stat, statbuf);
 
-	error = user_path_walk(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_new_stat32(nd.dentry->d_inode, statbuf);
-		path_release(&nd);
-	}
 	return error;
 }
 
 asmlinkage long sys32_newlstat(char * filename, struct stat32 *statbuf)
 {
-	struct nameidata nd;
-	int error;
+	struct kstat stat;
+	int error = vfs_lstat(filename, &stat);
 	
-	PPCDBG(PPCDBG_SYS32X, "sys32_newlstat - running - fn=%s, pid=%ld, comm=%s\n", filename, current->pid, current->comm);
+	if (!error)
+		error = cp_new_stat32(&stat, statbuf);
 
-	error = user_path_walk_link(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_new_stat32(nd.dentry->d_inode, statbuf);
-
-		path_release(&nd);
-	}
 	return error;
 }
 
 asmlinkage long sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
 {
-	struct file *f;
-	int err = -EBADF;
+	struct kstat stat;
+	int error = vfs_fstat(fd, &stat);
 	
-	PPCDBG(PPCDBG_SYS32X, "sys32_newfstat - running - fd=%x, pid=%ld, comm=%s\n", fd, current->pid, current->comm);
+	if (!error)
+		error = cp_new_stat32(&stat, statbuf);
 
-	f = fget(fd);
-	if (f) {
-		struct dentry * dentry = f->f_dentry;
-
-		err = do_revalidate(dentry);
-		if (!err)
-			err = cp_new_stat32(dentry->d_inode, statbuf);
-		fput(f);
-	}
-	return err;
+	return error;
 }
 
 static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
@@ -3104,7 +3026,7 @@
 /* stat syscall methods. */
 extern asmlinkage int sys_stat(char* filename, struct __old_kernel_stat* statbuf);
 
-static int cp_old_stat32(struct inode* inode, struct __old_kernel_stat32* statbuf)
+static int cp_old_stat32(struct kstat *stat, struct __old_kernel_stat32* statbuf)
 {
 	static int warncount = 5;
 	struct __old_kernel_stat32 tmp;
@@ -3115,79 +3037,51 @@
 			current->comm);
 	}
 
-	tmp.st_dev = kdev_t_to_nr(inode->i_dev);
-	tmp.st_ino = inode->i_ino;
-	tmp.st_mode = inode->i_mode;
-	tmp.st_nlink = inode->i_nlink;
-	SET_OLDSTAT_UID(tmp, inode->i_uid);
-	SET_OLDSTAT_GID(tmp, inode->i_gid);
-	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
-	tmp.st_size = inode->i_size;
-	tmp.st_atime = inode->i_atime;
-	tmp.st_mtime = inode->i_mtime;
-	tmp.st_ctime = inode->i_ctime;
+	tmp.st_dev = stat->dev;
+	tmp.st_ino = stat->ino;
+	tmp.st_mode = stat->mode;
+	tmp.st_nlink = stat->nlink;
+	SET_OLDSTAT_UID(tmp, stat->uid);
+	SET_OLDSTAT_GID(tmp, stat->gid);
+	tmp.st_rdev = stat->rdev;
+	if (stat->size > MAX_NON_LFS)
+		return -EOVERFLOW;
+	tmp.st_size = stat->size;
+	tmp.st_atime = stat->atime;
+	tmp.st_mtime = stat->mtime;
+	tmp.st_ctime = stat->ctime;
 	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
 }
 
 asmlinkage long sys32_stat(char* filename, struct __old_kernel_stat32* statbuf)
 {
-	struct nameidata nd;
-	int error;
-	
-	PPCDBG(PPCDBG_SYS32X, "sys32_stat - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
-	error = user_path_walk(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_old_stat32(nd.dentry->d_inode, statbuf);
-		path_release(&nd);
-	}
+	struct kstat stat;
+	int error = vfs_stat(filename, &stat);
 	
-	PPCDBG(PPCDBG_SYS32X, "sys32_stat - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	if (!error)
+		error = cp_old_stat32(&stat, statbuf);
 
 	return error;
 }
 
 asmlinkage long sys32_fstat(unsigned int fd, struct __old_kernel_stat32* statbuf)
 {
-	struct file *f;
-	int err = -EBADF;
-	
-	PPCDBG(PPCDBG_SYS32X, "sys32_fstat - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
-	f = fget(fd);
-	if (f) {
-		struct dentry * dentry = f->f_dentry;
-
-		err = do_revalidate(dentry);
-		if (!err)
-			err = cp_old_stat32(dentry->d_inode, statbuf);
-		fput(f);
-	}
+	struct kstat stat;
+	int error = vfs_fstat(fd, &stat);
 	
-	PPCDBG(PPCDBG_SYS32X, "sys32_fstat - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	if (!error)
+		error = cp_old_stat32(&stat, statbuf);
 
-	return err;
+	return error;
 }
 
 asmlinkage long sys32_lstat(char* filename, struct __old_kernel_stat32* statbuf)
 {
-	struct nameidata nd;
-	int error;
-	
-	PPCDBG(PPCDBG_SYS32X, "sys32_lstat - entered - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
-
-	error = user_path_walk_link(filename, &nd);
-	if (!error) {
-		error = do_revalidate(nd.dentry);
-		if (!error)
-			error = cp_old_stat32(nd.dentry->d_inode, statbuf);
-
-		path_release(&nd);
-	}
+	struct kstat stat;
+	int error = vfs_lstat(filename, &stat);
 	
-	PPCDBG(PPCDBG_SYS32X, "sys32_lstat - exited - pid=%ld current=%lx comm=%s \n", current->pid, current, current->comm);
+	if (!error)
+		error = cp_old_stat32(&stat, statbuf);
 
 	return error;
 }
diff -urN linux-2.5.6-pre1/arch/sparc64/kernel/sys_sparc32.c linux-2.5.6-pre2/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.5.6-pre1/arch/sparc64/kernel/sys_sparc32.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/arch/sparc64/kernel/sys_sparc32.c	Thu Feb 28 13:34:18 2002
@@ -1471,6 +1471,8 @@
 	err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
 	err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
 	err |= put_user(stat->rdev, &statbuf->st_rdev);
+	if (stat->size > MAX_NON_LFS)
+		return -EOVERFLOW;
 	err |= put_user(stat->size, &statbuf->st_size);
 	err |= put_user(stat->atime, &statbuf->st_atime);
 	err |= put_user(0, &statbuf->__unused1);
diff -urN linux-2.5.6-pre1/arch/x86_64/config.in linux-2.5.6-pre2/arch/x86_64/config.in
--- linux-2.5.6-pre1/arch/x86_64/config.in	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/arch/x86_64/config.in	Thu Feb 28 13:34:18 2002
@@ -29,7 +29,7 @@
 define_int CONFIG_X86_L1_CACHE_SHIFT 6
 define_bool CONFIG_X86_TSC y
 define_bool CONFIG_X86_GOOD_APIC y
-define_bool CONFIG_X86_CMPXCHG
+define_bool CONFIG_X86_CMPXCHG y
 
 tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR
 tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID
@@ -72,6 +72,7 @@
 
 if [ "$CONFIG_HOTPLUG" = "y" ] ; then
    source drivers/pcmcia/Config.in
+   source drivers/hotplug/Config.in
 else
    define_bool CONFIG_PCMCIA n
 fi
@@ -80,8 +81,8 @@
    define_bool CONFIG_KCORE_ELF y
 fi
 # We probably are not going to support a.out, are we? Or should we support a.out in i386 compatibility mode?
-#tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
-tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+		#tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+		tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
 bool 'Power Management support' CONFIG_PM
diff -urN linux-2.5.6-pre1/arch/x86_64/defconfig linux-2.5.6-pre2/arch/x86_64/defconfig
--- linux-2.5.6-pre1/arch/x86_64/defconfig	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/arch/x86_64/defconfig	Thu Feb 28 13:34:18 2002
@@ -37,6 +37,7 @@
 CONFIG_X86_L1_CACHE_SHIFT=6
 CONFIG_X86_TSC=y
 CONFIG_X86_GOOD_APIC=y
+CONFIG_X86_CMPXCHG=y
 CONFIG_X86_MSR=y
 CONFIG_X86_CPUID=y
 # CONFIG_MATH_EMULATION is not set
@@ -59,16 +60,7 @@
 # CONFIG_BINFMT_MISC is not set
 CONFIG_PM=y
 CONFIG_IA32_EMULATION=y
-CONFIG_ACPI=y
-CONFIG_ACPI_DEBUG=y
-CONFIG_ACPI_BUSMGR=y
-CONFIG_ACPI_SYS=y
-CONFIG_ACPI_CPU=y
-CONFIG_ACPI_BUTTON=y
-CONFIG_ACPI_AC=y
-CONFIG_ACPI_EC=y
-CONFIG_ACPI_CMBATT=y
-CONFIG_ACPI_THERMAL=y
+# CONFIG_ACPI is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -99,9 +91,8 @@
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -388,7 +379,6 @@
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
 # CONFIG_UFS_FS_WRITE is not set
-CONFIG_SIMICSFS=y
 
 #
 # Network File Systems
diff -urN linux-2.5.6-pre1/arch/x86_64/ia32/ia32_binfmt.c linux-2.5.6-pre2/arch/x86_64/ia32/ia32_binfmt.c
--- linux-2.5.6-pre1/arch/x86_64/ia32/ia32_binfmt.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/arch/x86_64/ia32/ia32_binfmt.c	Thu Feb 28 13:34:18 2002
@@ -12,6 +12,9 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 
+struct file;
+struct elf_phdr; 
+
 #define IA32_EMULATOR 1
 
 #define IA32_PAGE_OFFSET 0xE0000000
@@ -77,7 +80,6 @@
 	__asm__("movl %0,%%fs": :"r" (0)); \
 	__asm__("movl %0,%%es; movl %0,%%ds": :"r" (__USER32_DS)); \
 	wrmsrl(MSR_KERNEL_GS_BASE, 0); \
-	set_thread_flag(TIF_IA32); \
 	(regs)->rip = (new_rip); \
 	(regs)->rsp = (new_rsp); \
 	(regs)->eflags = 0x200; \
@@ -87,6 +89,8 @@
 } while(0) 
 
 
+#define elf_map elf32_map
+
 MODULE_DESCRIPTION("Binary format loader for compatibility with IA32 ELF binaries."); 
 MODULE_AUTHOR("Eric Youngdale, Andi Kleen");
 
@@ -102,6 +106,7 @@
 
 static void elf32_init(struct pt_regs *regs)
 {
+	struct task_struct *me = current; 
 	regs->rdi = 0;
 	regs->rsi = 0;
 	regs->rdx = 0;
@@ -109,9 +114,13 @@
 	regs->rax = 0;
 	regs->rbx = 0; 
 	regs->rbp = 0; 
-        current->thread.fs = 0; current->thread.gs = 0;
-	current->thread.fsindex = 0; current->thread.gsindex = 0;
-        current->thread.ds = __USER_DS; current->thread.es == __USER_DS;
+    me->thread.fs = 0; 
+	me->thread.gs = 0;
+	me->thread.fsindex = 0; 
+	me->thread.gsindex = 0;
+    me->thread.ds = __USER_DS; 
+	me->thread.es = __USER_DS;
+	set_thread_flag(TIF_IA32); 
 }
 
 extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address);
@@ -162,4 +171,17 @@
 	
 	return 0;
 }
+static unsigned long
+elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type)
+{
+	unsigned long map_addr;
+	struct task_struct *me = current; 
+
+	down_write(&me->mm->mmap_sem);
+	map_addr = do_mmap(filep, ELF_PAGESTART(addr),
+			   eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type|MAP_32BIT,
+			   eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
+	up_write(&me->mm->mmap_sem);
+	return(map_addr);
+}
 
diff -urN linux-2.5.6-pre1/arch/x86_64/ia32/ia32_ioctl.c linux-2.5.6-pre2/arch/x86_64/ia32/ia32_ioctl.c
--- linux-2.5.6-pre1/arch/x86_64/ia32/ia32_ioctl.c	Tue Feb 19 18:10:52 2002
+++ linux-2.5.6-pre2/arch/x86_64/ia32/ia32_ioctl.c	Thu Feb 28 13:34:18 2002
@@ -3083,8 +3083,6 @@
 COMPATIBLE_IOCTL(BLKROGET)
 COMPATIBLE_IOCTL(BLKRRPART)
 COMPATIBLE_IOCTL(BLKFLSBUF)
-COMPATIBLE_IOCTL(BLKRASET)
-COMPATIBLE_IOCTL(BLKFRASET)
 COMPATIBLE_IOCTL(BLKSECTSET)
 COMPATIBLE_IOCTL(BLKSSZGET)
 
@@ -3596,10 +3594,8 @@
 HANDLE_IOCTL(SIOCRTMSG, ret_einval)
 HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp)
 HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo)
-HANDLE_IOCTL(BLKRAGET, w_long)
 HANDLE_IOCTL(BLKGETSIZE, w_long)
 HANDLE_IOCTL(0x1260, broken_blkgetsize)
-HANDLE_IOCTL(BLKFRAGET, w_long)
 HANDLE_IOCTL(BLKSECTGET, w_long)
 HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans)
 HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans)
diff -urN linux-2.5.6-pre1/arch/x86_64/ia32/ia32_signal.c linux-2.5.6-pre2/arch/x86_64/ia32/ia32_signal.c
--- linux-2.5.6-pre1/arch/x86_64/ia32/ia32_signal.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/arch/x86_64/ia32/ia32_signal.c	Thu Feb 28 13:34:18 2002
@@ -82,7 +82,7 @@
 	spin_lock_irq(&current->sigmask_lock);
 	saveset = current->blocked;
 	siginitset(&current->blocked, mask);
-	recalc_sigpending(current);
+	recalc_sigpending();
 	spin_unlock_irq(&current->sigmask_lock);
 
 	regs.rax = -EINTR;
@@ -225,7 +225,7 @@
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
 	current->blocked = set;
-	recalc_sigpending(current);
+	recalc_sigpending();
 	spin_unlock_irq(&current->sigmask_lock);
 	
 	if (restore_sigcontext(&regs, &frame->sc, &eax))
@@ -252,7 +252,7 @@
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
 	current->blocked = set;
-	recalc_sigpending(current);
+	recalc_sigpending();
 	spin_unlock_irq(&current->sigmask_lock);
 	
 	if (restore_sigcontext(&regs, &frame->uc.uc_mcontext, &eax))
diff -urN linux-2.5.6-pre1/arch/x86_64/kernel/process.c linux-2.5.6-pre2/arch/x86_64/kernel/process.c
--- linux-2.5.6-pre1/arch/x86_64/kernel/process.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/arch/x86_64/kernel/process.c	Thu Feb 28 13:34:18 2002
@@ -140,7 +140,6 @@
 		while (!need_resched())
 			idle();
 		schedule();
-		check_pgt_cache();
 	}
 }
 
diff -urN linux-2.5.6-pre1/arch/x86_64/kernel/ptrace.c linux-2.5.6-pre2/arch/x86_64/kernel/ptrace.c
--- linux-2.5.6-pre1/arch/x86_64/kernel/ptrace.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/arch/x86_64/kernel/ptrace.c	Thu Feb 28 13:34:18 2002
@@ -420,9 +420,11 @@
 	
 	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
 					? 0x80 : 0);
+	preempt_disable();
 	current->state = TASK_STOPPED;
 	notify_parent(current, SIGCHLD);
 	schedule();
+	preempt_enable();
 	/*
 	 * this isn't the same as continuing with a signal, but it will do
 	 * for normal use.  strace only continues with a signal if the
diff -urN linux-2.5.6-pre1/arch/x86_64/kernel/signal.c linux-2.5.6-pre2/arch/x86_64/kernel/signal.c
--- linux-2.5.6-pre1/arch/x86_64/kernel/signal.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/arch/x86_64/kernel/signal.c	Thu Feb 28 13:34:20 2002
@@ -89,7 +89,7 @@
 	spin_lock_irq(&current->sigmask_lock);
 	saveset = current->blocked;
 	current->blocked = newset;
-	recalc_sigpending(current);
+	recalc_sigpending();
 	spin_unlock_irq(&current->sigmask_lock);
 #if DEBUG_SIG
 	printk("rt_sigsuspend savset(%lx) newset(%lx) regs(%p) rip(%lx)\n",
@@ -200,7 +200,7 @@
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sigmask_lock);
 	current->blocked = set;
-	recalc_sigpending(current);
+	recalc_sigpending();
 	spin_unlock_irq(&current->sigmask_lock);
 	
 	if (restore_sigcontext(&regs, &frame->uc.uc_mcontext, &eax))
@@ -431,7 +431,7 @@
 		spin_lock_irq(&current->sigmask_lock);
 		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
 		sigaddset(&current->blocked,sig);
-		recalc_sigpending(current);
+		recalc_sigpending();
 		spin_unlock_irq(&current->sigmask_lock);
 	}
 }
@@ -473,9 +473,11 @@
 		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
 			/* Let the debugger run.  */
 			current->exit_code = signr;
+			preempt_disable();
 			current->state = TASK_STOPPED;
 			notify_parent(current, SIGCHLD);
 			schedule();
+			preempt_enable();
 
 			/* We're back.  Did the debugger cancel the sig?  */
 			if (!(signr = current->exit_code))
@@ -530,12 +532,14 @@
 
 			case SIGSTOP: {
 				struct signal_struct *sig;
+				preempt_disable(); 
 				current->state = TASK_STOPPED;
 				current->exit_code = signr;
 				sig = current->p_pptr->sig;
 				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
+				preempt_enable();
 				continue;
 			}
 
diff -urN linux-2.5.6-pre1/arch/x86_64/kernel/time.c linux-2.5.6-pre2/arch/x86_64/kernel/time.c
--- linux-2.5.6-pre1/arch/x86_64/kernel/time.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/arch/x86_64/kernel/time.c	Thu Feb 28 13:34:21 2002
@@ -120,6 +120,62 @@
 
 extern spinlock_t i8259A_lock;
 
+
+static inline unsigned long do_fast_gettimeoffset(void)
+{
+	register unsigned long eax, edx;
+
+	/* Read the Time Stamp Counter */
+
+	rdtsc(eax,edx);
+
+	/* .. relative to previous jiffy (32 bits is enough) */
+	eax -= last_tsc_low;	/* tsc_low delta */
+
+	/*
+         * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
+         *             = (tsc_low delta) * (usecs_per_clock)
+         *             = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy)
+	 *
+	 * Using a mull instead of a divl saves up to 31 clock cycles
+	 * in the critical path.
+         */
+
+	edx = (eax*fast_gettimeoffset_quotient) >> 32;
+
+	/* our adjusted time offset in microseconds */
+	return delay_at_last_interrupt + edx;
+}
+
+/*
+ * This version of gettimeofday has microsecond resolution
+ * and better than microsecond precision on fast x86 machines with TSC.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned long flags;
+	unsigned long usec, sec;
+
+	read_lock_irqsave(&xtime_lock, flags);
+	usec = do_gettimeoffset();
+	{
+		unsigned long lost = jiffies - wall_jiffies;
+		if (lost)
+			usec += lost * (1000000 / HZ);
+	}
+	sec = xtime.tv_sec;
+	usec += xtime.tv_usec;
+	read_unlock_irqrestore(&xtime_lock, flags);
+
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
+	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
+}
+
 void do_settimeofday(struct timeval *tv)
 {
 	write_lock_irq(&xtime_lock);
@@ -484,7 +540,7 @@
 			 * clock/second. Our precision is about 100 ppm.
 			 */
 			{			
-			        cpu_khz = ((1000000*(1UL<<32)) / tsc_quotient); /* FIXME: is it right? */
+			        cpu_khz = ((1000*(1UL<<32)) / tsc_quotient); 
 				printk("Detected %ld Hz processor.\n", cpu_khz);
 			}
 		}
diff -urN linux-2.5.6-pre1/arch/x86_64/kernel/vsyscall.c linux-2.5.6-pre2/arch/x86_64/kernel/vsyscall.c
--- linux-2.5.6-pre1/arch/x86_64/kernel/vsyscall.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/arch/x86_64/kernel/vsyscall.c	Thu Feb 28 13:34:21 2002
@@ -60,9 +60,6 @@
 
 long __vxtime_sequence[2] __section_vxtime_sequence;
 
-/* The rest of the kernel knows it as this. */
-extern void do_gettimeofday(struct timeval *tv) __attribute__((alias("do_vgettimeofday"))); 
-
 inline void do_vgettimeofday(struct timeval * tv)
 {
 	long sequence;
diff -urN linux-2.5.6-pre1/arch/x86_64/kernel/x8664_ksyms.c linux-2.5.6-pre2/arch/x86_64/kernel/x8664_ksyms.c
--- linux-2.5.6-pre1/arch/x86_64/kernel/x8664_ksyms.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/arch/x86_64/kernel/x8664_ksyms.c	Thu Feb 28 13:34:21 2002
@@ -89,7 +89,6 @@
 
 EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strpbrk);
-EXPORT_SYMBOL(simple_strtol);
 EXPORT_SYMBOL(strstr);
 
 EXPORT_SYMBOL(strncpy_from_user);
diff -urN linux-2.5.6-pre1/arch/x86_64/mm/fault.c linux-2.5.6-pre2/arch/x86_64/mm/fault.c
--- linux-2.5.6-pre1/arch/x86_64/mm/fault.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/arch/x86_64/mm/fault.c	Thu Feb 28 13:34:21 2002
@@ -112,7 +112,7 @@
 	mm = tsk->mm;
 	info.si_code = SEGV_MAPERR;
 
-	if (address >= TASK_SIZE) 
+	if (address >= TASK_SIZE && !(error_code & 5))
 		goto vmalloc_fault;
 
 
diff -urN linux-2.5.6-pre1/arch/x86_64/mm/init.c linux-2.5.6-pre2/arch/x86_64/mm/init.c
--- linux-2.5.6-pre1/arch/x86_64/mm/init.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/arch/x86_64/mm/init.c	Thu Feb 28 13:34:21 2002
@@ -1,8 +1,9 @@
 /*
- *  linux/arch/i386/mm/init.c
+ *  linux/arch/x86_64/mm/init.c
  *
  *  Copyright (C) 1995  Linus Torvalds
  *  Copyright (C) 2000  Pavel Machek <pavel@suse.cz>
+ *  Copyright (C) 2002  Andi Kleen <ak@suse.de>
  */
 
 #include <linux/config.h>
@@ -39,28 +40,6 @@
 
 static unsigned long totalram_pages;
 
-int do_check_pgt_cache(int low, int high)
-{
-	int freed = 0;
-	if(read_pda(pgtable_cache_sz) > high) {
-		do {
-			if (read_pda(pgd_quick)) {
-				pgd_free_slow(pgd_alloc_one_fast());
-				freed++;
-			}
-			if (read_pda(pmd_quick)) {
-				pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
-				freed++;
-			}
-			if (read_pda(pte_quick)) {
-				pte_free_slow(pte_alloc_one_fast(NULL, 0));
-				freed++;
-			}
-		} while(read_pda(pgtable_cache_sz) > low);
-	}
-	return freed;
-}
-
 /*
  * NOTE: pagetable_init alloc all the fixmap pagetables contiguous on the
  * physical space so we can cache the place of the first one and move
@@ -89,7 +68,6 @@
 	printk("%d reserved pages\n",reserved);
 	printk("%d pages shared\n",shared);
 	printk("%d pages swap cached\n",cached);
-	printk("%ld pages in page table cache\n",read_pda(pgtable_cache_sz));
 	show_buffers();
 }
 
@@ -138,12 +116,12 @@
 	if (pmd_none(*pmd)) {
 		pte = (pte_t *) spp_getpage();
 		set_pmd(pmd, __pmd(__pa(pte) + 0x7));
-		if (pte != pte_offset(pmd, 0)) {
+		if (pte != pte_offset_kernel(pmd, 0)) {
 			printk("PAGETABLE BUG #02!\n");
 			return;
 		}
 	}
-	pte = pte_offset(pmd, vaddr);
+	pte = pte_offset_kernel(pmd, vaddr);
 	if (pte_val(*pte))
 		pte_ERROR(*pte);
 	set_pte(pte, mk_pte_phys(phys, prot));
diff -urN linux-2.5.6-pre1/arch/x86_64/mm/ioremap.c linux-2.5.6-pre2/arch/x86_64/mm/ioremap.c
--- linux-2.5.6-pre1/arch/x86_64/mm/ioremap.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/arch/x86_64/mm/ioremap.c	Thu Feb 28 13:34:21 2002
@@ -49,7 +49,7 @@
 	if (address >= end)
 		BUG();
 	do {
-		pte_t * pte = pte_alloc(&init_mm, pmd, address);
+		pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
 		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
diff -urN linux-2.5.6-pre1/arch/x86_64/tools/offset.c linux-2.5.6-pre2/arch/x86_64/tools/offset.c
--- linux-2.5.6-pre1/arch/x86_64/tools/offset.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/arch/x86_64/tools/offset.c	Thu Feb 28 13:34:21 2002
@@ -42,10 +42,6 @@
 	ENTRY(irqrsp);
 	ENTRY(irqcount);
 	ENTRY(irqstack); 
-	ENTRY(pgd_quick);
-	ENTRY(pmd_quick);
-	ENTRY(pte_quick);
-	ENTRY(pgtable_cache_sz);
 	ENTRY(cpunumber);
 	ENTRY(irqstackptr);
 	ENTRY(me);
diff -urN linux-2.5.6-pre1/drivers/block/amiflop.c linux-2.5.6-pre2/drivers/block/amiflop.c
--- linux-2.5.6-pre1/drivers/block/amiflop.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/drivers/block/amiflop.c	Thu Feb 28 13:34:21 2002
@@ -1514,7 +1514,7 @@
 			rel_fdc();
 			return -EBUSY;
 		}
-		fsync_dev(inode->i_rdev);
+		fsync_bdev(inode->i_bdev);
 		if (fd_motor_on(drive) == 0) {
 			rel_fdc();
 			return -ENODEV;
diff -urN linux-2.5.6-pre1/drivers/block/ll_rw_blk.c linux-2.5.6-pre2/drivers/block/ll_rw_blk.c
--- linux-2.5.6-pre1/drivers/block/ll_rw_blk.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/drivers/block/ll_rw_blk.c	Thu Feb 28 13:34:21 2002
@@ -1697,9 +1697,6 @@
 	blk_max_low_pfn = max_low_pfn;
 	blk_max_pfn = max_pfn;
 
-#if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_IDE)
-	ide_init();		/* this MUST precede hd_init */
-#endif
 #if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_HD)
 	hd_init();
 #endif
diff -urN linux-2.5.6-pre1/drivers/char/Config.help linux-2.5.6-pre2/drivers/char/Config.help
--- linux-2.5.6-pre1/drivers/char/Config.help	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/drivers/char/Config.help	Thu Feb 28 13:34:21 2002
@@ -425,6 +425,24 @@
   read <file:Documentation/modules.txt>. The module will be called
   istallion.o.
 
+CONFIG_SERIAL_TX3912
+  The TX3912 is a Toshiba RISC processor based o the MIPS 3900 core;
+  see <http://www.toshiba.com/taec/components/Generic/risc/tx3912.htm>.
+  Say Y here to enable kernel support for the on-board serial port.
+
+CONFIG_SERIAL_TX3912_CONSOLE
+  The TX3912 is a Toshiba RISC processor based o the MIPS 3900 core;
+  see <http://www.toshiba.com/taec/components/Generic/risc/tx3912.htm>.
+  Say Y here to direct console I/O to the on-board serial port.
+
+CONFIG_AU1000_SERIAL_CONSOLE
+  If you have an Alchemy AU1000 processor (MIPS based) and you want
+  to use a console on a serial port, say Y.  Otherwise, say N.
+
+CONFIG_AU1000_UART
+  If you have an Alchemy AU1000 processor (MIPS based) and you want
+  to use serial ports, say Y.  Otherwise, say N.
+
 CONFIG_SYNCLINK
   Provides support for the SyncLink ISA and PCI multiprotocol serial
   adapters. These adapters support asynchronous and HDLC bit
@@ -942,6 +960,11 @@
   module, say M here and read <file:Documentation/modules.txt>.  Most
   people will say N.
 
+CONFIG_EUROTECH_WDT
+  Enable support for the watchdog timer on the Eurotech CPU-1220 and
+  CPU-1410 cards.  These are PC/104 SBCs. Spec sheets and product
+  information are at <http://www.eurotech.it/>.
+
 CONFIG_IB700_WDT
   This is the driver for the hardware watchdog on the IB700 Single
   Board Computer produced by TMC Technology (www.tmc-uk.com). This watchdog
diff -urN linux-2.5.6-pre1/drivers/char/lp.c linux-2.5.6-pre2/drivers/char/lp.c
--- linux-2.5.6-pre1/drivers/char/lp.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/drivers/char/lp.c	Thu Feb 28 13:34:21 2002
@@ -270,7 +270,7 @@
 	return error;
 }
 
-static int lp_wait_ready(int minor)
+static int lp_wait_ready(int minor, int nonblock)
 {
 	int error = 0;
 
@@ -281,7 +281,7 @@
 
 	do {
 		error = lp_check_status (minor);
-		if (error && (LP_F(minor) & LP_ABORT))
+		if (error && (nonblock || (LP_F(minor) & LP_ABORT)))
 			break;
 		if (signal_pending (current)) {
 			error = -EINTR;
@@ -300,6 +300,8 @@
 	ssize_t retv = 0;
 	ssize_t written;
 	size_t copy_size = count;
+	int nonblock = ((file->f_flags & O_NONBLOCK) ||
+			(LP_F(minor) & LP_ABORT));
 
 #ifdef LP_STATS
 	if (jiffies-lp_table[minor].lastcall > LP_TIME(minor))
@@ -326,9 +328,10 @@
 						     lp_table[minor].best_mode);
 
 	parport_set_timeout (lp_table[minor].dev,
-			     lp_table[minor].timeout);
+			     (nonblock ? PARPORT_INACTIVITY_O_NONBLOCK
+			      : lp_table[minor].timeout));
 
-	if ((retv = lp_wait_ready (minor)) == 0)
+	if ((retv = lp_wait_ready (minor, nonblock)) == 0)
 	do {
 		/* Write the data. */
 		written = parport_write (port, kbuf, copy_size);
@@ -354,12 +357,16 @@
 					   IEEE1284_MODE_COMPAT);
 			lp_table[minor].current_mode = IEEE1284_MODE_COMPAT;
 
-			error = lp_wait_ready (minor);
+			error = lp_wait_ready (minor, nonblock);
 
 			if (error) {
 				if (retv == 0)
 					retv = error;
 				break;
+			} else if (nonblock) {
+				if (retv == 0)
+					retv = -EAGAIN;
+				break;
 			}
 
 			parport_yield_blocking (lp_table[minor].dev);
@@ -407,6 +414,8 @@
 	struct parport *port = lp_table[minor].dev->port;
 	ssize_t retval = 0;
 	char *kbuf = lp_table[minor].lp_buffer;
+	int nonblock = ((file->f_flags & O_NONBLOCK) ||
+			(LP_F(minor) & LP_ABORT));
 
 	if (count > LP_BUFFER_SIZE)
 		count = LP_BUFFER_SIZE;
@@ -415,7 +424,53 @@
 		return -EINTR;
 
 	lp_claim_parport_or_block (&lp_table[minor]);
-	retval = parport_read (port, kbuf, count);
+
+	parport_set_timeout (lp_table[minor].dev,
+			     (nonblock ? PARPORT_INACTIVITY_O_NONBLOCK
+			      : lp_table[minor].timeout));
+
+	parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT);
+	if (parport_negotiate (lp_table[minor].dev->port,
+			       IEEE1284_MODE_NIBBLE)) {
+		retval = -EIO;
+		goto out;
+	}
+
+	while (retval == 0) {
+		retval = parport_read (port, kbuf, count);
+
+		if (retval > 0)
+			break;
+
+		if (nonblock) {
+			retval = -EAGAIN;
+			break;
+		}
+
+		/* Wait for data. */
+
+		if (lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE) {
+			parport_negotiate (lp_table[minor].dev->port,
+					   IEEE1284_MODE_COMPAT);
+			lp_error (minor);
+			if (parport_negotiate (lp_table[minor].dev->port,
+					       IEEE1284_MODE_NIBBLE)) {
+				retval = -EIO;
+				goto out;
+			}
+		} else
+			interruptible_sleep_on_timeout (&lp_table[minor].waitq,
+							LP_TIMEOUT_POLLED);
+
+		if (signal_pending (current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+
+		cond_resched ();
+	}
+	parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT);
+ out:
 	lp_release_parport (&lp_table[minor]);
 
 	if (retval > 0 && copy_to_user (buf, kbuf, retval))
@@ -476,7 +531,6 @@
 		printk (KERN_INFO "lp%d: ECP mode\n", minor);
 		lp_table[minor].best_mode = IEEE1284_MODE_ECP;
 	} else {
-		printk (KERN_INFO "lp%d: compatibility mode\n", minor);
 		lp_table[minor].best_mode = IEEE1284_MODE_COMPAT;
 	}
 	/* Leave peripheral in compatibility mode */
diff -urN linux-2.5.6-pre1/drivers/char/ppdev.c linux-2.5.6-pre2/drivers/char/ppdev.c
--- linux-2.5.6-pre1/drivers/char/ppdev.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/drivers/char/ppdev.c	Thu Feb 28 13:34:21 2002
@@ -4,7 +4,7 @@
  * This is the code behind /dev/parport* -- it allows a user-space
  * application to use the parport subsystem.
  *
- * Copyright (C) 1998-2000 Tim Waugh <tim@cyberelk.demon.co.uk>
+ * Copyright (C) 1998-2000, 2002 Tim Waugh <tim@cyberelk.net>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -80,6 +80,7 @@
 	unsigned char irqctl;
 	struct ieee1284_info state;
 	struct ieee1284_info saved_state;
+	long default_inactivity;
 };
 
 /* pp_struct.flags bitfields */
@@ -107,7 +108,6 @@
 	struct pp_struct *pp = file->private_data;
 	char * kbuffer;
 	ssize_t bytes_read = 0;
-	ssize_t got = 0;
 	struct parport *pport;
 	int mode;
 
@@ -125,8 +125,13 @@
 	pport = pp->pdev->port;
 	mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
 
-	while (bytes_read < count) {
-		ssize_t need = min_t(unsigned long, count - bytes_read, PP_BUFFER_SIZE);
+	parport_set_timeout (pp->pdev,
+			     (file->f_flags & O_NONBLOCK) ?
+			     PARPORT_INACTIVITY_O_NONBLOCK :
+			     pp->default_inactivity);
+
+	while (bytes_read == 0) {
+		ssize_t need = min_t(unsigned long, count, PP_BUFFER_SIZE);
 
 		if (mode == IEEE1284_MODE_EPP) {
 			/* various specials for EPP mode */
@@ -144,35 +149,32 @@
 			} else {
 				fn = pport->ops->epp_read_data;
 			}
-			got = (*fn)(pport, kbuffer, need, flags);
+			bytes_read = (*fn)(pport, kbuffer, need, flags);
 		} else {
-			got = parport_read (pport, kbuffer, need);
+			bytes_read = parport_read (pport, kbuffer, need);
 		}
 
-		if (got <= 0) {
-			if (!bytes_read) {
-				bytes_read = got;
-			}
+		if (bytes_read != 0)
 			break;
-		}
 
-		if (copy_to_user (buf + bytes_read, kbuffer, got)) {
-			bytes_read = -EFAULT;
+		if (file->f_flags & O_NONBLOCK) {
+			bytes_read = -EAGAIN;
 			break;
 		}
 
-		bytes_read += got;
-
 		if (signal_pending (current)) {
-			if (!bytes_read) {
-				bytes_read = -EINTR;
-			}
+			bytes_read = -ERESTARTSYS;
 			break;
 		}
 
 		cond_resched();
 	}
 
+	parport_set_timeout (pp->pdev, pp->default_inactivity);
+
+	if (bytes_read > 0 && copy_to_user (buf, kbuffer, bytes_read))
+		bytes_read = -EFAULT;
+
 	kfree (kbuffer);
 	pp_enable_irq (pp);
 	return bytes_read;
@@ -203,6 +205,11 @@
 	pport = pp->pdev->port;
 	mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
 
+	parport_set_timeout (pp->pdev,
+			     (file->f_flags & O_NONBLOCK) ?
+			     PARPORT_INACTIVITY_O_NONBLOCK :
+			     pp->default_inactivity);
+
 	while (bytes_written < count) {
 		ssize_t n = min_t(unsigned long, count - bytes_written, PP_BUFFER_SIZE);
 
@@ -233,6 +240,12 @@
 
 		bytes_written += wrote;
 
+		if (file->f_flags & O_NONBLOCK) {
+			if (!bytes_written)
+				bytes_written = -EAGAIN;
+			break;
+		}
+
 		if (signal_pending (current)) {
 			if (!bytes_written) {
 				bytes_written = -EINTR;
@@ -243,6 +256,8 @@
 		cond_resched();
 	}
 
+	parport_set_timeout (pp->pdev, pp->default_inactivity);
+
 	kfree (kbuffer);
 	pp_enable_irq (pp);
 	return bytes_written;
@@ -352,6 +367,8 @@
 		pp->saved_state.phase = info->phase;
 		info->mode = pp->state.mode;
 		info->phase = pp->state.phase;
+		pp->default_inactivity = parport_set_timeout (pp->pdev, 0);
+		parport_set_timeout (pp->pdev, pp->default_inactivity);
 
 		return 0;
 	    }
diff -urN linux-2.5.6-pre1/drivers/char/sysrq.c linux-2.5.6-pre2/drivers/char/sysrq.c
--- linux-2.5.6-pre1/drivers/char/sysrq.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/drivers/char/sysrq.c	Thu Feb 28 13:34:21 2002
@@ -161,7 +161,7 @@
 		}
 		file_list_unlock();
 		DQUOT_OFF(sb);
-		fsync_dev(sb->s_dev);
+		fsync_bdev(sb->s_bdev);
 		flags = MS_RDONLY;
 		if (sb->s_op && sb->s_op->remount_fs) {
 			ret = sb->s_op->remount_fs(sb, &flags, NULL);
@@ -174,7 +174,7 @@
 		} else
 			printk("nothing to do\n");
 	} else { /* Sync only */
-		fsync_dev(sb->s_dev);
+		fsync_bdev(sb->s_bdev);
 		printk("OK\n");
 	}
 	console_loglevel = orig_loglevel;
diff -urN linux-2.5.6-pre1/drivers/hotplug/Config.help linux-2.5.6-pre2/drivers/hotplug/Config.help
--- linux-2.5.6-pre1/drivers/hotplug/Config.help	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/drivers/hotplug/Config.help	Thu Feb 28 13:34:21 2002
@@ -29,3 +29,14 @@
 
   When in doubt, say N.
 
+CONFIG_HOTPLUG_PCI_IBM
+  Say Y here if you have a motherboard with a IBM PCI Hotplug
+  controller.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called cpqphp.o. If you want to compile it
+  as a module, say M here and read <file:Documentation/modules.txt>.
+
+  When in doubt, say N.
+
diff -urN linux-2.5.6-pre1/drivers/hotplug/Config.in linux-2.5.6-pre2/drivers/hotplug/Config.in
--- linux-2.5.6-pre1/drivers/hotplug/Config.in	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/drivers/hotplug/Config.in	Thu Feb 28 13:34:21 2002
@@ -4,9 +4,10 @@
 mainmenu_option next_comment
 comment 'PCI Hotplug Support'
 
-dep_tristate 'Support for PCI Hotplug (EXPERIMENTAL)' CONFIG_HOTPLUG_PCI $CONFIG_DDFS $CONFIG_EXPERIMENTAL
+dep_tristate 'Support for PCI Hotplug (EXPERIMENTAL)' CONFIG_HOTPLUG_PCI $CONFIG_PCI $CONFIG_EXPERIMENTAL 
 
-dep_tristate '  Compaq PCI Hotplug driver' CONFIG_HOTPLUG_PCI_COMPAQ $CONFIG_HOTPLUG_PCI
+dep_tristate '  Compaq PCI Hotplug driver' CONFIG_HOTPLUG_PCI_COMPAQ $CONFIG_HOTPLUG_PCI $CONFIG_X86
 dep_mbool '    Save configuration into NVRAM on Compaq servers' CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM $CONFIG_HOTPLUG_PCI_COMPAQ
+dep_tristate '  IBM PCI Hotplug driver' CONFIG_HOTPLUG_PCI_IBM $CONFIG_HOTPLUG_PCI $CONFIG_X86_IO_APIC $CONFIG_X86
 
 endmenu
diff -urN linux-2.5.6-pre1/drivers/hotplug/Makefile linux-2.5.6-pre2/drivers/hotplug/Makefile
--- linux-2.5.6-pre1/drivers/hotplug/Makefile	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/drivers/hotplug/Makefile	Thu Feb 28 13:34:21 2002
@@ -4,12 +4,13 @@
 
 O_TARGET	:= vmlinux-obj.o
 
-list-multi	:= cpqphp.o pci_hotplug.o
+list-multi	:= cpqphp.o pci_hotplug.o ibmphp.o
 
 export-objs	:= pci_hotplug_core.o pci_hotplug_util.o
 
 obj-$(CONFIG_HOTPLUG_PCI)		+= pci_hotplug.o
 obj-$(CONFIG_HOTPLUG_PCI_COMPAQ)	+= cpqphp.o
+obj-$(CONFIG_HOTPLUG_PCI_IBM)		+= ibmphp.o
 
 pci_hotplug-objs	:=	pci_hotplug_core.o	\
 				pci_hotplug_util.o
@@ -19,6 +20,12 @@
 				cpqphp_proc.o	\
 				cpqphp_pci.o
 
+ibmphp-objs		:=	ibmphp_core.o	\
+				ibmphp_ebda.o	\
+				ibmphp_pci.o	\
+				ibmphp_res.o	\
+				ibmphp_hpc.o
+
 ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y)
 	cpqphp-objs += cpqphp_nvram.o
 endif
@@ -32,3 +39,6 @@
 cpqphp.o: $(cpqphp-objs)
 	$(LD) -r -o $@ $(cpqphp-objs)
 
+ibmphp.o: $(ibmphp-objs)
+	$(LD) -r -o $@ $(ibmphp-objs)
+
diff -urN linux-2.5.6-pre1/drivers/hotplug/cpqphp_proc.c linux-2.5.6-pre2/drivers/hotplug/cpqphp_proc.c
--- linux-2.5.6-pre1/drivers/hotplug/cpqphp_proc.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre2/drivers/hotplug/cpqphp_proc.c	Thu Feb 28 13:34:21 2002
@@ -177,7 +177,7 @@
 	
 int cpqhp_proc_init_ctrl (void)
 {
-	ctrl_proc_root = proc_mkdir("driver/hpc", NULL);
+	ctrl_proc_root = proc_mkdir("hpc", proc_root_driver);
 	if (!ctrl_proc_root)
 		return -ENOMEM;
 	ctrl_proc_root->owner = THIS_MODULE;
diff -urN linux-2.5.6-pre1/drivers/hotplug/ibmphp.h linux-2.5.6-pre2/drivers/hotplug/ibmphp.h
--- linux-2.5.6-pre1/drivers/hotplug/ibmphp.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/drivers/hotplug/ibmphp.h	Thu Feb 28 13:34:21 2002
@@ -0,0 +1,745 @@
+#ifndef __IBMPHP_H
+#define __IBMPHP_H
+
+/*
+ * IBM Hot Plug Controller Driver
+ *
+ * Written By: Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation
+ *
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001,2002 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>
+ *
+ */
+
+#include "pci_hotplug.h"
+
+extern int ibmphp_debug;
+
+#if !defined(CONFIG_HOTPLUG_PCI_IBM_MODULE)
+	#define MY_NAME "ibmphpd"
+#else
+	#define MY_NAME THIS_MODULE->name
+#endif
+#define debug(fmt, arg...) do { if (ibmphp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg)
+
+
+/* EBDA stuff */
+
+/***********************************************************
+* SLOT CAPABILITY                                          *
+***********************************************************/
+
+#define EBDA_SLOT_133_MAX		0x20
+#define EBDA_SLOT_100_MAX		0x10
+#define EBDA_SLOT_66_MAX		0x02
+#define EBDA_SLOT_PCIX_CAP		0x08
+
+
+/************************************************************
+*  RESOURE TYPE                                             *
+************************************************************/
+
+#define EBDA_RSRC_TYPE_MASK		0x03
+#define EBDA_IO_RSRC_TYPE		0x00
+#define EBDA_MEM_RSRC_TYPE		0x01
+#define EBDA_PFM_RSRC_TYPE		0x03
+#define EBDA_RES_RSRC_TYPE		0x02
+
+
+/*************************************************************
+*  IO RESTRICTION TYPE                                       *
+*************************************************************/
+
+#define EBDA_IO_RESTRI_MASK		0x0c
+#define EBDA_NO_RESTRI			0x00
+#define EBDA_AVO_VGA_ADDR		0x04
+#define EBDA_AVO_VGA_ADDR_AND_ALIA	0x08
+#define EBDA_AVO_ISA_ADDR		0x0c
+
+
+/**************************************************************
+*  DEVICE TYPE DEF                                            *
+**************************************************************/
+
+#define EBDA_DEV_TYPE_MASK		0x10
+#define EBDA_PCI_DEV			0x10
+#define EBDA_NON_PCI_DEV		0x00
+
+
+/***************************************************************
+*  PRIMARY DEF DEFINITION                                      *
+***************************************************************/
+
+#define EBDA_PRI_DEF_MASK		0x20
+#define EBDA_PRI_PCI_BUS_INFO		0x20
+#define EBDA_NORM_DEV_RSRC_INFO		0x00
+
+
+//--------------------------------------------------------------
+// RIO TABLE DATA STRUCTURE
+//--------------------------------------------------------------
+
+struct rio_table_hdr {
+	u8 ver_num; 
+	u8 scal_count;
+	u8 riodev_count;
+	u16 offset;
+};
+
+//-------------------------------------------------------------
+// SCALABILITY DETAIL
+//-------------------------------------------------------------
+
+struct scal_detail {
+	u8 node_id;
+	u32 cbar;
+	u8 port0_node_connect;
+	u8 port0_port_connect;
+	u8 port1_node_connect;
+	u8 port1_port_connect;
+	u8 port2_node_connect;
+	u8 port2_port_connect;
+//	struct list_head scal_detail_list;
+};
+
+//--------------------------------------------------------------
+// RIO DETAIL 
+//--------------------------------------------------------------
+
+struct rio_detail {
+	u8 rio_node_id;
+	u32 bbar;
+	u8 rio_type;
+	u8 owner_id;
+	u8 port0_node_connect;
+	u8 port0_port_connect;
+	u8 port1_node_connect;
+	u8 port1_port_connect;
+	u8 first_slot_num;
+	u8 status;
+//	struct list_head rio_detail_list;
+};
+
+
+/****************************************************************
+*  HPC DESCRIPTOR NODE                                          *
+****************************************************************/
+
+struct ebda_hpc_list {
+	u8 format;
+	u16 num_ctlrs;
+	short phys_addr;
+//      struct list_head ebda_hpc_list;
+};
+
+/*****************************************************************
+*   IN HPC DATA STRUCTURE, THE ASSOCIATED SLOT AND BUS           *
+*   STRUCTURE                                                    *
+*****************************************************************/
+
+struct ebda_hpc_slot {
+	u8 slot_num;
+	u32 slot_bus_num;
+	u8 ctl_index;
+	u8 slot_cap;
+};
+
+struct ebda_hpc_bus {
+	u32 bus_num;
+/*
+	u8 slots_at_33_conv;
+	u8 slots_at_66_conv;
+	u8 slots_at_66_pcix;
+	u8 slots_at_100_pcix;
+	u8 slots_at_133_pcix;
+*/
+};
+
+
+/********************************************************************
+*   THREE TYPE OF HOT PLUG CONTROLER                                *
+********************************************************************/
+
+struct isa_ctlr_access {
+	u16 io_start;
+	u16 io_end;
+};
+
+struct pci_ctlr_access {
+	u8 bus;
+	u8 dev_fun;
+};
+
+struct wpeg_i2c_ctlr_access {
+	ulong wpegbbar;
+	u8 i2c_addr;
+};
+
+/*************************************************************************
+*   RSTC DESCRIPTOR NODE                                                 *
+*************************************************************************/
+
+struct ebda_rsrc_list {
+	u8 format;
+	u16 num_entries;
+	u16 phys_addr;
+	struct ebda_rsrc_list *next;
+};
+
+
+/***************************************************************************
+*   PCI RSRC NODE                                                          *
+***************************************************************************/
+
+struct ebda_pci_rsrc {
+	u8 rsrc_type;
+	u8 bus_num;
+	u8 dev_fun;
+	ulong start_addr;
+	ulong end_addr;
+	struct list_head ebda_pci_rsrc_list;
+};
+
+
+/***********************************************************
+* BUS_INFO DATE STRUCTURE                                  *
+***********************************************************/
+
+struct bus_info {
+	u8 slot_min;
+	u8 slot_max;
+	u8 slot_count;
+	u8 busno;
+	u8 current_speed;
+	u8 supported_speed;
+	u8 controller_id;
+	u8 supported_bus_mode;
+	u8 current_bus_mode;
+	u8 index;
+	struct list_head bus_info_list;
+};
+
+
+/***********************************************************
+* GLOBAL VARIABLES                                         *
+***********************************************************/
+extern struct list_head ibmphp_ebda_pci_rsrc_head;
+extern struct list_head ibmphp_slot_head;
+
+/***********************************************************
+* FUNCTION PROTOTYPES                                      *
+***********************************************************/
+
+extern void ibmphp_free_ebda_hpc_queue (void);
+extern int ibmphp_access_ebda (void);
+extern struct slot *ibmphp_get_slot_from_physical_num (u8);
+extern int ibmphp_get_total_hp_slots (void);
+extern void ibmphp_free_ibm_slot (struct slot *);
+extern void ibmphp_free_bus_info_queue (void);
+extern void ibmphp_free_ebda_pci_rsrc_queue (void);
+extern struct bus_info *ibmphp_find_same_bus_num (u32);
+extern int ibmphp_get_bus_index (u8);
+extern u16 ibmphp_get_total_controllers (void);
+
+/* passed parameters */
+#define MEM		0
+#define IO		1
+#define PFMEM		2
+
+/* bit masks */
+#define RESTYPE		0x03
+#define IOMASK		0x00	/* will need to take its complement */
+#define MMASK		0x01
+#define PFMASK		0x03
+#define PCIDEVMASK	0x10	/* we should always have PCI devices */
+#define PRIMARYBUSMASK	0x20
+
+/* pci specific defines */
+#define PCI_VENDOR_ID_NOTVALID		0xFFFF
+#define PCI_HEADER_TYPE_MULTIDEVICE	0x80
+#define PCI_HEADER_TYPE_MULTIBRIDGE	0x81
+
+#define LATENCY		0x64
+#define CACHE		64
+#define DEVICEENABLE	0x015F		/* CPQ has 0x0157 */
+
+#define IOBRIDGE	0x1000		/* 4k */
+#define MEMBRIDGE	0x100000	/* 1M */
+
+/* irqs */
+#define SCSI_IRQ	0x09
+#define LAN_IRQ		0x0A
+#define OTHER_IRQ	0x0B
+
+/* Data Structures */
+
+/* type is of the form x x xx xx
+ *                     | |  |  |_ 00 - I/O, 01 - Memory, 11 - PFMemory
+ *                     | |  - 00 - No Restrictions, 01 - Avoid VGA, 10 - Avoid
+ *                     | |    VGA and their aliases, 11 - Avoid ISA
+ *                     | - 1 - PCI device, 0 - non pci device
+ *                     - 1 - Primary PCI Bus Information (0 if Normal device)
+ * the IO restrictions [2:3] are only for primary buses
+ */
+
+
+/* we need this struct because there could be several resource blocks
+ * allocated per primary bus in the EBDA
+ */
+struct range_node {
+	int rangeno;
+	u32 start;
+	u32 end;
+	struct range_node *next;
+};
+
+struct bus_node {
+	u8 busno;
+	int noIORanges;
+	struct range_node *rangeIO;
+	int noMemRanges;
+	struct range_node *rangeMem;
+	int noPFMemRanges;
+	struct range_node *rangePFMem;
+	int needIOUpdate;
+	int needMemUpdate;
+	int needPFMemUpdate;
+	struct resource_node *firstIO;	/* first IO resource on the Bus */
+	struct resource_node *firstMem;	/* first memory resource on the Bus */
+	struct resource_node *firstPFMem;	/* first prefetchable memory resource on the Bus */
+	struct resource_node *firstPFMemFromMem;	/* when run out of pfmem available, taking from Mem */
+	struct list_head bus_list;
+};
+
+struct resource_node {
+	int rangeno;
+	u8 busno;
+	u8 devfunc;
+	u32 start;
+	u32 end;
+	u32 len;
+	int type;		/* MEM, IO, PFMEM */
+	u8 fromMem;		/* this is to indicate that the range is from
+				 * from the Memory bucket rather than from PFMem */
+	struct resource_node *next;
+	struct resource_node *nextRange;	/* for the other mem range on bus */
+};
+
+struct res_needed {
+	u32 mem;
+	u32 pfmem;
+	u32 io;
+	u8 not_correct;		/* needed for return */
+	int devices[32];	/* for device numbers behind this bridge */
+};
+
+/* functions */
+
+extern int ibmphp_rsrc_init (void);
+extern int ibmphp_add_resource (struct resource_node *);
+extern int ibmphp_remove_resource (struct resource_node *);
+extern int ibmphp_find_resource (struct bus_node *, u32, struct resource_node **, int);
+extern int ibmphp_check_resource (struct resource_node *, u8);
+extern int ibmphp_remove_bus (struct bus_node *, u8);
+extern void ibmphp_free_resources (void);
+extern int ibmphp_add_pfmem_from_mem (struct resource_node *);
+extern struct bus_node *ibmphp_find_res_bus (u8);
+extern void ibmphp_print_test (void);	/* for debugging purposes */
+
+extern void ibmphp_hpc_initvars (void);
+extern int ibmphp_hpc_readslot (struct slot *, u8, u8 *);
+extern int ibmphp_hpc_writeslot (struct slot *, u8);
+extern void ibmphp_lock_operations (void);
+extern void ibmphp_unlock_operations (void);
+extern int ibmphp_hpc_fillhpslotinfo (struct hotplug_slot *);
+extern int ibmphp_hpc_start_poll_thread (void);
+extern void ibmphp_hpc_stop_poll_thread (void);
+
+//----------------------------------------------------------------------------
+
+
+//----------------------------------------------------------------------------
+// HPC return codes
+//----------------------------------------------------------------------------
+#define FALSE				0x00
+#define TRUE				0x01
+#define HPC_ERROR			0xFF
+
+//-----------------------------------------------------------------------------
+// BUS INFO
+//-----------------------------------------------------------------------------
+#define BUS_SPEED			0x30
+#define BUS_MODE			0x40
+#define BUS_MODE_PCIX			0x01
+#define BUS_MODE_PCI			0x00
+#define BUS_SPEED_2			0x20
+#define BUS_SPEED_1			0x10
+#define BUS_SPEED_33			0x00
+#define BUS_SPEED_66			0x01
+#define BUS_SPEED_100			0x02
+#define BUS_SPEED_133			0x03
+#define BUS_SPEED_66PCIX		0x04
+#define BUS_SPEED_66UNKNOWN		0x05
+#define BUS_STATUS_AVAILABLE		0x01
+#define BUS_CONTROL_AVAILABLE		0x02
+#define SLOT_LATCH_REGS_SUPPORTED	0x10
+
+#define PRGM_MODEL_REV_LEVEL		0xF0
+#define MAX_ADAPTER_NONE		0x09
+
+//----------------------------------------------------------------------------
+// HPC 'write' operations/commands
+//----------------------------------------------------------------------------
+//	Command			Code	State	Write to reg
+//					Machine	at index
+//-------------------------	----	-------	------------
+#define HPC_CTLR_ENABLEIRQ	0x00	// N	15
+#define HPC_CTLR_DISABLEIRQ	0x01	// N	15
+#define HPC_SLOT_OFF		0x02	// Y	0-14
+#define HPC_SLOT_ON		0x03	// Y	0-14
+#define HPC_SLOT_ATTNOFF	0x04	// N	0-14
+#define HPC_SLOT_ATTNON		0x05	// N	0-14
+#define HPC_CTLR_CLEARIRQ	0x06	// N	15
+#define HPC_CTLR_RESET		0x07	// Y	15
+#define HPC_CTLR_IRQSTEER	0x08	// N	15
+#define HPC_BUS_33CONVMODE	0x09	// Y	31-34
+#define HPC_BUS_66CONVMODE	0x0A	// Y	31-34
+#define HPC_BUS_66PCIXMODE	0x0B	// Y	31-34
+#define HPC_BUS_100PCIXMODE	0x0C	// Y	31-34
+#define HPC_BUS_133PCIXMODE	0x0D	// Y	31-34
+#define HPC_ALLSLOT_OFF		0x11	// Y	15
+#define HPC_ALLSLOT_ON		0x12	// Y	15
+#define HPC_SLOT_BLINKLED	0x13	// N	0-14
+
+//----------------------------------------------------------------------------
+// read commands
+//----------------------------------------------------------------------------
+#define READ_SLOTSTATUS		0x01
+#define READ_EXTSLOTSTATUS	0x02
+#define READ_BUSSTATUS		0x03
+#define READ_CTLRSTATUS		0x04
+#define READ_ALLSTAT		0x05
+#define READ_ALLSLOT		0x06
+#define READ_SLOTLATCHLOWREG	0x07
+#define READ_REVLEVEL		0x08
+#define READ_HPCOPTIONS		0x09
+//----------------------------------------------------------------------------
+// slot status
+//----------------------------------------------------------------------------
+#define HPC_SLOT_POWER		0x01
+#define HPC_SLOT_CONNECT	0x02
+#define HPC_SLOT_ATTN		0x04
+#define HPC_SLOT_PRSNT2		0x08
+#define HPC_SLOT_PRSNT1		0x10
+#define HPC_SLOT_PWRGD		0x20
+#define HPC_SLOT_BUS_SPEED	0x40
+#define HPC_SLOT_LATCH		0x80
+
+//----------------------------------------------------------------------------
+// HPC_SLOT_POWER status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_POWER_OFF	0x00
+#define HPC_SLOT_POWER_ON	0x01
+
+//----------------------------------------------------------------------------
+// HPC_SLOT_CONNECT status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_CONNECTED	0x00
+#define HPC_SLOT_DISCONNECTED	0x01
+
+//----------------------------------------------------------------------------
+// HPC_SLOT_ATTN status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_ATTN_OFF	0x00
+#define HPC_SLOT_ATTN_ON	0x01
+#define HPC_SLOT_ATTN_BLINK	0x02
+
+//----------------------------------------------------------------------------
+// HPC_SLOT_PRSNT status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_EMPTY		0x00
+#define HPC_SLOT_PRSNT_7	0x01
+#define HPC_SLOT_PRSNT_15	0x02
+#define HPC_SLOT_PRSNT_25	0x03
+
+//----------------------------------------------------------------------------
+// HPC_SLOT_PWRGD status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_PWRGD_FAULT_NONE	0x00
+#define HPC_SLOT_PWRGD_GOOD		0x01
+
+//----------------------------------------------------------------------------
+// HPC_SLOT_BUS_SPEED status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_BUS_SPEED_OK	0x00
+#define HPC_SLOT_BUS_SPEED_MISM	0x01
+
+//----------------------------------------------------------------------------
+// HPC_SLOT_LATCH status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_LATCH_OPEN	0x01	// NOTE : in PCI spec bit off = open
+#define HPC_SLOT_LATCH_CLOSED	0x00	// NOTE : in PCI spec bit on  = closed
+
+
+//----------------------------------------------------------------------------
+// extended slot status
+//----------------------------------------------------------------------------
+#define HPC_SLOT_PCIX		0x01
+#define HPC_SLOT_SPEED1		0x02
+#define HPC_SLOT_SPEED2		0x04
+#define HPC_SLOT_BLINK_ATTN	0x08
+#define HPC_SLOT_RSRVD1		0x10
+#define HPC_SLOT_RSRVD2		0x20
+#define HPC_SLOT_BUS_MODE	0x40
+#define HPC_SLOT_RSRVD3		0x80
+
+//----------------------------------------------------------------------------
+// HPC_XSLOT_PCIX_CAP status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_PCIX_NO	0x00
+#define HPC_SLOT_PCIX_YES	0x01
+
+//----------------------------------------------------------------------------
+// HPC_XSLOT_SPEED status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_SPEED_33	0x00
+#define HPC_SLOT_SPEED_66	0x01
+#define HPC_SLOT_SPEED_133	0x02
+
+//----------------------------------------------------------------------------
+// HPC_XSLOT_ATTN_BLINK status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_ATTN_BLINK_OFF	0x00
+#define HPC_SLOT_ATTN_BLINK_ON	0x01
+
+//----------------------------------------------------------------------------
+// HPC_XSLOT_BUS_MODE status return codes
+//----------------------------------------------------------------------------
+#define HPC_SLOT_BUS_MODE_OK	0x00
+#define HPC_SLOT_BUS_MODE_MISM	0x01
+
+//----------------------------------------------------------------------------
+// Controller status
+//----------------------------------------------------------------------------
+#define HPC_CTLR_WORKING	0x01
+#define HPC_CTLR_FINISHED	0x02
+#define HPC_CTLR_RESULT0	0x04
+#define HPC_CTLR_RESULT1	0x08
+#define HPC_CTLR_RESULE2	0x10
+#define HPC_CTLR_RESULT3	0x20
+#define HPC_CTLR_IRQ_ROUTG	0x40
+#define HPC_CTLR_IRQ_PENDG	0x80
+
+//----------------------------------------------------------------------------
+// HPC_CTLR_WROKING status return codes
+//----------------------------------------------------------------------------
+#define HPC_CTLR_WORKING_NO	0x00
+#define HPC_CTLR_WORKING_YES	0x01
+
+//----------------------------------------------------------------------------
+// HPC_CTLR_FINISHED status return codes
+//----------------------------------------------------------------------------
+#define HPC_CTLR_FINISHED_NO	0x00
+#define HPC_CTLR_FINISHED_YES	0x01
+
+//----------------------------------------------------------------------------
+// HPC_CTLR_RESULT status return codes
+//----------------------------------------------------------------------------
+#define HPC_CTLR_RESULT_SUCCESS	0x00
+#define HPC_CTLR_RESULT_FAILED	0x01
+#define HPC_CTLR_RESULT_RSVD	0x02
+#define HPC_CTLR_RESULT_NORESP	0x03
+
+
+//----------------------------------------------------------------------------
+// macro for slot info
+//----------------------------------------------------------------------------
+#define SLOT_POWER(s)	((u8) ((s & HPC_SLOT_POWER) \
+	? HPC_SLOT_POWER_ON : HPC_SLOT_POWER_OFF))
+
+#define SLOT_CONNECT(s)	((u8) ((s & HPC_SLOT_CONNECT) \
+	? HPC_SLOT_DISCONNECTED : HPC_SLOT_CONNECTED))
+
+#define SLOT_ATTN(s,es)	((u8) ((es & HPC_SLOT_BLINK_ATTN) \
+	? HPC_SLOT_ATTN_BLINK \
+	: ((s & HPC_SLOT_ATTN) ? HPC_SLOT_ATTN_ON : HPC_SLOT_ATTN_OFF)))
+
+#define SLOT_PRESENT(s)	((u8) ((s & HPC_SLOT_PRSNT1) \
+	? ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_EMPTY : HPC_SLOT_PRSNT_15) \
+	: ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_PRSNT_25 : HPC_SLOT_PRSNT_7)))
+
+#define SLOT_PWRGD(s)	((u8) ((s & HPC_SLOT_PWRGD) \
+	? HPC_SLOT_PWRGD_GOOD : HPC_SLOT_PWRGD_FAULT_NONE))
+
+#define SLOT_BUS_SPEED(s)	((u8) ((s & HPC_SLOT_BUS_SPEED) \
+	? HPC_SLOT_BUS_SPEED_MISM : HPC_SLOT_BUS_SPEED_OK))
+
+#define SLOT_LATCH(s)	((u8) ((s & HPC_SLOT_LATCH) \
+	? HPC_SLOT_LATCH_CLOSED : HPC_SLOT_LATCH_OPEN))
+
+#define SLOT_PCIX(es)	((u8) ((es & HPC_SLOT_PCIX) \
+	? HPC_SLOT_PCIX_YES : HPC_SLOT_PCIX_NO))
+
+#define SLOT_SPEED(es)	((u8) ((es & HPC_SLOT_SPEED2) \
+	? ((es & HPC_SLOT_SPEED1) ? HPC_SLOT_SPEED_133   \
+				: HPC_SLOT_SPEED_66)   \
+	: HPC_SLOT_SPEED_33))
+
+#define SLOT_BUS_MODE(es)	((u8) ((es & HPC_SLOT_BUS_MODE) \
+	? HPC_SLOT_BUS_MODE_MISM : HPC_SLOT_BUS_MODE_OK))
+
+//--------------------------------------------------------------------------
+// macro for bus info
+//---------------------------------------------------------------------------
+#define CURRENT_BUS_SPEED(s)	((u8) (s & BUS_SPEED_2) \
+	? ((s & BUS_SPEED_1) ? BUS_SPEED_133 : BUS_SPEED_100) \
+	: ((s & BUS_SPEED_1) ? BUS_SPEED_66 : BUS_SPEED_33))
+
+#define CURRENT_BUS_MODE(s)	((u8) (s & BUS_MODE) ? BUS_MODE_PCIX : BUS_MODE_PCI)
+
+#define READ_BUS_STATUS(s)	((u8) (s->options & BUS_STATUS_AVAILABLE))
+
+#define READ_BUS_MODE(s)	((s->revision & PRGM_MODEL_REV_LEVEL) >= 0x20)
+
+#define SET_BUS_STATUS(s)	((u8) (s->options & BUS_CONTROL_AVAILABLE))
+
+#define READ_SLOT_LATCH(s)	((u8) (s->options & SLOT_LATCH_REGS_SUPPORTED))
+
+//----------------------------------------------------------------------------
+// macro for controller info
+//----------------------------------------------------------------------------
+#define CTLR_WORKING(c) ((u8) ((c & HPC_CTLR_WORKING) \
+	? HPC_CTLR_WORKING_YES : HPC_CTLR_WORKING_NO))
+#define CTLR_FINISHED(c) ((u8) ((c & HPC_CTLR_FINISHED) \
+	? HPC_CTLR_FINISHED_YES : HPC_CTLR_FINISHED_NO))
+#define CTLR_RESULT(c) ((u8) ((c & HPC_CTLR_RESULT1)  \
+	? ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_NORESP \
+				: HPC_CTLR_RESULT_RSVD)  \
+	: ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_FAILED \
+				: HPC_CTLR_RESULT_SUCCESS)))
+
+// command that affect the state machine of HPC
+#define NEEDTOCHECK_CMDSTATUS(c) ((c == HPC_SLOT_OFF)        || \
+				  (c == HPC_SLOT_ON)         || \
+				  (c == HPC_CTLR_RESET)      || \
+				  (c == HPC_BUS_33CONVMODE)  || \
+				  (c == HPC_BUS_66CONVMODE)  || \
+				  (c == HPC_BUS_66PCIXMODE)  || \
+				  (c == HPC_BUS_100PCIXMODE) || \
+				  (c == HPC_BUS_133PCIXMODE) || \
+				  (c == HPC_ALLSLOT_OFF)     || \
+				  (c == HPC_ALLSLOT_ON))
+
+
+/* Core part of the driver */
+
+#define ENABLE		1
+#define DISABLE		0
+
+#define ADD		0
+#define REMOVE		1
+#define DETAIL		2
+
+#define MAX_OPS		3
+#define CARD_INFO	0x07
+#define PCIX133		0x07
+#define PCIX66		0x05
+#define PCI66		0x04
+
+extern struct pci_ops *ibmphp_pci_root_ops;
+
+/* Variables */
+
+struct pci_func {
+	struct pci_dev *dev;	/* from the OS */
+	u8 busno;
+	u8 device;
+	u8 function;
+	struct resource_node *io[6];
+	struct resource_node *mem[6];
+	struct resource_node *pfmem[6];
+	struct pci_func *next;
+	int devices[32];	/* for bridge config */
+	u8 irq[4];		/* for interrupt config */
+	u8 bus;			/* flag for unconfiguring, to say if PPB */
+};
+
+struct slot {
+	u8 bus;
+	u8 device;
+	u8 number;
+	char name[100];
+	u32 capabilities;
+	struct hotplug_slot *hotplug_slot;
+	struct controller *ctrl;
+	struct pci_func *func;
+	u8 irq[4];
+	u8 flag;		/* this is for disable slot and polling */
+	int bit_mode;		/* 0 = 32, 1 = 64 */
+	u8 ctlr_index;
+	struct bus_info *bus_on;
+	struct list_head ibm_slot_list;
+	u8 status;
+	u8 ext_status;
+	u8 busstatus;
+};
+
+struct controller {
+	struct ebda_hpc_slot *slots;
+	struct ebda_hpc_bus *buses;
+	u8 revision;
+	u8 options;		/* which options HPC supports */
+	u8 status;
+	u8 ctlr_id;		/* TONI */
+	u8 slot_count;
+	u8 bus_count;
+	u8 ctlr_relative_id;
+	u32 irq;
+	union {
+		struct isa_ctlr_access isa_ctlr;
+		struct pci_ctlr_access pci_ctlr;
+		struct wpeg_i2c_ctlr_access wpeg_ctlr;
+	} u;
+	u8 ctlr_type;
+	struct list_head ebda_hpc_list;
+};
+
+/* Functions */
+
+extern int ibmphp_init_devno (struct slot **);	/* This function is called from EBDA, so we need it not be static */
+extern int ibmphp_disable_slot (struct hotplug_slot *);	/* This function is called from HPC, so we need it to not be static */
+extern int ibmphp_update_slot_info (struct slot *);	/* This function is called from HPC, so we need it to not be be static */
+extern int ibmphp_configure_card (struct pci_func *, u8);
+extern int ibmphp_unconfigure_card (struct slot **, int);
+extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops;
+
+static inline void long_delay (int delay)
+{
+	set_current_state (TASK_INTERRUPTIBLE);
+	schedule_timeout (delay);
+}
+
+#endif				//__IBMPHP_H
+
diff -urN linux-2.5.6-pre1/drivers/hotplug/ibmphp_core.c linux-2.5.6-pre2/drivers/hotplug/ibmphp_core.c
--- linux-2.5.6-pre1/drivers/hotplug/ibmphp_core.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/drivers/hotplug/ibmphp_core.c	Thu Feb 28 13:34:21 2002
@@ -0,0 +1,1480 @@
+/*
+ * IBM Hot Plug Controller Driver
+ *
+ * Written By: Chuck Cole, Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation
+ *
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001,2002 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/smp_lock.h>
+#include "../../arch/i386/kernel/pci-i386.h"	/* for struct irq_routing_table */
+#include "ibmphp.h"
+
+#define attn_on(sl)  ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNON)
+#define attn_off(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNOFF)
+#define attn_LED_blink(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_BLINKLED)
+#define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev)
+#define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt)
+
+#define DRIVER_VERSION	"0.1"
+#define DRIVER_DESC	"IBM Hot Plug PCI Controller Driver"
+
+int ibmphp_debug;
+
+static int debug;
+MODULE_PARM (debug, "i");
+MODULE_PARM_DESC (debug, "Debugging mode enabled or not");
+MODULE_LICENSE ("GPL");
+MODULE_DESCRIPTION (DRIVER_DESC);
+
+static int *ops[MAX_OPS + 1];
+static struct pci_ops *ibmphp_pci_root_ops;
+static int max_slots;
+
+static int irqs[16];    /* PIC mode IRQ's we're using so far (in case MPS tables don't provide default info for empty slots */
+
+static int init_flag;
+
+/*
+static int get_max_adapter_speed_1 (struct hotplug_slot *, u8 *, u8);
+
+static inline int get_max_adapter_speed (struct hotplug_slot *hs, u8 *value)
+{
+	return get_max_adapter_speed_1 (hs, value, 1);
+}
+*/
+static inline int get_cur_bus_info (struct slot **sl) 
+{
+	int rc = 1;
+	struct slot * slot_cur = *sl;
+
+	debug ("options = %x\n", slot_cur->ctrl->options);
+	debug ("revision = %x\n", slot_cur->ctrl->revision);	
+
+	if (READ_BUS_STATUS (slot_cur->ctrl)) 
+		rc = ibmphp_hpc_readslot (slot_cur, READ_BUSSTATUS, NULL);
+	
+	if (rc) 
+		return rc;
+	  
+	slot_cur->bus_on->current_speed = CURRENT_BUS_SPEED (slot_cur->busstatus);
+	if (READ_BUS_MODE (slot_cur->ctrl))
+		slot_cur->bus_on->current_bus_mode = CURRENT_BUS_MODE (slot_cur->busstatus);
+
+	debug ("busstatus = %x, bus_speed = %x, bus_mode = %x\n", slot_cur->busstatus, slot_cur->bus_on->current_speed, slot_cur->bus_on->current_bus_mode);
+	
+	*sl = slot_cur;
+	return 0;
+}
+
+static inline int slot_update (struct slot **sl)
+{
+	int rc;
+ 	rc = ibmphp_hpc_readslot (*sl, READ_ALLSTAT, NULL);
+	if (rc) 
+		return rc;
+	if (!init_flag)
+		return get_cur_bus_info (sl);
+	return rc;
+}
+
+static int get_max_slots (void)
+{
+	struct list_head * tmp;
+	int slot_count = 0;
+
+	list_for_each (tmp, &ibmphp_slot_head) 
+		++slot_count;
+	return slot_count;
+}
+
+/* This routine will put the correct slot->device information per slot.  It's
+ * called from initialization of the slot structures. It will also assign
+ * interrupt numbers per each slot.
+ * Parameters: struct slot
+ * Returns 0 or errors
+ */
+int ibmphp_init_devno (struct slot **cur_slot)
+{
+	struct irq_routing_table *rtable;
+	int len;
+	int loop;
+	int i;
+
+	rtable = pcibios_get_irq_routing_table ();
+	if (!rtable) {
+		err ("no BIOS routing table...\n");
+		return -ENOMEM;
+	}
+
+	len = (rtable->size - sizeof (struct irq_routing_table)) / sizeof (struct irq_info);
+
+	if (!len)
+		return -1;
+	for (loop = 0; loop < len; loop++) {
+		if ((*cur_slot)->number == rtable->slots[loop].slot) {
+		if ((*cur_slot)->bus == rtable->slots[loop].bus) {
+			(*cur_slot)->device = PCI_SLOT (rtable->slots[loop].devfn);
+			for (i = 0; i < 4; i++)
+				(*cur_slot)->irq[i] = IO_APIC_get_PCI_irq_vector ((int) (*cur_slot)->bus, (int) (*cur_slot)->device, i);
+
+				debug ("(*cur_slot)->irq[0] = %x\n", (*cur_slot)->irq[0]);
+				debug ("(*cur_slot)->irq[1] = %x\n", (*cur_slot)->irq[1]);
+				debug ("(*cur_slot)->irq[2] = %x\n", (*cur_slot)->irq[2]);
+				debug ("(*cur_slot)->irq[3] = %x\n", (*cur_slot)->irq[3]);
+
+				debug ("rtable->exlusive_irqs = %x\n", rtable->exclusive_irqs);
+				debug ("rtable->slots[loop].irq[0].bitmap = %x\n", rtable->slots[loop].irq[0].bitmap);
+				debug ("rtable->slots[loop].irq[1].bitmap = %x\n", rtable->slots[loop].irq[1].bitmap);
+				debug ("rtable->slots[loop].irq[2].bitmap = %x\n", rtable->slots[loop].irq[2].bitmap);
+				debug ("rtable->slots[loop].irq[3].bitmap = %x\n", rtable->slots[loop].irq[3].bitmap);
+
+				debug ("rtable->slots[loop].irq[0].link= %x\n", rtable->slots[loop].irq[0].link);
+				debug ("rtable->slots[loop].irq[1].link = %x\n", rtable->slots[loop].irq[1].link);
+				debug ("rtable->slots[loop].irq[2].link = %x\n", rtable->slots[loop].irq[2].link);
+				debug ("rtable->slots[loop].irq[3].link = %x\n", rtable->slots[loop].irq[3].link);
+				debug ("end of init_devno\n");
+				return 0;
+			}
+		}
+	}
+
+	return -1;
+}
+
+static inline int power_on (struct slot *slot_cur)
+{
+	u8 cmd = HPC_SLOT_ON;
+	int retval;
+
+	retval = ibmphp_hpc_writeslot (slot_cur, cmd);
+	if (retval) {
+		err ("power on failed\n");
+		return retval;
+	}
+	if (CTLR_RESULT (slot_cur->ctrl->status)) {
+		err ("command not completed successfully in power_on \n");
+		return -EIO;
+	}
+	long_delay (3 * HZ); /* For ServeRAID cards, and some 66 PCI */
+	return 0;
+}
+
+static inline int power_off (struct slot *slot_cur)
+{
+	u8 cmd = HPC_SLOT_OFF;
+	int retval;
+
+	retval = ibmphp_hpc_writeslot (slot_cur, cmd);
+	if (retval) {
+		err ("power off failed \n");
+		return retval;
+	}
+	if (CTLR_RESULT (slot_cur->ctrl->status)) {
+		err ("command not completed successfully in power_off \n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value)
+{
+	int rc = 0;
+	struct slot *pslot;
+	u8 cmd;
+	int hpcrc = 0;
+
+	debug ("set_attention_status - Entry hotplug_slot[%lx] value[%x]\n", (ulong) hotplug_slot, value);
+	ibmphp_lock_operations ();
+	cmd = 0x00;     // avoid compiler warning
+
+	if (hotplug_slot) {
+		switch (value) {
+		case HPC_SLOT_ATTN_OFF:
+			cmd = HPC_SLOT_ATTNOFF;
+			break;
+		case HPC_SLOT_ATTN_ON:
+			cmd = HPC_SLOT_ATTNON;
+			break;
+		case HPC_SLOT_ATTN_BLINK:
+			cmd = HPC_SLOT_BLINKLED;
+			break;
+		default:
+			rc = -ENODEV;
+			err ("set_attention_status - Error : invalid input [%x]\n", value);
+			break;
+		}
+		if (rc == 0) {
+			pslot = (struct slot *) hotplug_slot->private;
+			if (pslot)
+				hpcrc = ibmphp_hpc_writeslot (pslot, cmd);
+			else
+				rc = -ENODEV;
+		}
+	} else	
+		rc = -ENODEV;
+
+	if (hpcrc)
+		rc = hpcrc;
+
+	ibmphp_unlock_operations ();
+
+	debug ("set_attention_status - Exit rc[%d]\n", rc);
+	return rc;
+}
+
+static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	int rc = -ENODEV;
+	struct slot *pslot;
+	int hpcrc = 0;
+	struct slot myslot;
+
+	debug ("get_attention_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value);
+        
+	ibmphp_lock_operations ();
+	if (hotplug_slot && value) {
+		pslot = (struct slot *) hotplug_slot->private;
+		if (pslot) {
+			memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot));
+			hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status));
+			if (!hpcrc)
+				hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status));
+			if (!hpcrc) {
+				*value = SLOT_ATTN (myslot.status, myslot.ext_status);
+				rc = 0;
+			}
+		}
+	} else
+		rc = -ENODEV;
+
+	if (hpcrc)
+		rc = hpcrc;
+
+	ibmphp_unlock_operations ();
+	debug ("get_attention_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
+	return rc;
+}
+
+static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	int rc = -ENODEV;
+	struct slot *pslot;
+	int hpcrc = 0;
+	struct slot myslot;
+
+	debug ("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value);
+	ibmphp_lock_operations ();
+	if (hotplug_slot && value) {
+		pslot = (struct slot *) hotplug_slot->private;
+		if (pslot) {
+			memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot));
+			hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status));
+			if (!hpcrc) {
+				*value = SLOT_LATCH (myslot.status);
+				rc = 0;
+			}
+		}
+	} else
+		rc = -ENODEV;
+
+	if (hpcrc)
+		rc = hpcrc;
+
+	ibmphp_unlock_operations ();
+	debug ("get_latch_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
+	return rc;
+}
+
+
+static int get_power_status (struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	int rc = -ENODEV;
+	struct slot *pslot;
+	int hpcrc = 0;
+	struct slot myslot;
+
+	debug ("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value);
+	ibmphp_lock_operations ();
+	if (hotplug_slot && value) {
+		pslot = (struct slot *) hotplug_slot->private;
+		if (pslot) {
+			memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot));
+			hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status));
+			if (!hpcrc) {
+				*value = SLOT_POWER (myslot.status);
+				rc = 0;
+			}
+		}
+	} else
+		rc = -ENODEV;
+
+	if (hpcrc)
+		rc = hpcrc;
+
+	ibmphp_unlock_operations ();
+	debug ("get_power_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
+	return rc;
+}
+
+static int get_adapter_present (struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	int rc = -ENODEV;
+	struct slot *pslot;
+	u8 present;
+	int hpcrc = 0;
+	struct slot myslot;
+
+	debug ("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value);
+	ibmphp_lock_operations ();
+	if (hotplug_slot && value) {
+		pslot = (struct slot *) hotplug_slot->private;
+		if (pslot) {
+			memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot));
+			hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status));
+			if (!hpcrc) {
+				present = SLOT_PRESENT (myslot.status);
+				if (present == HPC_SLOT_EMPTY)
+					*value = 0;
+				else
+					*value = 1;
+				rc = 0;
+			}
+		}
+	} else
+		rc = -ENODEV;
+	if (hpcrc)
+		rc = hpcrc;
+
+	ibmphp_unlock_operations ();
+	debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
+	return rc;
+}
+/*
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	int rc = -ENODEV;
+	struct slot *pslot;
+	u8 mode = 0;
+
+	debug ("get_max_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+
+	ibmphp_lock_operations ();
+
+	if (hotplug_slot && value) {
+		pslot = (struct slot *) hotplug_slot->private;
+		if (pslot) {
+			rc = 0;
+			mode = pslot->bus_on->supported_bus_mode;
+			*value = pslot->bus_on->supported_speed;
+			*value &= 0x0f;
+
+			if (mode == BUS_MODE_PCIX)
+				*value |= 0x80;
+			else if (mode == BUS_MODE_PCI)
+				*value |= 0x40;
+			else
+				*value |= 0x20;
+		}
+	} else
+		rc = -ENODEV;
+
+	ibmphp_unlock_operations ();
+	debug ("get_max_bus_speed - Exit rc[%d] value[%x]\n", rc, *value);
+	return rc;
+}
+
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	int rc = -ENODEV;
+	struct slot *pslot;
+	u8 mode = 0;
+
+	debug ("get_cur_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+
+	ibmphp_lock_operations ();
+
+	if (hotplug_slot && value) {
+		pslot = (struct slot *) hotplug_slot->private;
+		if (pslot) {
+			rc = get_cur_bus_info (&pslot);
+			if (!rc) {
+				mode = pslot->bus_on->current_bus_mode;
+				*value = pslot->bus_on->current_speed;
+				*value &= 0x0f;
+				
+				if (mode == BUS_MODE_PCIX)
+					*value |= 0x80;
+				else if (mode == BUS_MODE_PCI)
+					*value |= 0x40;
+				else
+					*value |= 0x20;	
+			}
+		}
+	} else
+		rc = -ENODEV;
+
+	ibmphp_unlock_operations ();
+	debug ("get_cur_bus_speed - Exit rc[%d] value[%x]\n", rc, *value);
+	return rc;
+}
+
+static int get_max_adapter_speed_1 (struct hotplug_slot *hotplug_slot, u8 * value, u8 flag)
+{
+	int rc = -ENODEV;
+	struct slot *pslot;
+	int hpcrc = 0;
+	struct slot myslot;
+
+	debug ("get_max_adapter_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+
+	if (flag)
+		ibmphp_lock_operations ();
+
+	if (hotplug_slot && value) {
+		pslot = (struct slot *) hotplug_slot->private;
+		if (pslot) {
+			memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot));
+			hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status));
+
+			if (!(SLOT_LATCH (myslot.status)) && (SLOT_PRESENT (myslot.status))) {
+				hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status));
+				if (!hpcrc) {
+					*value = SLOT_SPEED (myslot.ext_status);
+					rc = 0;
+				}
+			} else {
+				*value = MAX_ADAPTER_NONE;
+				rc = 0;
+			}
+                }
+        } else
+		rc = -ENODEV;
+
+	if (hpcrc)
+		rc = hpcrc;
+
+	if (flag)
+		ibmphp_unlock_operations ();
+
+	debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
+	return rc;
+}
+
+static int get_card_bus_names (struct hotplug_slot *hotplug_slot, char * value)
+{
+	int rc = -ENODEV;
+	struct slot *pslot = NULL;
+	struct pci_dev * dev = NULL;
+
+	debug ("get_card_bus_names - Entry hotplug_slot[%lx] \n", (ulong)hotplug_slot);
+
+	ibmphp_lock_operations ();
+
+	if (hotplug_slot) {
+		pslot = (struct slot *) hotplug_slot->private;
+		if (pslot) {
+			rc = 0;
+			if (pslot->func)
+				dev = pslot->func->dev;
+			else
+                		dev = pci_find_slot (pslot->bus, (pslot->device << 3) | (0x00 & 0x7));
+			if (dev) 
+				snprintf (value, 100, "Bus %d : %s", pslot->bus,dev->name);
+			else
+				snprintf (value, 100, "Bus %d", pslot->bus);
+			
+				
+		}
+	} else
+		rc = -ENODEV;
+
+	ibmphp_unlock_operations ();
+	debug ("get_card_bus_names - Exit rc[%d] value[%x]\n", rc, *value);
+	return rc;
+}
+
+*/
+/*******************************************************************************
+ * This routine will initialize the ops data structure used in the validate
+ * function. It will also power off empty slots that are powered on since BIOS
+ * leaves those on, albeit disconnected
+ ******************************************************************************/
+static int init_ops (void)
+{
+	struct slot *slot_cur;
+	int retval;
+	int j;
+	int rc;
+
+	for (j = 0; j < MAX_OPS; j++) {
+		ops[j] = (int *) kmalloc ((max_slots + 1) * sizeof (int), GFP_KERNEL);
+		if (!ops[j]) {
+			err ("out of system memory \n");
+			return -ENOMEM;
+		}
+	}
+
+	ops[ADD][0] = 0;
+	ops[REMOVE][0] = 0;
+	ops[DETAIL][0] = 0;
+
+	for (j = 1; j <= max_slots; j++) {
+
+		slot_cur = ibmphp_get_slot_from_physical_num (j);
+
+		debug ("BEFORE GETTING SLOT STATUS, slot # %x\n", slot_cur->number);
+
+		if (slot_cur->ctrl->revision == 0xFF) 
+			if (get_ctrl_revision (slot_cur, &slot_cur->ctrl->revision))
+				return -1;
+
+		if (slot_cur->bus_on->current_speed == 0xFF) 
+			if (get_cur_bus_info (&slot_cur)) 
+				return -1;
+
+		if (slot_cur->ctrl->options == 0xFF)
+			if (get_hpc_options (slot_cur, &slot_cur->ctrl->options))
+				return -1;
+
+		retval = slot_update (&slot_cur);
+		if (retval)
+			return retval;
+
+		debug ("status = %x, ext_status = %x\n", slot_cur->status, slot_cur->ext_status);
+		debug ("SLOT_POWER = %x, SLOT_PRESENT = %x, SLOT_LATCH = %x\n", SLOT_POWER (slot_cur->status), SLOT_PRESENT (slot_cur->status), SLOT_LATCH (slot_cur->status));
+
+		if (!(SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
+			/* No power, adapter, and latch closed */
+			ops[ADD][j] = 1;
+		else
+			ops[ADD][j] = 0;
+
+		ops[DETAIL][j] = 1;
+
+		if ((SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
+			/*Power,adapter,latch closed */
+			ops[REMOVE][j] = 1;
+		else
+			ops[REMOVE][j] = 0;
+
+		if ((SLOT_POWER (slot_cur->status)) && !(SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status))) {
+			debug ("BEFORE POWER OFF COMMAND\n");
+				rc = power_off (slot_cur);
+				if (rc)
+					return rc;
+
+	/*		retval = slot_update (&slot_cur);
+	 *		if (retval)
+	 *			return retval;
+	 *		ibmphp_update_slot_info (slot_cur);
+	 */
+		}
+	}
+	init_flag = 0;
+	return 0;
+}
+
+/* This operation will check whether the slot is within the bounds and
+ * the operation is valid to perform on that slot
+ * Parameters: slot, operation
+ * Returns: 0 or error codes
+ */
+static int validate (struct slot *slot_cur, int opn)
+{
+	int number;
+	int retval;
+
+	if (!slot_cur)
+		return -ENODEV;
+	number = slot_cur->number;
+	if ((number > max_slots) || (number < 0))
+		return -EBADSLT;
+	debug ("slot_number in validate is %d\n", slot_cur->number);
+
+	retval = slot_update (&slot_cur);
+	if (retval)
+		return retval;
+
+	if (!(SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
+	    && !(SLOT_LATCH (slot_cur->status)))
+		ops[ADD][number] = 1;
+	else
+		ops[ADD][number] = 0;
+
+	ops[DETAIL][number] = 1;
+
+	if ((SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
+	    && !(SLOT_LATCH (slot_cur->status)))
+		ops[REMOVE][number] = 1;
+	else
+		ops[REMOVE][number] = 0;
+
+	switch (opn) {
+		case ENABLE:
+			if (ops[ADD][number])
+				return 0;
+			break;
+		case DISABLE:
+			if (ops[REMOVE][number])
+				return 0;
+			break;
+		case DETAIL:
+			if (ops[DETAIL][number])
+				return 0;
+			break;
+		default:
+			return -EINVAL;
+			break;
+	}
+	err ("validate failed....\n");
+	return -EINVAL;
+}
+
+/********************************************************************************
+ * This routine is for updating the data structures in the hotplug core
+ * Parameters: struct slot
+ * Returns: 0 or error
+ *******************************************************************************/
+int ibmphp_update_slot_info (struct slot *slot_cur)
+{
+	struct hotplug_slot_info *info;
+	char buffer[10];
+	int rc;
+//	u8 bus_speed;
+
+	info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+	if (!info) {
+		err ("out of system memory \n");
+		return -ENOMEM;
+	}
+        
+	snprintf (buffer, 10, "%d", slot_cur->number);
+	info->power_status = SLOT_POWER (slot_cur->status);
+	info->attention_status = SLOT_ATTN (slot_cur->status, slot_cur->ext_status);
+	info->latch_status = SLOT_LATCH (slot_cur->status);
+        if (!SLOT_PRESENT (slot_cur->status)) {
+                info->adapter_status = 0;
+//		info->max_adapter_speed_status = MAX_ADAPTER_NONE;
+	} else {
+                info->adapter_status = 1;
+//		get_max_adapter_speed_1 (slot_cur->hotplug_slot, &info->max_adapter_speed_status, 0);
+	}
+/*
+	bus_speed = slot_cur->bus_on->current_speed;
+	bus_speed &= 0x0f;
+                        
+	if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX)
+		bus_speed |= 0x80;
+	else if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCI)
+		bus_speed |= 0x40;
+	else
+		bus_speed |= 0x20;
+
+	info->cur_bus_speed_status = bus_speed;
+	info->max_bus_speed_status = slot_cur->hotplug_slot->info->max_bus_speed_status;
+	// To do: card_bus_names 
+*/	
+	rc = pci_hp_change_slot_info (buffer, info);
+	kfree (info);
+	return rc;
+}
+
+
+/******************************************************************************
+ * This function will return the pci_func, given bus and devfunc, or NULL.  It
+ * is called from visit routines
+ ******************************************************************************/
+
+static struct pci_func *ibm_slot_find (u8 busno, u8 device, u8 function)
+{
+	struct pci_func *func_cur;
+	struct slot *slot_cur;
+	struct list_head * tmp;
+	list_for_each (tmp, &ibmphp_slot_head) {
+		slot_cur = list_entry (tmp, struct slot, ibm_slot_list);
+		if (slot_cur->func) {
+			func_cur = slot_cur->func;
+			while (func_cur) {
+				if ((func_cur->busno == busno) && (func_cur->device == device) && (func_cur->function == function))
+					return func_cur;
+				func_cur = func_cur->next;
+			}
+		}
+	}
+	return NULL;
+}
+
+/* This routine is to find the pci_bus from kernel structures.
+ * Parameters: bus number
+ * Returns : pci_bus *  or NULL if not found
+ */
+static struct pci_bus *find_bus (u8 busno)
+{
+	const struct list_head *tmp;
+	struct pci_bus *bus;
+	debug ("inside find_bus, busno = %x \n", busno);
+
+	list_for_each (tmp, &pci_root_buses) {
+		bus = (struct pci_bus *) pci_bus_b (tmp);
+		if (bus)
+			if (bus->number == busno)
+				return bus;
+	}
+	return NULL;
+}
+
+/******************************************************************
+ * This function is here because we can no longer use pci_root_ops
+ ******************************************************************/
+static struct pci_ops *get_root_pci_ops (void)
+{
+	struct pci_bus * bus;
+
+	if ((bus = find_bus (0)))
+		return bus->ops;
+	return NULL;
+}
+
+/*************************************************************
+ * This routine frees up memory used by struct slot, including
+ * the pointers to pci_func, bus, hotplug_slot, controller,
+ * and deregistering from the hotplug core
+ *************************************************************/
+static void free_slots (void)
+{
+	struct slot *slot_cur;
+	struct list_head * tmp;
+	struct list_head * next;
+
+	list_for_each_safe (tmp, next, &ibmphp_slot_head) {
+
+		slot_cur = list_entry (tmp, struct slot, ibm_slot_list);
+
+		pci_hp_deregister (slot_cur->hotplug_slot);
+
+		if (slot_cur->hotplug_slot) {
+			kfree (slot_cur->hotplug_slot);
+			slot_cur->hotplug_slot = NULL;
+		}
+
+		if (slot_cur->ctrl) 
+			slot_cur->ctrl = NULL;
+		
+		if (slot_cur->bus_on) 
+			slot_cur->bus_on = NULL;
+
+		ibmphp_unconfigure_card (&slot_cur, -1);  /* we don't want to actually remove the resources, since free_resources will do just that */
+
+		kfree (slot_cur);
+	}
+}
+
+static int ibm_is_pci_dev_in_use (struct pci_dev *dev)
+{
+	int i = 0;
+	int inuse = 0;
+
+	if (dev->driver)
+		return 1;
+
+	for (i = 0; !dev->driver && !inuse && (i < 6); i++) {
+
+		if (!pci_resource_start (dev, i))
+			continue;
+
+		if (pci_resource_flags (dev, i) & IORESOURCE_IO)
+			inuse = check_region (pci_resource_start (dev, i), pci_resource_len (dev, i));
+
+		else if (pci_resource_flags (dev, i) & IORESOURCE_MEM)
+			inuse = check_mem_region (pci_resource_start (dev, i), pci_resource_len (dev, i));
+	}
+
+	return inuse;
+}
+
+static int ibm_pci_hp_remove_device (struct pci_dev *dev)
+{
+	if (ibm_is_pci_dev_in_use (dev)) {
+		err ("***Cannot safely power down device -- it appears to be in use***\n");
+		return -EBUSY;
+	}
+	pci_remove_device (dev);
+	return 0;
+}
+
+static int ibm_unconfigure_visit_pci_dev_phase2 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus)
+{
+	struct pci_dev *dev = wrapped_dev->dev;
+	struct pci_func *temp_func;
+	int i = 0;
+
+	do {
+		temp_func = ibm_slot_find (dev->bus->number, dev->devfn >> 3, i++);
+	} while (temp_func && (temp_func->function != (dev->devfn & 0x07)));
+
+	if (dev) {
+		if (ibm_pci_hp_remove_device (dev) == 0)
+			kfree (dev);    /* Now, remove */
+		else
+			return -1;
+	}
+
+	if (temp_func)
+		temp_func->dev = NULL;
+	else
+		err ("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn);
+
+	return 0;
+}
+
+static int ibm_unconfigure_visit_pci_bus_phase2 (struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_dev)
+{
+	struct pci_bus *bus = wrapped_bus->bus;
+
+	pci_proc_detach_bus (bus);
+	/* The cleanup code should live in the kernel... */
+	bus->self->subordinate = NULL;
+	/* unlink from parent bus */
+	list_del (&bus->node);
+
+	/* Now, remove */
+	if (bus)
+		kfree (bus);
+
+	return 0;
+}
+
+static int ibm_unconfigure_visit_pci_dev_phase1 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus)
+{
+	struct pci_dev *dev = wrapped_dev->dev;
+
+	debug ("attempting removal of driver for device (%x, %x, %x)\n", dev->bus->number, PCI_SLOT (dev->devfn), PCI_FUNC (dev->devfn));
+
+	/* Now, remove the Linux Driver Representation */
+	if (dev->driver) {
+		debug ("is there a driver?\n");
+		if (dev->driver->remove) {
+			dev->driver->remove (dev);
+			debug ("driver was properly removed\n");
+		}
+		dev->driver = NULL;
+	}
+
+	return ibm_is_pci_dev_in_use (dev);
+}
+
+static struct pci_visit ibm_unconfigure_functions_phase1 = {
+	post_visit_pci_dev:	ibm_unconfigure_visit_pci_dev_phase1,
+};
+
+static struct pci_visit ibm_unconfigure_functions_phase2 = {
+	post_visit_pci_bus:	ibm_unconfigure_visit_pci_bus_phase2,
+	post_visit_pci_dev:	ibm_unconfigure_visit_pci_dev_phase2,
+};
+
+static int ibm_unconfigure_device (struct pci_func *func)
+{
+	int rc = 0;
+	struct pci_dev_wrapped wrapped_dev;
+	struct pci_bus_wrapped wrapped_bus;
+	struct pci_dev *temp;
+	u8 j;
+
+	memset (&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
+	memset (&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
+
+	debug ("inside ibm_unconfigure_device\n");
+	debug ("func->device = %x, func->function = %x\n", func->device, func->function);
+	debug ("func->device << 3 | 0x0  = %x\n", func->device << 3 | 0x0);
+
+	for (j = 0; j < 0x08; j++) {
+		temp = pci_find_slot (func->busno, (func->device << 3) | j);
+		if (temp) {
+			wrapped_dev.dev = temp;
+			wrapped_bus.bus = temp->bus;
+			rc = pci_visit_dev (&ibm_unconfigure_functions_phase1, &wrapped_dev, &wrapped_bus);
+			if (rc)
+				break;
+
+			rc = pci_visit_dev (&ibm_unconfigure_functions_phase2, &wrapped_dev, &wrapped_bus);
+			if (rc)
+				break;
+		}
+	}
+	debug ("rc in ibm_unconfigure_device b4 returning is %d \n", rc);
+	return rc;
+}
+
+static int configure_visit_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus)
+{
+	//      struct pci_bus *bus = wrapped_bus->bus; /* We don't need this, since we don't create in the else statement */
+	struct pci_dev *dev = wrapped_dev->dev;
+	struct pci_func *temp_func;
+	int i = 0;
+
+	do {
+		temp_func = ibm_slot_find (dev->bus->number, dev->devfn >> 3, i++);
+	} while (temp_func && (temp_func->function != (dev->devfn & 0x07)));
+
+	if (temp_func)
+		temp_func->dev = dev;
+	else {
+		/* This should not really happen, since we create functions
+		   first and then call to configure */
+		debug (" We shouldn't come here \n");
+	}
+
+	if (temp_func->dev) {
+		pci_proc_attach_device (temp_func->dev);
+		pci_announce_device_to_drivers (temp_func->dev);
+	}
+
+	return 0;
+}
+
+static struct pci_visit configure_functions = {
+	visit_pci_dev:	configure_visit_pci_dev,
+};
+
+static int ibm_configure_device (struct pci_func *func)
+{
+	unsigned char bus;
+	struct pci_dev dev0;
+	struct pci_bus *child;
+	struct pci_dev *temp;
+	int rc = 0;
+
+	struct pci_dev_wrapped wrapped_dev;
+	struct pci_bus_wrapped wrapped_bus;
+
+	memset (&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
+	memset (&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
+	memset (&dev0, 0, sizeof (struct pci_dev));
+
+	if (func->dev == NULL)
+		func->dev = pci_find_slot (func->busno, (func->device << 3) | (func->function & 0x7));
+
+	if (func->dev == NULL) {
+		dev0.bus = find_bus (func->busno);
+		dev0.devfn = ((func->device << 3) + (func->function & 0x7));
+		dev0.sysdata = dev0.bus->sysdata;
+
+		func->dev = pci_scan_slot (&dev0);
+
+		if (func->dev == NULL) {
+			err ("ERROR... : pci_dev still NULL \n");
+			return 0;
+		}
+	}
+	if (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		pci_read_config_byte (func->dev, PCI_SECONDARY_BUS, &bus);
+		child = (struct pci_bus *) pci_add_new_bus (func->dev->bus, (func->dev), bus);
+		pci_do_scan_bus (child);
+	}
+
+	temp = func->dev;
+	if (temp) {
+		wrapped_dev.dev = temp;
+		wrapped_bus.bus = temp->bus;
+		rc = pci_visit_dev (&configure_functions, &wrapped_dev, &wrapped_bus);
+	}
+	return rc;
+}
+/*******************************************************
+ * Returns whether the bus is empty or not 
+ *******************************************************/
+static int is_bus_empty (struct slot * slot_cur)
+{
+	int rc;
+	struct slot * tmp_slot;
+	u8 i = slot_cur->bus_on->slot_min;
+
+	while (i <= slot_cur->bus_on->slot_max) {
+		if (i == slot_cur->number) {
+			i++;
+			continue;
+		}
+		tmp_slot = ibmphp_get_slot_from_physical_num (i);
+		rc = slot_update (&tmp_slot);
+		if (rc)
+			return 0;
+		if (SLOT_PRESENT (tmp_slot->status) && SLOT_POWER (tmp_slot->status))
+			return 0;
+		i++;
+	}
+	return 1;
+}
+
+/***********************************************************
+ * If the HPC permits and the bus currently empty, tries to set the 
+ * bus speed and mode at the maximum card capability
+ ***********************************************************/
+static int set_bus (struct slot * slot_cur)
+{
+	int rc;
+	u8 speed;
+	u8 cmd = 0x0;
+
+	debug ("%s - entry slot # %d \n", __FUNCTION__, slot_cur->number);
+	if (SET_BUS_STATUS (slot_cur->ctrl) && is_bus_empty (slot_cur)) {
+		rc = slot_update (&slot_cur);
+		if (rc)
+			return rc;
+		speed = SLOT_SPEED (slot_cur->ext_status);
+		debug ("ext_status = %x, speed = %x\n", slot_cur->ext_status, speed);
+		switch (speed) {
+		case HPC_SLOT_SPEED_33:
+			cmd = HPC_BUS_33CONVMODE;
+			break;
+		case HPC_SLOT_SPEED_66:
+			if (SLOT_PCIX (slot_cur->ext_status))
+				cmd = HPC_BUS_66PCIXMODE;
+			else
+				cmd = HPC_BUS_66CONVMODE;
+			break;
+		case HPC_SLOT_SPEED_133:
+			if (slot_cur->bus_on->slot_count > 1)
+				cmd = HPC_BUS_100PCIXMODE;
+			else
+				cmd = HPC_BUS_133PCIXMODE;
+			break;
+		default:
+			err ("wrong slot speed \n");
+			return -ENODEV;
+		}
+		debug ("setting bus speed for slot %d, cmd %x\n", slot_cur->number, cmd);
+		rc = ibmphp_hpc_writeslot (slot_cur, cmd);
+		if (rc)
+			return rc;
+	}
+	debug ("%s -Exit \n", __FUNCTION__);
+	return 0;
+}
+
+static inline void print_card_capability (struct slot *slot_cur)
+{
+	info ("capability of the card is ");
+	if ((slot_cur->ext_status & CARD_INFO) == PCIX133) 
+		info ("   133 MHz PCI-X \n");
+	else if ((slot_cur->ext_status & CARD_INFO) == PCIX66)
+		info ("    66 MHz PCI-X \n");
+	else if ((slot_cur->ext_status & CARD_INFO) == PCI66)
+		info ("    66 MHz PCI \n");
+	else
+		info ("    33 MHz PCI \n");
+
+}
+
+/* This routine will power on the slot, configure the device(s) and find the
+ * drivers for them.
+ * Parameters: hotplug_slot
+ * Returns: 0 or failure codes
+ */
+static int enable_slot (struct hotplug_slot *hs)
+{
+	int rc, i, rcpr;
+	struct slot *slot_cur;
+	u8 function;
+	u8 faulted = 0;
+	struct pci_func *tmp_func;
+
+	ibmphp_lock_operations ();
+
+	debug ("ENABLING SLOT........ \n");
+	slot_cur = (struct slot *) hs->private;
+
+	if ((rc = validate (slot_cur, ENABLE))) {
+		err ("validate function failed \n");
+		attn_off (slot_cur);	/* need to turn off if was blinking b4 */
+		attn_on (slot_cur);
+		rc = slot_update (&slot_cur);
+		if (rc) {
+			ibmphp_unlock_operations();
+			return rc;
+		}
+		ibmphp_update_slot_info (slot_cur);
+                ibmphp_unlock_operations ();
+		return rc;
+	}
+
+	attn_LED_blink (slot_cur);
+	
+	rc = set_bus (slot_cur);
+	if (rc) {
+		err ("was not able to set the bus \n");
+		attn_off (slot_cur);
+		attn_on (slot_cur);
+		ibmphp_unlock_operations ();
+		return -ENODEV;
+	}
+		
+	rc = power_on (slot_cur);
+
+	if (rc) {
+		err ("something wrong when powering up... please see below for details\n");
+		/* need to turn off before on, otherwise, blinking overwrites */
+		attn_off(slot_cur);
+		attn_on (slot_cur);
+		if (slot_update (&slot_cur)) {
+			attn_off (slot_cur);
+			attn_on (slot_cur);
+			ibmphp_unlock_operations ();
+			return -ENODEV;
+		}
+		/* Check to see the error of why it failed */
+		if (!(SLOT_PWRGD (slot_cur->status)))
+			err ("power fault occured trying to power up \n");
+		else if (SLOT_BUS_SPEED (slot_cur->status)) {
+			err ("bus speed mismatch occured.  please check current bus speed and card capability \n");
+			print_card_capability (slot_cur);
+		} else if (SLOT_BUS_MODE (slot_cur->ext_status)) 
+			err ("bus mode mismatch occured.  please check current bus mode and card capability \n");
+
+		ibmphp_update_slot_info (slot_cur);
+		ibmphp_unlock_operations (); 
+		return rc;
+	}
+	debug ("after power_on\n");
+
+	rc = slot_update (&slot_cur);
+	if (rc) {
+		attn_off (slot_cur);
+		attn_on (slot_cur);
+		rcpr = power_off (slot_cur);
+		if (rcpr) {
+			ibmphp_unlock_operations ();
+			return rcpr;
+		}
+		ibmphp_unlock_operations ();
+		return rc;
+	}
+	
+	if (SLOT_POWER (slot_cur->status) && !(SLOT_PWRGD (slot_cur->status))) {
+		faulted = 1;
+		err ("power fault occured trying to power up...\n");
+	} else if (SLOT_POWER (slot_cur->status) && (SLOT_BUS_SPEED (slot_cur->status))) {
+		faulted = 1;
+		err ("bus speed mismatch occured.  please check current bus speed and card capability \n");
+		print_card_capability (slot_cur);
+	} 
+	/* Don't think this case will happen after above checks... but just in case, for paranoia sake */
+	else if (!(SLOT_POWER (slot_cur->status))) {
+		err ("power on failed... \n");
+		faulted = 1;
+	}
+	if (faulted) {
+		attn_off (slot_cur);	/* need to turn off b4 on */
+		attn_on (slot_cur);
+		rcpr = power_off (slot_cur);
+		if (rcpr) {
+			ibmphp_unlock_operations ();
+			return rcpr;
+		}
+			
+		if (slot_update (&slot_cur)) {
+			ibmphp_unlock_operations ();
+			return -ENODEV;
+		}
+		ibmphp_update_slot_info (slot_cur);
+		ibmphp_unlock_operations ();
+		return -EINVAL;
+	}
+
+	slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL);
+	if (!slot_cur->func) { /* We cannot do update_slot_info here, since no memory for kmalloc n.e.ways, and update_slot_info allocates some */
+		err ("out of system memory \n");
+		attn_off (slot_cur);
+		attn_on (slot_cur);
+		rcpr = power_off (slot_cur);
+		if (rcpr) {
+			ibmphp_unlock_operations ();
+			return rcpr;
+		}
+		ibmphp_unlock_operations ();
+		return -ENOMEM;
+	}
+	memset (slot_cur->func, 0, sizeof (struct pci_func));
+	slot_cur->func->busno = slot_cur->bus;
+	slot_cur->func->device = slot_cur->device;
+	for (i = 0; i < 4; i++)
+		slot_cur->func->irq[i] = slot_cur->irq[i];
+
+	debug ("b4 configure_card, slot_cur->bus = %x, slot_cur->device = %x\n", slot_cur->bus, slot_cur->device);
+
+	if (ibmphp_configure_card (slot_cur->func, slot_cur->number)) {
+		err ("configure_card was unsuccessful... \n");
+		ibmphp_unconfigure_card (&slot_cur, 1); /* true because don't need to actually deallocate resources, just remove references */
+		debug ("after unconfigure_card\n");
+		slot_cur->func = NULL;
+		attn_off (slot_cur);	/* need to turn off in case was blinking */
+		attn_on (slot_cur);
+		rcpr = power_off (slot_cur);
+		if (rcpr) {
+			ibmphp_unlock_operations ();
+			return rcpr;
+		}
+		if (slot_update (&slot_cur)) {
+			ibmphp_unlock_operations();
+			return -ENODEV;
+		}
+		ibmphp_update_slot_info (slot_cur);
+		ibmphp_unlock_operations ();
+		return -ENOMEM;
+	}
+	function = 0x00;
+	do {
+		tmp_func = ibm_slot_find (slot_cur->bus, slot_cur->func->device, function++);
+		if (tmp_func && !(tmp_func->dev))
+			ibm_configure_device (tmp_func);
+	} while (tmp_func);
+
+	attn_off (slot_cur);
+	if (slot_update (&slot_cur)) {
+		ibmphp_unlock_operations ();
+		return -EFAULT;
+	}
+	ibmphp_print_test ();
+	rc = ibmphp_update_slot_info (slot_cur);
+	ibmphp_unlock_operations(); 
+	return rc;
+}
+
+/**************************************************************
+* HOT REMOVING ADAPTER CARD                                   *
+* INPUT: POINTER TO THE HOTPLUG SLOT STRUCTURE                *
+* OUTPUT: SUCCESS 0 ; FAILURE: UNCONFIGURE , VALIDATE         *
+          DISABLE POWER ,                                    *
+**************************************************************/
+int ibmphp_disable_slot (struct hotplug_slot *hotplug_slot)
+{
+	int rc;
+	struct slot *slot_cur = (struct slot *) hotplug_slot->private;
+	u8 flag = slot_cur->flag;
+
+	slot_cur->flag = TRUE;
+	debug ("DISABLING SLOT... \n"); 
+		
+	ibmphp_lock_operations (); 
+	if (slot_cur == NULL) {
+		ibmphp_unlock_operations ();
+		return -ENODEV;
+	}
+	if (slot_cur->ctrl == NULL) {
+		ibmphp_unlock_operations ();
+		return -ENODEV;
+	}
+	if (flag == TRUE) {
+		rc = validate (slot_cur, DISABLE);	/* checking if powered off already & valid slot # */
+		if (rc) {
+			/*  Need to turn off if was blinking b4 */
+			attn_off (slot_cur);
+			attn_on (slot_cur);
+			if (slot_update (&slot_cur)) {
+				ibmphp_unlock_operations ();
+				return -EFAULT;
+			}
+		
+			ibmphp_update_slot_info (slot_cur);
+			ibmphp_unlock_operations ();
+			return rc;
+		}
+	}
+	attn_LED_blink (slot_cur);
+
+	if (slot_cur->func == NULL) {
+		/* We need this for fncs's that were there on bootup */
+		slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL);
+		if (!slot_cur->func) {
+			err ("out of system memory \n");
+			attn_off (slot_cur);
+			attn_on (slot_cur);
+			ibmphp_unlock_operations ();
+			return -ENOMEM;
+		}
+		memset (slot_cur->func, 0, sizeof (struct pci_func));
+		slot_cur->func->busno = slot_cur->bus;
+		slot_cur->func->device = slot_cur->device;
+	}
+
+	if ((rc = ibm_unconfigure_device (slot_cur->func))) {
+		err ("removing from kernel failed... \n");
+		err ("Please check to see if it was statically linked or is in use otherwise. (perhaps the driver is not 'hot-removable')\n");
+		attn_off (slot_cur);
+		attn_on (slot_cur);
+		ibmphp_unlock_operations ();
+		return rc;
+	}
+
+	rc = ibmphp_unconfigure_card (&slot_cur, 0);
+	slot_cur->func = NULL;
+	debug ("in disable_slot. after unconfigure_card \n");
+	if (rc) {
+		err ("could not unconfigure card.\n");
+		attn_off (slot_cur);	/* need to turn off if was blinking b4 */
+		attn_on (slot_cur);
+
+		if (slot_update (&slot_cur)) {
+			ibmphp_unlock_operations ();
+			return -EFAULT;
+		}
+
+		if (flag) 
+			ibmphp_update_slot_info (slot_cur);
+
+		ibmphp_unlock_operations ();
+		return -EFAULT;
+	}
+
+	rc = ibmphp_hpc_writeslot (hotplug_slot->private, HPC_SLOT_OFF);
+	if (rc) {
+		attn_off (slot_cur);
+		attn_on (slot_cur);
+		if (slot_update (&slot_cur)) {
+			ibmphp_unlock_operations ();
+			return -EFAULT;
+		}
+
+		if (flag)
+			ibmphp_update_slot_info (slot_cur);
+
+		ibmphp_unlock_operations ();
+		return rc;
+	}
+
+	attn_off (slot_cur);
+	if (slot_update (&slot_cur)) {
+		ibmphp_unlock_operations ();
+		return -EFAULT;
+	}
+	if (flag) 
+		rc = ibmphp_update_slot_info (slot_cur);
+	else
+		rc = 0;
+
+	ibmphp_print_test ();
+	ibmphp_unlock_operations();
+	return rc;
+}
+
+struct hotplug_slot_ops ibmphp_hotplug_slot_ops = {
+	owner:				THIS_MODULE,
+	set_attention_status:		set_attention_status,
+	enable_slot:			enable_slot,
+	disable_slot:			ibmphp_disable_slot,
+	hardware_test:			NULL,
+	get_power_status:		get_power_status,
+	get_attention_status:		get_attention_status,
+	get_latch_status:		get_latch_status,
+	get_adapter_status:		get_adapter_present,
+/*	get_max_bus_speed_status:	get_max_bus_speed,
+	get_max_adapter_speed_status:	get_max_adapter_speed,
+	get_cur_bus_speed_status:	get_cur_bus_speed,
+	get_card_bus_names_status:	get_card_bus_names,
+*/
+};
+
+static void ibmphp_unload (void)
+{
+	free_slots ();
+	debug ("after slots \n");
+	ibmphp_free_resources ();
+	debug ("after resources \n");
+	ibmphp_free_bus_info_queue ();
+	debug ("after bus info \n");
+	ibmphp_free_ebda_hpc_queue ();
+	debug ("after ebda hpc \n");
+	ibmphp_free_ebda_pci_rsrc_queue ();
+	debug ("after ebda pci rsrc \n");
+}
+
+static int __init ibmphp_init (void)
+{
+	int i = 0;
+	int rc = 0;
+
+	init_flag = 1;
+	ibmphp_pci_root_ops = get_root_pci_ops ();
+	if (ibmphp_pci_root_ops == NULL) {
+		err ("cannot read bus operations... will not be able to read the cards.  Please check your system \n");
+		return -ENODEV;	
+	}
+
+	ibmphp_debug = debug;
+
+	ibmphp_hpc_initvars ();
+
+	for (i = 0; i < 16; i++)
+		irqs[i] = 0;
+
+	if ((rc = ibmphp_access_ebda ())) {
+		ibmphp_unload ();
+		return rc;
+	}
+	debug ("after ibmphp_access_ebda () \n");
+
+	if ((rc = ibmphp_rsrc_init ())) {
+		ibmphp_unload ();
+		return rc;
+	}
+	debug ("AFTER Resource & EBDA INITIALIZATIONS \n");
+
+	max_slots = get_max_slots ();
+
+	if (init_ops ()) {
+		ibmphp_unload ();
+		return -ENODEV;
+	}
+	ibmphp_print_test ();
+	if ((rc = ibmphp_hpc_start_poll_thread ())) {
+		ibmphp_unload ();
+		return -ENODEV;
+	}
+
+	/* lock ourselves into memory with a module count of -1 
+	 * so that no one can unload us. */
+	MOD_DEC_USE_COUNT;
+
+	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+	return 0;
+}
+
+static void __exit ibmphp_exit (void)
+{
+	ibmphp_hpc_stop_poll_thread ();
+	debug ("after polling \n");
+	ibmphp_unload ();
+	debug ("done \n");
+}
+
+module_init (ibmphp_init);
+module_exit (ibmphp_exit);
diff -urN linux-2.5.6-pre1/drivers/hotplug/ibmphp_ebda.c linux-2.5.6-pre2/drivers/hotplug/ibmphp_ebda.c
--- linux-2.5.6-pre1/drivers/hotplug/ibmphp_ebda.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/drivers/hotplug/ibmphp_ebda.c	Thu Feb 28 13:34:21 2002
@@ -0,0 +1,851 @@
+/*
+ * IBM Hot Plug Controller Driver
+ *
+ * Written By: Tong Yu, IBM Corporation
+ *
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001,2002 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include "ibmphp.h"
+
+/*
+ * POST builds data blocks(in this data block definition, a char-1
+ * byte, short(or word)-2 byte, long(dword)-4 byte) in the Extended
+ * BIOS Data Area which describe the configuration of the hot-plug
+ * controllers and resources used by the PCI Hot-Plug devices.
+ *
+ * This file walks EBDA, maps data block from physical addr,
+ * reconstruct linked lists about all system resource(MEM, PFM, IO)
+ * already assigned by POST, as well as linked lists about hot plug
+ * controllers (ctlr#, slot#, bus&slot features...)
+ */
+
+/* Global lists */
+LIST_HEAD (ibmphp_ebda_pci_rsrc_head);
+LIST_HEAD (ibmphp_slot_head);
+
+/* Local variables */
+static struct ebda_hpc_list *hpc_list_ptr;
+static struct ebda_rsrc_list *rsrc_list_ptr;
+static struct rio_table_hdr *rio_table_ptr;
+static LIST_HEAD (ebda_hpc_head);
+static LIST_HEAD (bus_info_head);
+static void *io_mem;
+
+/* Local functions */
+static int ebda_rsrc_controller (void);
+static int ebda_rsrc_rsrc (void);
+static int ebda_rio_table (void);
+
+static struct slot *alloc_ibm_slot (void)
+{
+	struct slot *slot;
+
+	slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
+	if (!slot)
+		return NULL;
+	memset (slot, 0, sizeof (*slot));
+	return slot;
+}
+
+static struct ebda_hpc_list *alloc_ebda_hpc_list (void)
+{
+	struct ebda_hpc_list *list;
+
+	list = kmalloc (sizeof (struct ebda_hpc_list), GFP_KERNEL);
+	if (!list)
+		return NULL;
+	memset (list, 0, sizeof (*list));
+	return list;
+}
+
+static struct controller *alloc_ebda_hpc (u32 slot_count, u32 bus_count)
+{
+	struct controller *controller;
+	struct ebda_hpc_slot *slots;
+	struct ebda_hpc_bus *buses;
+
+	controller = kmalloc (sizeof (struct controller), GFP_KERNEL);
+	if (!controller)
+		return NULL;
+	memset (controller, 0, sizeof (*controller));
+
+	slots = kmalloc (sizeof (struct ebda_hpc_slot) * slot_count, GFP_KERNEL);
+	if (!slots) {
+		kfree (controller);
+		return NULL;
+	}
+	memset (slots, 0, sizeof (*slots) * slot_count);
+	controller->slots = slots;
+
+	buses = kmalloc (sizeof (struct ebda_hpc_bus) * bus_count, GFP_KERNEL);
+	if (!buses) {
+		kfree (controller->slots);
+		kfree (controller);
+		return NULL;
+	}
+	memset (buses, 0, sizeof (*buses) * bus_count);
+	controller->buses = buses;
+
+	return controller;
+}
+
+static void free_ebda_hpc (struct controller *controller)
+{
+	kfree (controller->slots);
+	controller->slots = NULL;
+	kfree (controller->buses);
+	controller->buses = NULL;
+	kfree (controller);
+}
+
+static struct ebda_rsrc_list *alloc_ebda_rsrc_list (void)
+{
+	struct ebda_rsrc_list *list;
+
+	list = kmalloc (sizeof (struct ebda_rsrc_list), GFP_KERNEL);
+	if (!list)
+		return NULL;
+	memset (list, 0, sizeof (*list));
+	return list;
+}
+
+static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc (void)
+{
+	struct ebda_pci_rsrc *resource;
+
+	resource = kmalloc (sizeof (struct ebda_pci_rsrc), GFP_KERNEL);
+	if (!resource)
+		return NULL;
+	memset (resource, 0, sizeof (*resource));
+	return resource;
+}
+
+static void print_bus_info (void)
+{
+	struct bus_info *ptr;
+	struct list_head *ptr1;
+	
+	list_for_each (ptr1, &bus_info_head) {
+		ptr = list_entry (ptr1, struct bus_info, bus_info_list);
+		debug ("%s - slot_min = %x\n", __FUNCTION__, ptr->slot_min);
+		debug ("%s - slot_max = %x\n", __FUNCTION__, ptr->slot_max);
+		debug ("%s - slot_count = %x\n", __FUNCTION__, ptr->slot_count);
+		debug ("%s - bus# = %x\n", __FUNCTION__, ptr->busno);
+		debug ("%s - current_speed = %x\n", __FUNCTION__, ptr->current_speed);
+		debug ("%s - supported_speed = %x\n", __FUNCTION__, ptr->supported_speed);
+		debug ("%s - controller_id = %x\n", __FUNCTION__, ptr->controller_id);
+		debug ("%s - bus_mode = %x\n", __FUNCTION__, ptr->supported_bus_mode);
+	}
+}
+
+static void print_ebda_pci_rsrc (void)
+{
+	struct ebda_pci_rsrc *ptr;
+	struct list_head *ptr1;
+
+	list_for_each (ptr1, &ibmphp_ebda_pci_rsrc_head) {
+		ptr = list_entry (ptr1, struct ebda_pci_rsrc, ebda_pci_rsrc_list);
+		debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %lx end addr: %lx\n", 
+			__FUNCTION__, ptr->rsrc_type ,ptr->bus_num, ptr->dev_fun,ptr->start_addr, ptr->end_addr);
+	}
+}
+
+static void print_ebda_hpc (void)
+{
+	struct controller *hpc_ptr;
+	struct list_head *ptr1;
+	u16 index;
+
+	list_for_each (ptr1, &ebda_hpc_head) {
+
+		hpc_ptr = list_entry (ptr1, struct controller, ebda_hpc_list); 
+
+		for (index = 0; index < hpc_ptr->slot_count; index++) {
+			debug ("%s - physical slot#: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_num);
+			debug ("%s - pci bus# of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_bus_num);
+			debug ("%s - index into ctlr addr: %x\n", __FUNCTION__, hpc_ptr->slots[index].ctl_index);
+			debug ("%s - cap of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_cap);
+		}
+
+		for (index = 0; index < hpc_ptr->bus_count; index++) {
+			debug ("%s - bus# of each bus controlled by this ctlr: %x\n", __FUNCTION__, hpc_ptr->buses[index].bus_num);
+		}
+
+		debug ("%s - type of hpc: %x\n", __FUNCTION__, hpc_ptr->ctlr_type);
+		switch (hpc_ptr->ctlr_type) {
+		case 1:
+			debug ("%s - bus: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.bus);
+			debug ("%s - dev_fun: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.dev_fun);
+			debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq);
+			break;
+
+		case 0:
+			debug ("%s - io_start: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_start);
+			debug ("%s - io_end: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_end);
+			debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq);
+			break;
+
+		case 2:
+			debug ("%s - wpegbbar: %lx\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.wpegbbar);
+			debug ("%s - i2c_addr: %x\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.i2c_addr);
+			debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq);
+			break;
+		}
+	}
+}
+
+int ibmphp_access_ebda (void)
+{
+	u8 format, num_ctlrs, rio_complete, hs_complete;
+	u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, rc, re, rc_id, re_id, base;
+
+
+	rio_complete = 0;
+	hs_complete = 0;
+
+	io_mem = ioremap ((0x40 << 4) + 0x0e, 2);
+	if (!io_mem )
+		return -ENOMEM;
+	ebda_seg = readw (io_mem);
+	iounmap (io_mem);
+	debug ("returned ebda segment: %x\n", ebda_seg);
+	
+	io_mem = ioremap (ebda_seg<<4, 65000);
+	if (!io_mem )
+		return -ENOMEM;
+	next_offset = 0x180;
+
+	for (;;) {
+		offset = next_offset;
+		next_offset = readw (io_mem + offset);	/* offset of next blk */
+
+		offset += 2;
+		if (next_offset == 0)	/* 0 indicate it's last blk */
+			break;
+		blk_id = readw (io_mem + offset);	/* this blk id */
+
+		offset += 2;
+		/* check if it is hot swap block or rio block */
+		if (blk_id != 0x4853 && blk_id != 0x4752)
+			continue;
+		/* found hs table */
+		if (blk_id == 0x4853) {
+			debug ("now enter hot swap block---\n");
+			debug ("hot blk id: %x\n", blk_id);
+			format = readb (io_mem + offset);
+
+			offset += 1;
+			if (format != 4) {
+				iounmap (io_mem);
+				return -ENODEV;
+			}
+			debug ("hot blk format: %x\n", format);
+			/* hot swap sub blk */
+			base = offset;
+
+			sub_addr = base;
+			re = readw (io_mem + sub_addr);	/* next sub blk */
+
+			sub_addr += 2;
+			rc_id = readw (io_mem + sub_addr); 	/* sub blk id */
+
+			sub_addr += 2;
+			if (rc_id != 0x5243) {
+				iounmap (io_mem);
+				return -ENODEV;
+			}
+			/* rc sub blk signature  */
+			num_ctlrs = readb (io_mem + sub_addr);
+
+			sub_addr += 1;
+			hpc_list_ptr = alloc_ebda_hpc_list ();
+			if (!hpc_list_ptr) {
+				iounmap (io_mem);
+				return -ENOMEM;
+			}
+			hpc_list_ptr->format = format;
+			hpc_list_ptr->num_ctlrs = num_ctlrs;
+			hpc_list_ptr->phys_addr = sub_addr;	/*  offset of RSRC_CONTROLLER blk */
+			debug ("info about hpc descriptor---\n");
+			debug ("hot blk format: %x\n", format);
+			debug ("num of controller: %x\n", num_ctlrs);
+			debug ("offset of hpc data structure enteries: %x\n ", sub_addr);
+
+			sub_addr = base + re;	/* re sub blk */
+			rc = readw (io_mem + sub_addr);	/* next sub blk */
+
+			sub_addr += 2;
+			re_id = readw (io_mem + sub_addr);	/* sub blk id */
+
+			sub_addr += 2;
+			if (re_id != 0x5245) {
+				iounmap (io_mem);
+				return -ENODEV;
+			}
+
+			/* signature of re */
+			num_entries = readw (io_mem + sub_addr);
+
+			sub_addr += 2;	/* offset of RSRC_ENTRIES blk */
+			rsrc_list_ptr = alloc_ebda_rsrc_list ();
+			if (!rsrc_list_ptr ) {
+				iounmap (io_mem);
+				return -ENOMEM;
+			}
+			rsrc_list_ptr->format = format;
+			rsrc_list_ptr->num_entries = num_entries;
+			rsrc_list_ptr->phys_addr = sub_addr;
+
+			debug ("info about rsrc descriptor---\n");
+			debug ("format: %x\n", format);
+			debug ("num of rsrc: %x\n", num_entries);
+			debug ("offset of rsrc data structure enteries: %x\n ", sub_addr);
+
+			hs_complete = 1;
+		}
+		/* found rio table */
+		else if (blk_id == 0x4752) {
+			debug ("now enter io table ---\n");
+			debug ("rio blk id: %x\n", blk_id);
+
+			rio_table_ptr = kmalloc (sizeof (struct rio_table_hdr), GFP_KERNEL);
+			if (!rio_table_ptr)
+				return -ENOMEM; 
+			memset (rio_table_ptr, 0, sizeof (struct rio_table_hdr) );
+			rio_table_ptr->ver_num = readb (io_mem + offset);
+			rio_table_ptr->scal_count = readb (io_mem + offset + 1);
+			rio_table_ptr->riodev_count = readb (io_mem + offset + 2);
+			rio_table_ptr->offset = offset +3 ;
+			
+			debug ("info about rio table hdr ---\n");
+			debug ("ver_num: %x\nscal_count: %x\nriodev_count: %x\noffset of rio table: %x\n ", rio_table_ptr->ver_num, rio_table_ptr->scal_count, rio_table_ptr->riodev_count, rio_table_ptr->offset);
+
+			rio_complete = 1;
+		}
+
+		if (hs_complete && rio_complete) {
+			rc = ebda_rsrc_controller ();
+			if (rc) {
+				iounmap(io_mem);
+				return rc;
+			}
+			rc = ebda_rsrc_rsrc ();
+			if (rc) {
+				iounmap(io_mem);
+				return rc;
+			}
+			rc = ebda_rio_table ();
+			if (rc) {
+				iounmap(io_mem);
+				return rc;
+			}	
+			iounmap (io_mem);
+			return 0;
+		}
+	}
+	iounmap (io_mem);
+	return -ENODEV;
+}
+
+
+/*
+ * map info (ctlr-id, slot count, slot#.. bus count, bus#, ctlr type...) of
+ * each hpc from physical address to a list of hot plug controllers based on
+ * hpc descriptors.
+ */
+static int ebda_rsrc_controller (void)
+{
+	u16 addr, addr_slot, addr_bus;
+	u8 ctlr_id, temp, bus_index;
+	u16 ctlr, slot, bus;
+	u16 slot_num, bus_num, index;
+	struct hotplug_slot *hp_slot_ptr;
+	struct controller *hpc_ptr;
+	struct ebda_hpc_bus *bus_ptr;
+	struct ebda_hpc_slot *slot_ptr;
+	struct bus_info *bus_info_ptr1, *bus_info_ptr2;
+	int rc;
+
+	addr = hpc_list_ptr->phys_addr;
+	for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) {
+		bus_index = 1;
+		ctlr_id = readb (io_mem + addr);
+		addr += 1;
+		slot_num = readb (io_mem + addr);
+
+		addr += 1;
+		addr_slot = addr;	/* offset of slot structure */
+		addr += (slot_num * 4);
+
+		bus_num = readb (io_mem + addr);
+
+		addr += 1;
+		addr_bus = addr;	/* offset of bus */
+		addr += (bus_num * 9);	/* offset of ctlr_type */
+		temp = readb (io_mem + addr);
+
+		addr += 1;
+		/* init hpc structure */
+		hpc_ptr = alloc_ebda_hpc (slot_num, bus_num);
+		if (!hpc_ptr ) {
+			iounmap (io_mem);
+			return -ENOMEM;
+		}
+		hpc_ptr->ctlr_id = ctlr_id;
+		hpc_ptr->ctlr_relative_id = ctlr;
+		hpc_ptr->slot_count = slot_num;
+		hpc_ptr->bus_count = bus_num;
+		debug ("now enter ctlr data struture ---\n");
+		debug ("ctlr id: %x\n", ctlr_id);
+		debug ("ctlr_relative_id: %x\n", hpc_ptr->ctlr_relative_id);
+		debug ("count of slots controlled by this ctlr: %x\n", slot_num);
+		debug ("count of buses controlled by this ctlr: %x\n", bus_num);
+
+		/* init slot structure, fetch slot, bus, cap... */
+		slot_ptr = hpc_ptr->slots;
+		for (slot = 0; slot < slot_num; slot++) {
+			slot_ptr->slot_num = readb (io_mem + addr_slot);
+			slot_ptr->slot_bus_num = readb (io_mem + addr_slot + slot_num);
+			slot_ptr->ctl_index = readb (io_mem + addr_slot + 2*slot_num);
+			slot_ptr->slot_cap = readb (io_mem + addr_slot + 3*slot_num);
+
+			// create bus_info lined list --- if only one slot per bus: slot_min = slot_max 
+
+			bus_info_ptr2 = ibmphp_find_same_bus_num (slot_ptr->slot_bus_num);
+			if (!bus_info_ptr2) {
+				bus_info_ptr1 = (struct bus_info *) kmalloc (sizeof (struct bus_info), GFP_KERNEL);
+				if (!bus_info_ptr1) {
+					iounmap (io_mem);
+					return -ENOMEM;
+				}
+				memset (bus_info_ptr1, 0, sizeof (struct bus_info));
+				bus_info_ptr1->slot_min = slot_ptr->slot_num;
+				bus_info_ptr1->slot_max = slot_ptr->slot_num;
+				bus_info_ptr1->slot_count += 1;
+				bus_info_ptr1->busno = slot_ptr->slot_bus_num;
+				bus_info_ptr1->index = bus_index++;
+				bus_info_ptr1->current_speed = 0xff;
+				bus_info_ptr1->current_bus_mode = 0xff;
+				if ( ((slot_ptr->slot_cap) & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX )
+					bus_info_ptr1->supported_speed =  3;
+				else if ( ((slot_ptr->slot_cap) & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX )
+					bus_info_ptr1->supported_speed =  2;
+				else if ( ((slot_ptr->slot_cap) & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX )
+					bus_info_ptr1->supported_speed =  1;
+				bus_info_ptr1->controller_id = hpc_ptr->ctlr_id;
+				if ( ((slot_ptr->slot_cap) & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP )
+					bus_info_ptr1->supported_bus_mode = 1;
+				else
+					bus_info_ptr1->supported_bus_mode =0;
+
+
+				list_add_tail (&bus_info_ptr1->bus_info_list, &bus_info_head);
+
+			} else {
+				bus_info_ptr2->slot_min = min (bus_info_ptr2->slot_min, slot_ptr->slot_num);
+				bus_info_ptr2->slot_max = max (bus_info_ptr2->slot_max, slot_ptr->slot_num);
+				bus_info_ptr2->slot_count += 1;
+
+			}
+
+			// end of creating the bus_info linked list
+
+			slot_ptr++;
+			addr_slot += 1;
+		}
+
+		/* init bus structure */
+		bus_ptr = hpc_ptr->buses;
+		for (bus = 0; bus < bus_num; bus++) {
+			bus_ptr->bus_num = readb (io_mem + addr_bus);
+			bus_ptr++;
+			addr_bus += 1;
+		}
+
+		hpc_ptr->ctlr_type = temp;
+
+		switch (hpc_ptr->ctlr_type) {
+			case 1:
+				hpc_ptr->u.pci_ctlr.bus = readb (io_mem + addr);
+				hpc_ptr->u.pci_ctlr.dev_fun = readb (io_mem + addr + 1);
+				hpc_ptr->irq = readb (io_mem + addr + 2);
+				addr += 3; 
+				break;
+
+			case 0:
+				hpc_ptr->u.isa_ctlr.io_start = readw (io_mem + addr);
+				hpc_ptr->u.isa_ctlr.io_end = readw (io_mem + addr + 2);
+				hpc_ptr->irq = readb (io_mem + addr + 4);
+				addr += 5;
+				break;
+
+			case 2:
+				hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr);
+				hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4);
+				/* following 2 lines for testing purpose */
+				if (hpc_ptr->u.wpeg_ctlr.i2c_addr == 0) 
+					hpc_ptr->ctlr_type = 4;	
+				
+
+				hpc_ptr->irq = readb (io_mem + addr + 5);
+				addr += 6;
+				break;
+			case 4:
+				hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr);
+				hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4);
+				hpc_ptr->irq = readb (io_mem + addr + 5);
+				addr += 6;
+				break;
+			default:
+				iounmap (io_mem);
+				return -ENODEV;
+		}
+		/* following 3 line: Now our driver only supports I2c ctlrType */
+		if ((hpc_ptr->ctlr_type != 2) && (hpc_ptr->ctlr_type != 4)) {
+			err ("Please run this driver on ibm xseries440\n ");
+			return -ENODEV;
+		}
+
+		hpc_ptr->revision = 0xff;
+		hpc_ptr->options = 0xff;
+
+		// register slots with hpc core as well as create linked list of ibm slot
+		for (index = 0; index < hpc_ptr->slot_count; index++) {
+
+			hp_slot_ptr = (struct hotplug_slot *) kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
+			if (!hp_slot_ptr) {
+				iounmap (io_mem);
+				return -ENOMEM;
+			}
+			memset (hp_slot_ptr, 0, sizeof (struct hotplug_slot));
+
+			hp_slot_ptr->info = (struct hotplug_slot_info *) kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+			if (!hp_slot_ptr->info) {
+				iounmap (io_mem);
+				kfree (hp_slot_ptr);
+				return -ENOMEM;
+			}
+			memset (hp_slot_ptr->info, 0, sizeof (struct hotplug_slot_info));
+
+			hp_slot_ptr->name = (char *) kmalloc (10, GFP_KERNEL);
+			if (!hp_slot_ptr->name) {
+				iounmap (io_mem);
+				kfree (hp_slot_ptr->info);
+				kfree (hp_slot_ptr);
+				return -ENOMEM;
+			}
+
+			hp_slot_ptr->private = alloc_ibm_slot ();
+			if (!hp_slot_ptr->private) {
+				iounmap (io_mem);
+				kfree (hp_slot_ptr->name);
+				kfree (hp_slot_ptr->info);
+				kfree (hp_slot_ptr);
+				return -ENOMEM;
+			}
+
+			((struct slot *)hp_slot_ptr->private)->flag = TRUE;
+			snprintf (hp_slot_ptr->name, 10, "%d", hpc_ptr->slots[index].slot_num);
+
+			((struct slot *) hp_slot_ptr->private)->capabilities = hpc_ptr->slots[index].slot_cap;
+			((struct slot *) hp_slot_ptr->private)->bus = hpc_ptr->slots[index].slot_bus_num;
+
+			bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num);
+			if (!bus_info_ptr1) {
+				iounmap (io_mem);
+				return -ENODEV;
+			}
+			((struct slot *) hp_slot_ptr->private)->bus_on = bus_info_ptr1;
+			bus_info_ptr1 = NULL;
+			((struct slot *) hp_slot_ptr->private)->ctrl = hpc_ptr;
+
+
+			((struct slot *) hp_slot_ptr->private)->ctlr_index = hpc_ptr->slots[index].ctl_index;
+			((struct slot *) hp_slot_ptr->private)->number = hpc_ptr->slots[index].slot_num;
+
+			((struct slot *) hp_slot_ptr->private)->hotplug_slot = hp_slot_ptr;
+
+			rc = ibmphp_hpc_fillhpslotinfo (hp_slot_ptr);
+			if (rc) {
+				iounmap (io_mem);
+				return rc;
+			}
+
+			rc = ibmphp_init_devno ((struct slot **) &hp_slot_ptr->private);
+			if (rc) {
+				iounmap (io_mem);
+				return rc;
+			}
+			hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops;
+
+			pci_hp_register (hp_slot_ptr);
+
+			// end of registering ibm slot with hotplug core
+
+			list_add (& ((struct slot *)(hp_slot_ptr->private))->ibm_slot_list, &ibmphp_slot_head);
+		}
+
+		print_bus_info ();
+		list_add (&hpc_ptr->ebda_hpc_list, &ebda_hpc_head );
+
+	}			/* each hpc  */
+	print_ebda_hpc ();
+	return 0;
+}
+
+/* 
+ * map info (bus, devfun, start addr, end addr..) of i/o, memory,
+ * pfm from the physical addr to a list of resource.
+ */
+static int ebda_rsrc_rsrc (void)
+{
+	u16 addr;
+	short rsrc;
+	u8 type, rsrc_type;
+	struct ebda_pci_rsrc *rsrc_ptr;
+
+	addr = rsrc_list_ptr->phys_addr;
+	debug ("now entering rsrc land\n");
+	debug ("offset of rsrc: %x\n", rsrc_list_ptr->phys_addr);
+
+	for (rsrc = 0; rsrc < rsrc_list_ptr->num_entries; rsrc++) {
+		type = readb (io_mem + addr);
+
+		addr += 1;
+		rsrc_type = type & EBDA_RSRC_TYPE_MASK;
+
+		if (rsrc_type == EBDA_IO_RSRC_TYPE) {
+			rsrc_ptr = alloc_ebda_pci_rsrc ();
+			if (!rsrc_ptr) {
+				iounmap (io_mem);
+				return -ENOMEM;
+			}
+			rsrc_ptr->rsrc_type = type;
+
+			rsrc_ptr->bus_num = readb (io_mem + addr);
+			rsrc_ptr->dev_fun = readb (io_mem + addr + 1);
+			rsrc_ptr->start_addr = readw (io_mem + addr + 2);
+			rsrc_ptr->end_addr = readw (io_mem + addr + 4);
+			addr += 6;
+
+			debug ("rsrc from io type ----\n");
+			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %lx end addr: %lx\n",
+				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
+
+			list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
+		}
+
+		if (rsrc_type == EBDA_MEM_RSRC_TYPE || rsrc_type == EBDA_PFM_RSRC_TYPE) {
+			rsrc_ptr = alloc_ebda_pci_rsrc ();
+			if (!rsrc_ptr ) {
+				iounmap (io_mem);
+				return -ENOMEM;
+			}
+			rsrc_ptr->rsrc_type = type;
+
+			rsrc_ptr->bus_num = readb (io_mem + addr);
+			rsrc_ptr->dev_fun = readb (io_mem + addr + 1);
+			rsrc_ptr->start_addr = readl (io_mem + addr + 2);
+			rsrc_ptr->end_addr = readl (io_mem + addr + 6);
+			addr += 10;
+
+			debug ("rsrc from mem or pfm ---\n");
+			debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %lx end addr: %lx\n", 
+				rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr);
+
+			list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head);
+		}
+	}
+	kfree (rsrc_list_ptr);
+	rsrc_list_ptr = NULL;
+	print_ebda_pci_rsrc ();
+	return 0;
+}
+
+/*
+ * map info of scalability details and rio details from physical address
+ */
+static int ebda_rio_table(void)
+{
+	u16 offset;
+	u8 i;
+	struct scal_detail *scal_detail_ptr;
+	struct rio_detail *rio_detail_ptr;
+
+	offset = rio_table_ptr->offset;
+	for (i = 0; i < rio_table_ptr->scal_count; i++) {
+		
+		scal_detail_ptr = kmalloc (sizeof (struct scal_detail), GFP_KERNEL );
+		if (!scal_detail_ptr )
+			return -ENOMEM;
+		memset (scal_detail_ptr, 0, sizeof (struct scal_detail) );
+		scal_detail_ptr->node_id = readb (io_mem + offset);
+		scal_detail_ptr->cbar = readl (io_mem+ offset + 1);
+		scal_detail_ptr->port0_node_connect = readb (io_mem + 5);
+		scal_detail_ptr->port0_port_connect = readb (io_mem + 6);
+		scal_detail_ptr->port1_node_connect = readb (io_mem + 7);
+		scal_detail_ptr->port1_port_connect = readb (io_mem + 8);
+		scal_detail_ptr->port2_node_connect = readb (io_mem + 9);
+		scal_detail_ptr->port2_port_connect = readb (io_mem + 10);
+		debug ("node_id: %x\ncbar: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nport2_node: %x\nport2_port: %x\n", scal_detail_ptr->node_id, scal_detail_ptr->cbar, scal_detail_ptr->port0_node_connect, scal_detail_ptr->port0_port_connect, scal_detail_ptr->port1_node_connect, scal_detail_ptr->port1_port_connect, scal_detail_ptr->port2_node_connect, scal_detail_ptr->port2_port_connect);
+//		list_add (&scal_detail_ptr->scal_detail_list, &scal_detail_head);
+		offset += 11;
+	}
+	for (i=0; i < rio_table_ptr->riodev_count; i++) {
+		rio_detail_ptr = kmalloc (sizeof (struct rio_detail), GFP_KERNEL );
+		if (!rio_detail_ptr )
+			return -ENOMEM;
+		memset (rio_detail_ptr, 0, sizeof (struct rio_detail) );
+		rio_detail_ptr->rio_node_id = readb (io_mem + offset );
+		rio_detail_ptr->bbar = readl (io_mem + offset + 1);
+		rio_detail_ptr->rio_type = readb (io_mem + offset + 5);
+		rio_detail_ptr->owner_id = readb (io_mem + offset + 6);
+		rio_detail_ptr->port0_node_connect = readb (io_mem + offset + 7);
+		rio_detail_ptr->port0_port_connect = readb (io_mem + offset + 8);
+		rio_detail_ptr->port1_node_connect = readb (io_mem + offset + 9);
+		rio_detail_ptr->port1_port_connect = readb (io_mem + offset + 10);
+		rio_detail_ptr->first_slot_num = readb (io_mem + offset + 11);
+		rio_detail_ptr->status = readb (io_mem + offset + 12);
+		debug ("rio_node_id: %x\nbbar: %x\nrio_type: %x\nowner_id: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nfirst_slot_num: %x\nstatus: %x\n", rio_detail_ptr->rio_node_id, rio_detail_ptr->bbar, rio_detail_ptr->rio_type, rio_detail_ptr->owner_id, rio_detail_ptr->port0_node_connect, rio_detail_ptr->port0_port_connect, rio_detail_ptr->port1_node_connect, rio_detail_ptr->port1_port_connect, rio_detail_ptr->first_slot_num, rio_detail_ptr->status);
+		offset += 13;
+	}
+	return 0;
+}
+
+u16 ibmphp_get_total_controllers (void)
+{
+	return hpc_list_ptr->num_ctlrs;
+}
+
+struct slot *ibmphp_get_slot_from_physical_num (u8 physical_num)
+{
+	struct slot *slot;
+	struct list_head *list;
+
+	list_for_each (list, &ibmphp_slot_head) {
+		slot = list_entry (list, struct slot, ibm_slot_list);
+		if (slot->number == physical_num)
+			return slot;
+	}
+	return NULL;
+}
+
+/* To find:
+ *	- the smallest slot number
+ *	- the largest slot number
+ *	- the total number of the slots based on each bus
+ *	  (if only one slot per bus slot_min = slot_max )
+ */
+struct bus_info *ibmphp_find_same_bus_num (u32 num)
+{
+	struct bus_info *ptr;
+	struct list_head  *ptr1;
+
+	list_for_each (ptr1, &bus_info_head) {
+		ptr = list_entry (ptr1, struct bus_info, bus_info_list); 
+		if (ptr->busno == num) 
+			 return ptr;
+	}
+	return NULL;
+}
+
+/*  Finding relative bus number, in order to map corresponding
+ *  bus register
+ */
+int ibmphp_get_bus_index (u8 num)
+{
+	struct bus_info *ptr;
+	struct list_head  *ptr1;
+
+	list_for_each (ptr1, &bus_info_head) {
+		ptr = list_entry (ptr1, struct bus_info, bus_info_list);
+		if (ptr->busno == num)  
+			return ptr->index;
+	}
+	return -ENODEV;
+}
+
+void ibmphp_free_bus_info_queue (void)
+{
+	struct bus_info *bus_info;
+	struct list_head *list;
+	struct list_head *next;
+
+	list_for_each_safe (list, next, &bus_info_head ) {
+		bus_info = list_entry (list, struct bus_info, bus_info_list);
+		kfree (bus_info);
+	}
+}
+
+/*
+ * Calculate the total hot pluggable slots controlled by total hpcs
+ */
+/*
+int ibmphp_get_total_hp_slots (void)
+{
+	struct ebda_hpc *ptr;
+	int slot_num = 0;
+
+	ptr = ebda_hpc_head;
+	while (ptr != NULL) {
+		slot_num += ptr->slot_count;
+		ptr = ptr->next;
+	}
+	return slot_num;
+}
+*/
+
+void ibmphp_free_ebda_hpc_queue (void)
+{
+	struct controller *controller;
+	struct list_head *list;
+	struct list_head *next;
+
+	list_for_each_safe (list, next, &ebda_hpc_head) {
+		controller = list_entry (list, struct controller, ebda_hpc_list);
+		free_ebda_hpc (controller);
+	}
+}
+
+void ibmphp_free_ebda_pci_rsrc_queue (void)
+{
+	struct ebda_pci_rsrc *resource;
+	struct list_head *list;
+	struct list_head *next;
+
+	list_for_each_safe (list, next, &ibmphp_ebda_pci_rsrc_head) {
+		resource = list_entry (list, struct ebda_pci_rsrc, ebda_pci_rsrc_list);
+		kfree (resource);
+		resource = NULL;
+	}
+}
+
diff -urN linux-2.5.6-pre1/drivers/hotplug/ibmphp_hpc.c linux-2.5.6-pre2/drivers/hotplug/ibmphp_hpc.c
--- linux-2.5.6-pre1/drivers/hotplug/ibmphp_hpc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/drivers/hotplug/ibmphp_hpc.c	Thu Feb 28 13:34:21 2002
@@ -0,0 +1,1135 @@
+/*
+ * IBM Hot Plug Controller Driver
+ *
+ * Written By: Jyoti Shah, IBM Corporation
+ *
+ * Copyright (c) 2001,2001 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>
+ *                  <jshah@us.ibm.com>
+ *
+ */
+
+//#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/time.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include "ibmphp.h"
+
+#define POLL_NO		0x01
+#define POLL_YES	0x00
+
+static int to_debug = FALSE;
+#define debug_polling(fmt, arg...)	do { if (to_debug) debug (fmt, arg); } while (0)
+
+//----------------------------------------------------------------------------
+// timeout values
+//----------------------------------------------------------------------------
+#define CMD_COMPLETE_TOUT_SEC	60	// give HPC 60 sec to finish cmd
+#define HPC_CTLR_WORKING_TOUT	60	// give HPC 60 sec to finish cmd
+#define HPC_GETACCESS_TIMEOUT	60	// seconds
+#define POLL_INTERVAL_SEC	2	// poll HPC every 2 seconds
+#define POLL_LATCH_CNT		5	// poll latch 5 times, then poll slots
+
+//----------------------------------------------------------------------------
+// Winnipeg Architected Register Offsets
+//----------------------------------------------------------------------------
+#define WPG_I2CMBUFL_OFFSET	0x08	// I2C Message Buffer Low
+#define WPG_I2CMOSUP_OFFSET	0x10	// I2C Master Operation Setup Reg
+#define WPG_I2CMCNTL_OFFSET	0x20	// I2C Master Control Register
+#define WPG_I2CPARM_OFFSET	0x40	// I2C Parameter Register
+#define WPG_I2CSTAT_OFFSET	0x70	// I2C Status Register
+
+//----------------------------------------------------------------------------
+// Winnipeg Store Type commands (Add this commands to the register offset)
+//----------------------------------------------------------------------------
+#define WPG_I2C_AND		0x1000	// I2C AND operation
+#define WPG_I2C_OR		0x2000	// I2C OR operation
+
+//----------------------------------------------------------------------------
+// Command set for I2C Master Operation Setup Regisetr
+//----------------------------------------------------------------------------
+#define WPG_READATADDR_MASK	0x00010000	// read,bytes,I2C shifted,index
+#define WPG_WRITEATADDR_MASK	0x40010000	// write,bytes,I2C shifted,index
+#define WPG_READDIRECT_MASK	0x10010000
+#define WPG_WRITEDIRECT_MASK	0x60010000
+
+
+//----------------------------------------------------------------------------
+// bit masks for I2C Master Control Register
+//----------------------------------------------------------------------------
+#define WPG_I2CMCNTL_STARTOP_MASK	0x00000002	// Start the Operation
+
+//----------------------------------------------------------------------------
+//
+//----------------------------------------------------------------------------
+#define WPG_I2C_IOREMAP_SIZE	0x2044	// size of linear address interval
+#define WPG_CTLR_MAX		0x01	// max controllers
+#define WPG_SLOT_MAX		0x06	// max slots
+#define WPG_CTLR_SLOT_MAX	0x06	// max slots per controller
+#define WPG_FIRST_CTLR		0x00	// index of the controller
+
+//----------------------------------------------------------------------------
+// command index
+//----------------------------------------------------------------------------
+#define WPG_1ST_SLOT_INDEX	0x01	// index - 1st slot for ctlr
+#define WPG_CTLR_INDEX		0x0F	// index - ctlr
+#define WPG_1ST_EXTSLOT_INDEX	0x10	// index - 1st ext slot for ctlr
+#define WPG_1ST_BUS_INDEX	0x1F	// index - 1st bus for ctlr
+
+//----------------------------------------------------------------------------
+// macro utilities
+//----------------------------------------------------------------------------
+// if bits 20,22,25,26,27,29,30 are OFF return TRUE
+#define HPC_I2CSTATUS_CHECK(s)	((u8)((s & 0x00000A76) ? FALSE : TRUE))
+
+// return code 0:poll slots, 1-POLL_LATCH_CNT:poll latch register
+#define INCREMENT_POLLCNT(i)	((i < POLL_LATCH_CNT) ? i++ : (i=0))
+//----------------------------------------------------------------------------
+// global variables
+//----------------------------------------------------------------------------
+static int ibmphp_shutdown;
+static int tid_poll;
+static int stop_polling;		// 2 values: poll, don't poll
+static struct semaphore sem_hpcaccess;	// lock access to HPC
+static struct semaphore semOperations;	// lock all operations and
+					// access to data structures
+static struct semaphore sem_exit;	// make sure polling thread goes away
+static struct semaphore sem_poll;	// make sure poll is idle 
+//----------------------------------------------------------------------------
+// local function prototypes
+//----------------------------------------------------------------------------
+static u8 ctrl_read (struct controller *, void *, u8);
+static u8 ctrl_write (struct controller *, void *, u8, u8);
+static u8 hpc_writecmdtoindex (u8, u8);
+static u8 hpc_readcmdtoindex (u8, u8);
+static void get_hpc_access (void);
+static void free_hpc_access (void);
+static void poll_hpc (void);
+static int update_slot (struct slot *, u8);
+static int process_changeinstatus (struct slot *, struct slot *);
+static int process_changeinlatch (u8, u8);
+static int hpc_poll_thread (void *);
+static int hpc_wait_ctlr_notworking (int, struct controller *, void *, u8 *);
+//----------------------------------------------------------------------------
+
+
+/*----------------------------------------------------------------------
+* Name:    ibmphp_hpc_initvars
+*
+* Action:  initialize semaphores and variables
+*---------------------------------------------------------------------*/
+void ibmphp_hpc_initvars (void)
+{
+	debug ("%s - Entry\n", __FUNCTION__);
+
+	init_MUTEX (&sem_hpcaccess);
+	init_MUTEX (&semOperations);
+	init_MUTEX_LOCKED (&sem_exit);
+	init_MUTEX_LOCKED (&sem_poll);
+	stop_polling = POLL_YES;
+	to_debug = FALSE;
+	ibmphp_shutdown = FALSE;
+	tid_poll = 0;
+
+	debug ("%s - Exit\n", __FUNCTION__);
+}
+
+/*----------------------------------------------------------------------
+* Name:    ctrl_read
+*
+* Action:  read from HPC over I2C
+*
+*---------------------------------------------------------------------*/
+static u8 ctrl_read (struct controller *ctlr_ptr, void *WPGBbar, u8 index)
+{
+	u8 status;
+	int i;
+	void *wpg_addr;		// base addr + offset
+	ulong wpg_data,		// data to/from WPG LOHI format
+	ultemp, data;		// actual data HILO format
+
+
+	debug_polling ("%s - Entry WPGBbar[%lx] index[%x] \n", __FUNCTION__, (ulong) WPGBbar, index);
+
+	//--------------------------------------------------------------------
+	// READ - step 1
+	// read at address, byte length, I2C address (shifted), index
+	// or read direct, byte length, index
+	if (ctlr_ptr->ctlr_type == 0x02) {
+		data = WPG_READATADDR_MASK;
+		// fill in I2C address
+		ultemp = (ulong) ctlr_ptr->u.wpeg_ctlr.i2c_addr;
+		ultemp = ultemp >> 1;
+		data |= (ultemp << 8);
+
+		// fill in index
+		data |= (ulong) index;
+	} else if (ctlr_ptr->ctlr_type == 0x04) {
+		data = WPG_READDIRECT_MASK;
+
+		// fill in index
+		ultemp = (ulong) index;
+		ultemp = ultemp << 8;
+		data |= ultemp;
+	} else {
+		err ("this controller type is not supported \n");
+		return HPC_ERROR;
+	}
+
+	wpg_data = swab32 (data);	// swap data before writing
+	(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET;
+	writel (wpg_data, wpg_addr);
+
+	//--------------------------------------------------------------------
+	// READ - step 2 : clear the message buffer
+	data = 0x00000000;
+	wpg_data = swab32 (data);
+	(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET;
+	writel (wpg_data, wpg_addr);
+
+	//--------------------------------------------------------------------
+	// READ - step 3 : issue start operation, I2C master control bit 30:ON
+	//                 2020 : [20] OR operation at [20] offset 0x20
+	data = WPG_I2CMCNTL_STARTOP_MASK;
+	wpg_data = swab32 (data);
+	(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR;
+	writel (wpg_data, wpg_addr);
+
+	//--------------------------------------------------------------------
+	// READ - step 4 : wait until start operation bit clears
+	i = CMD_COMPLETE_TOUT_SEC;
+	while (i) {
+		long_delay (1 * HZ / 100);
+		(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET;
+		wpg_data = readl (wpg_addr);
+		data = swab32 (wpg_data);
+		if (!(data & WPG_I2CMCNTL_STARTOP_MASK))
+			break;
+		i--;
+	}
+	if (i == 0) {
+		debug ("%s - Error : WPG timeout\n", __FUNCTION__);
+		return HPC_ERROR;
+	}
+	//--------------------------------------------------------------------
+	// READ - step 5 : read I2C status register
+	i = CMD_COMPLETE_TOUT_SEC;
+	while (i) {
+		long_delay (1 * HZ / 100);
+		(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET;
+		wpg_data = readl (wpg_addr);
+		data = swab32 (wpg_data);
+		if (HPC_I2CSTATUS_CHECK (data))
+			break;
+		i--;
+	}
+	if (i == 0) {
+		debug ("ctrl_read - Exit Error:I2C timeout\n");
+		return HPC_ERROR;
+	}
+
+	//--------------------------------------------------------------------
+	// READ - step 6 : get DATA
+	(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET;
+	wpg_data = readl (wpg_addr);
+	data = swab32 (wpg_data);
+
+	status = (u8) data;
+
+	debug_polling ("%s - Exit index[%x] status[%x]\n", __FUNCTION__, index, status);
+
+	return (status);
+}
+
+/*----------------------------------------------------------------------
+* Name:    ctrl_write
+*
+* Action:  write to HPC over I2C
+*
+* Return   0 or error codes
+*---------------------------------------------------------------------*/
+static u8 ctrl_write (struct controller *ctlr_ptr, void *WPGBbar, u8 index, u8 cmd)
+{
+	u8 rc;
+	void *wpg_addr;		// base addr + offset
+	ulong wpg_data,		// data to/from WPG LOHI format 
+	ultemp, data;		// actual data HILO format
+	int i;
+
+
+	debug_polling ("%s - Entry WPGBbar[%lx] index[%x] cmd[%x]\n",
+		       __FUNCTION__, (ulong) WPGBbar, index, cmd);
+
+	rc = 0;
+	//--------------------------------------------------------------------
+	// WRITE - step 1
+	// write at address, byte length, I2C address (shifted), index
+	// or write direct, byte length, index
+	data = 0x00000000;
+
+	if (ctlr_ptr->ctlr_type == 0x02) {
+		data = WPG_WRITEATADDR_MASK;
+		// fill in I2C address
+		ultemp = (ulong) ctlr_ptr->u.wpeg_ctlr.i2c_addr;
+		ultemp = ultemp >> 1;
+		data |= (ultemp << 8);
+
+		// fill in index
+		data |= (ulong) index;
+	} else if (ctlr_ptr->ctlr_type == 0x04) {
+		data = WPG_WRITEDIRECT_MASK;
+
+		// fill in index
+		ultemp = (ulong) index;
+		ultemp = ultemp << 8;
+		data |= ultemp;
+	} else {
+		err ("this controller type is not supported \n");
+		return HPC_ERROR;
+	}
+
+	wpg_data = swab32 (data);	// swap data before writing
+	(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET;
+	writel (wpg_data, wpg_addr);
+
+	//--------------------------------------------------------------------
+	// WRITE - step 2 : clear the message buffer
+	data = 0x00000000 | (ulong) cmd;
+	wpg_data = swab32 (data);
+	(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET;
+	writel (wpg_data, wpg_addr);
+
+	//--------------------------------------------------------------------
+	// WRITE - step 3 : issue start operation,I2C master control bit 30:ON
+	//                 2020 : [20] OR operation at [20] offset 0x20
+	data = WPG_I2CMCNTL_STARTOP_MASK;
+	wpg_data = swab32 (data);
+	(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR;
+	writel (wpg_data, wpg_addr);
+
+	//--------------------------------------------------------------------
+	// WRITE - step 4 : wait until start operation bit clears
+	i = CMD_COMPLETE_TOUT_SEC;
+	while (i) {
+		long_delay (1 * HZ / 100);
+		(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET;
+		wpg_data = readl (wpg_addr);
+		data = swab32 (wpg_data);
+		if (!(data & WPG_I2CMCNTL_STARTOP_MASK))
+			break;
+		i--;
+	}
+	if (i == 0) {
+		debug ("%s - Exit Error:WPG timeout\n", __FUNCTION__);
+		rc = HPC_ERROR;
+	}
+
+	//--------------------------------------------------------------------
+	// WRITE - step 5 : read I2C status register
+	i = CMD_COMPLETE_TOUT_SEC;
+	while (i) {
+		long_delay (1 * HZ / 100);
+		(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET;
+		wpg_data = readl (wpg_addr);
+		data = swab32 (wpg_data);
+		if (HPC_I2CSTATUS_CHECK (data))
+			break;
+		i--;
+	}
+	if (i == 0) {
+		debug ("ctrl_read - Error : I2C timeout\n");
+		rc = HPC_ERROR;
+	}
+
+	debug_polling ("%s Exit rc[%x]\n", __FUNCTION__, rc);
+	return (rc);
+}
+
+/*----------------------------------------------------------------------
+* Name:    hpc_writecmdtoindex()
+*
+* Action:  convert a write command to proper index within a controller
+*
+* Return   index, HPC_ERROR
+*---------------------------------------------------------------------*/
+static u8 hpc_writecmdtoindex (u8 cmd, u8 index)
+{
+	u8 rc;
+
+	switch (cmd) {
+	case HPC_CTLR_ENABLEIRQ:	// 0x00.N.15
+	case HPC_CTLR_CLEARIRQ:	// 0x06.N.15
+	case HPC_CTLR_RESET:	// 0x07.N.15
+	case HPC_CTLR_IRQSTEER:	// 0x08.N.15
+	case HPC_CTLR_DISABLEIRQ:	// 0x01.N.15
+	case HPC_ALLSLOT_ON:	// 0x11.N.15
+	case HPC_ALLSLOT_OFF:	// 0x12.N.15
+		rc = 0x0F;
+		break;
+
+	case HPC_SLOT_OFF:	// 0x02.Y.0-14
+	case HPC_SLOT_ON:	// 0x03.Y.0-14
+	case HPC_SLOT_ATTNOFF:	// 0x04.N.0-14
+	case HPC_SLOT_ATTNON:	// 0x05.N.0-14
+	case HPC_SLOT_BLINKLED:	// 0x13.N.0-14
+		rc = index;
+		break;
+
+	case HPC_BUS_33CONVMODE:
+	case HPC_BUS_66CONVMODE:
+	case HPC_BUS_66PCIXMODE:
+	case HPC_BUS_100PCIXMODE:
+	case HPC_BUS_133PCIXMODE:
+		rc = index + WPG_1ST_BUS_INDEX - 1;
+		break;
+
+	default:
+		err ("hpc_writecmdtoindex - Error invalid cmd[%x]\n", cmd);
+		rc = HPC_ERROR;
+	}
+
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    hpc_readcmdtoindex()
+*
+* Action:  convert a read command to proper index within a controller
+*
+* Return   index, HPC_ERROR
+*---------------------------------------------------------------------*/
+static u8 hpc_readcmdtoindex (u8 cmd, u8 index)
+{
+	u8 rc;
+
+	switch (cmd) {
+	case READ_CTLRSTATUS:
+		rc = 0x0F;
+		break;
+	case READ_SLOTSTATUS:
+	case READ_ALLSTAT:
+		rc = index;
+		break;
+	case READ_EXTSLOTSTATUS:
+		rc = index + WPG_1ST_EXTSLOT_INDEX;
+		break;
+	case READ_BUSSTATUS:
+		rc = index + WPG_1ST_BUS_INDEX - 1;
+		break;
+	case READ_SLOTLATCHLOWREG:
+		rc = 0x28;
+		break;
+	case READ_REVLEVEL:
+		rc = 0x25;
+		break;
+	case READ_HPCOPTIONS:
+		rc = 0x27;
+		break;
+	default:
+		rc = HPC_ERROR;
+	}
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    HPCreadslot()
+*
+* Action:  issue a READ command to HPC
+*
+* Input:   pslot   - can not be NULL for READ_ALLSTAT
+*          pstatus - can be NULL for READ_ALLSTAT
+*
+* Return   0 or error codes
+*---------------------------------------------------------------------*/
+int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus)
+{
+	void *wpg_bbar;
+	struct controller *ctlr_ptr;
+	struct list_head *pslotlist;
+	u8 index, status;
+	int rc = 0;
+	int busindex;
+
+	debug_polling ("%s - Entry pslot[%lx] cmd[%x] pstatus[%lx]\n",
+		       __FUNCTION__, (ulong) pslot, cmd, (ulong) pstatus);
+
+	if ((pslot == NULL)
+	    || ((pstatus == NULL) && (cmd != READ_ALLSTAT) && (cmd != READ_BUSSTATUS))) {
+		rc = -EINVAL;
+		err ("%s - Error invalid pointer, rc[%d]\n", __FUNCTION__, rc);
+		return rc;
+	}
+
+	if (cmd == READ_BUSSTATUS) {
+		busindex = ibmphp_get_bus_index (pslot->bus);
+		if (busindex < 0) {
+			rc = -EINVAL;
+			err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc);
+			return rc;
+		} else
+			index = (u8) busindex;
+	} else
+		index = pslot->ctlr_index;
+
+	index = hpc_readcmdtoindex (cmd, index);
+
+	if (index == HPC_ERROR) {
+		rc = -EINVAL;
+		err ("%s - Exit Error:invalid index, rc[%d]\n", __FUNCTION__, rc);
+		return rc;
+	}
+
+	ctlr_ptr = pslot->ctrl;
+
+	get_hpc_access ();
+
+	//--------------------------------------------------------------------
+	// map physical address to logical address
+	//--------------------------------------------------------------------
+	wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE);
+
+	//--------------------------------------------------------------------
+	// check controller status before reading
+	//--------------------------------------------------------------------
+	rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status);
+	if (!rc) {
+		switch (cmd) {
+		case READ_ALLSTAT:
+			// update the slot structure
+			pslot->ctrl->status = status;
+			pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index);
+			rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar,
+						       &status);
+			if (!rc)
+				pslot->ext_status = ctrl_read (ctlr_ptr, wpg_bbar, index + WPG_1ST_EXTSLOT_INDEX);
+
+			break;
+
+		case READ_SLOTSTATUS:
+			// DO NOT update the slot structure
+			*pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index);
+			break;
+
+		case READ_EXTSLOTSTATUS:
+			// DO NOT update the slot structure
+			*pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index);
+			break;
+
+		case READ_CTLRSTATUS:
+			// DO NOT update the slot structure
+			*pstatus = status;
+			break;
+
+		case READ_BUSSTATUS:
+			pslot->busstatus = ctrl_read (ctlr_ptr, wpg_bbar, index);
+			break;
+		case READ_REVLEVEL:
+			*pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index);
+			break;
+		case READ_HPCOPTIONS:
+			*pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index);
+			break;
+		case READ_SLOTLATCHLOWREG:
+			// DO NOT update the slot structure
+			*pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index);
+			break;
+
+			// Not used
+		case READ_ALLSLOT:
+			list_for_each (pslotlist, &ibmphp_slot_head) {
+				pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+				index = pslot->ctlr_index;
+				rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr,
+								wpg_bbar, &status);
+				if (!rc) {
+					pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index);
+					rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT,
+									ctlr_ptr, wpg_bbar, &status);
+					if (!rc)
+						pslot->ext_status =
+						    ctrl_read (ctlr_ptr, wpg_bbar,
+								index + WPG_1ST_EXTSLOT_INDEX);
+				} else {
+					err ("%s - Error ctrl_read failed\n", __FUNCTION__);
+					rc = -EINVAL;
+					break;
+				}
+			}
+			break;
+		default:
+			rc = -EINVAL;
+			break;
+		}
+	}
+	//--------------------------------------------------------------------
+	// cleanup
+	//--------------------------------------------------------------------
+	iounmap (wpg_bbar);	// remove physical to logical address mapping
+	free_hpc_access ();
+
+	debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc);
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    ibmphp_hpc_writeslot()
+*
+* Action: issue a WRITE command to HPC
+*---------------------------------------------------------------------*/
+int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd)
+{
+	void *wpg_bbar;
+	struct controller *ctlr_ptr;
+	u8 index, status;
+	int busindex;
+	u8 done;
+	int rc = 0;
+	int timeout;
+
+	debug_polling ("%s - Entry pslot[%lx] cmd[%x]\n", __FUNCTION__, (ulong) pslot, cmd);
+	if (pslot == NULL) {
+		rc = -EINVAL;
+		err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc);
+		return rc;
+	}
+
+	if ((cmd == HPC_BUS_33CONVMODE) || (cmd == HPC_BUS_66CONVMODE) ||
+		(cmd == HPC_BUS_66PCIXMODE) || (cmd == HPC_BUS_100PCIXMODE) ||
+		(cmd == HPC_BUS_133PCIXMODE)) {
+		busindex = ibmphp_get_bus_index (pslot->bus);
+		if (busindex < 0) {
+			rc = -EINVAL;
+			err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc);
+			return rc;
+		} else
+			index = (u8) busindex;
+	} else
+		index = pslot->ctlr_index;
+
+	index = hpc_writecmdtoindex (cmd, index);
+
+	if (index == HPC_ERROR) {
+		rc = -EINVAL;
+		err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc);
+		return rc;
+	}
+
+	ctlr_ptr = pslot->ctrl;
+
+	get_hpc_access ();
+
+	//--------------------------------------------------------------------
+	// map physical address to logical address
+	//--------------------------------------------------------------------
+	wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE);
+
+	debug ("%s - ctlr id[%x] physical[%lx] logical[%lx] i2c[%x]\n", __FUNCTION__,
+		ctlr_ptr->ctlr_id, (ulong) (ctlr_ptr->u.wpeg_ctlr.wpegbbar), (ulong) wpg_bbar,
+		ctlr_ptr->u.wpeg_ctlr.i2c_addr);
+
+	//--------------------------------------------------------------------
+	// check controller status before writing
+	//--------------------------------------------------------------------
+	rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status);
+	if (!rc) {
+
+		ctrl_write (ctlr_ptr, wpg_bbar, index, cmd);
+
+		//--------------------------------------------------------------------
+		// check controller is still not working on the command
+		//--------------------------------------------------------------------
+		timeout = CMD_COMPLETE_TOUT_SEC;
+		done = FALSE;
+		while (!done) {
+			rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar,
+							&status);
+			if (!rc) {
+				if (NEEDTOCHECK_CMDSTATUS (cmd)) {
+					if (CTLR_FINISHED (status) == HPC_CTLR_FINISHED_YES)
+						done = TRUE;
+				} else
+					done = TRUE;
+			}
+			if (!done) {
+				long_delay (1 * HZ);
+				if (timeout < 1) {
+					done = TRUE;
+					err ("%s - Error command complete timeout\n", __FUNCTION__);
+					rc = -EFAULT;
+				} else
+					timeout--;
+			}
+		}
+		ctlr_ptr->status = status;
+	}
+	// cleanup
+	iounmap (wpg_bbar);	// remove physical to logical address mapping
+	free_hpc_access ();
+
+	debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc);
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    get_hpc_access()
+*
+* Action: make sure only one process can access HPC at one time
+*---------------------------------------------------------------------*/
+static void get_hpc_access (void)
+{
+	down (&sem_hpcaccess);
+}
+
+/*----------------------------------------------------------------------
+* Name:    free_hpc_access()
+*---------------------------------------------------------------------*/
+void free_hpc_access (void)
+{
+	up (&sem_hpcaccess);
+}
+
+/*----------------------------------------------------------------------
+* Name:    ibmphp_lock_operations()
+*
+* Action: make sure only one process can change the data structure
+*---------------------------------------------------------------------*/
+void ibmphp_lock_operations (void)
+{
+	down (&semOperations);
+	stop_polling = POLL_NO;
+	to_debug = TRUE;
+
+	/* waiting for polling to actually stop */
+	down (&sem_poll);
+}
+
+/*----------------------------------------------------------------------
+* Name:    ibmphp_unlock_operations()
+*---------------------------------------------------------------------*/
+void ibmphp_unlock_operations (void)
+{
+	debug ("%s - Entry\n", __FUNCTION__);
+	stop_polling = POLL_YES;
+	to_debug = FALSE;
+	up (&semOperations);
+	debug ("%s - Exit\n", __FUNCTION__);
+}
+
+/*----------------------------------------------------------------------
+* Name:    poll_hpc()
+*---------------------------------------------------------------------*/
+static void poll_hpc (void)
+{
+	struct slot myslot, *pslot = NULL;
+	struct list_head *pslotlist;
+	int rc;
+	u8 oldlatchlow = 0x00;
+	u8 curlatchlow = 0x00;
+	int pollcnt = 0;
+	u8 ctrl_count = 0x00;
+
+	debug ("poll_hpc - Entry\n");
+
+	while (!ibmphp_shutdown) {
+		if (stop_polling) {
+			debug ("poll_hpc - stop_polling\n");
+			up (&sem_poll); 
+			/* to prevent deadlock */
+			if (ibmphp_shutdown)
+				break;
+			/* to make the thread sleep */
+			down (&semOperations);
+			up (&semOperations);
+			debug ("poll_hpc - after stop_polling sleep\n");
+		} else {
+			if (pollcnt) {
+				// only poll the latch register
+				oldlatchlow = curlatchlow;
+
+				ctrl_count = 0x00;
+				list_for_each (pslotlist, &ibmphp_slot_head) {
+					if (ctrl_count >= ibmphp_get_total_controllers())
+						break;
+					pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+					if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
+						ctrl_count++;
+						if (READ_SLOT_LATCH (pslot->ctrl)) {
+							rc = ibmphp_hpc_readslot (pslot,
+										  READ_SLOTLATCHLOWREG,
+										  &curlatchlow);
+							if (oldlatchlow != curlatchlow)
+								process_changeinlatch (oldlatchlow,
+											curlatchlow);
+						}
+					}
+				}
+			} else {
+				list_for_each (pslotlist, &ibmphp_slot_head) {
+					if (stop_polling)
+						break;
+					pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+					// make a copy of the old status
+					memcpy ((void *) &myslot, (void *) pslot,
+						sizeof (struct slot));
+					rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL);
+					if ((myslot.status != pslot->status)
+					    || (myslot.ext_status != pslot->ext_status))
+						process_changeinstatus (pslot, &myslot);
+				}
+
+				if (!stop_polling) {
+					ctrl_count = 0x00;
+					list_for_each (pslotlist, &ibmphp_slot_head) {
+						if (ctrl_count >= ibmphp_get_total_controllers())
+							break;
+						pslot =
+						    list_entry (pslotlist, struct slot,
+								ibm_slot_list);
+						if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
+							ctrl_count++;
+							if (READ_SLOT_LATCH (pslot->ctrl))
+								rc = ibmphp_hpc_readslot (pslot,
+											  READ_SLOTLATCHLOWREG,
+											  &curlatchlow);
+						}
+					}
+				}
+			}
+			INCREMENT_POLLCNT (pollcnt);
+			long_delay (POLL_INTERVAL_SEC * HZ);	// snooze
+		}
+	}
+	up (&sem_poll);
+	up (&sem_exit);
+	debug ("poll_hpc - Exit\n");
+}
+
+
+/* ----------------------------------------------------------------------
+ *  Name:    ibmphp_hpc_fillhpslotinfo(hotplug_slot * phpslot)
+ *
+ *  Action:  fill out the hotplug_slot info
+ *
+ *  Input:   pointer to hotplug_slot
+ *
+ *  Return
+ *  Value:   0 or error codes
+ *-----------------------------------------------------------------------*/
+int ibmphp_hpc_fillhpslotinfo (struct hotplug_slot *phpslot)
+{
+	int rc = 0;
+	struct slot *pslot;
+
+	if (phpslot && phpslot->private) {
+		pslot = (struct slot *) phpslot->private;
+		rc = update_slot (pslot, (u8) TRUE);
+		if (!rc) {
+
+			// power - enabled:1  not:0
+			phpslot->info->power_status = SLOT_POWER (pslot->status);
+
+			// attention - off:0, on:1, blinking:2
+			phpslot->info->attention_status = SLOT_ATTN (pslot->status, pslot->ext_status);
+
+			// latch - open:1 closed:0
+			phpslot->info->latch_status = SLOT_LATCH (pslot->status);
+
+			// pci board - present:1 not:0
+			if (SLOT_PRESENT (pslot->status))
+				phpslot->info->adapter_status = 1;
+			else
+				phpslot->info->adapter_status = 0;
+/*
+			if (pslot->bus_on->supported_bus_mode
+				&& (pslot->bus_on->supported_speed == BUS_SPEED_66))
+				phpslot->info->max_bus_speed_status = BUS_SPEED_66PCIX;
+			else
+				phpslot->info->max_bus_speed_status = pslot->bus_on->supported_speed;
+*/		} else
+			rc = -EINVAL;
+	} else
+		rc = -EINVAL;
+
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    update_slot
+*
+* Action:  fill out slot status and extended status, controller status
+*
+* Input:   pointer to slot struct
+*---------------------------------------------------------------------*/
+static int update_slot (struct slot *pslot, u8 update)
+{
+	int rc = 0;
+
+	debug ("%s - Entry pslot[%lx]\n", __FUNCTION__, (ulong) pslot);
+	rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL);
+	debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc);
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    process_changeinstatus
+*
+* Action:  compare old and new slot status, process the change in status
+*
+* Input:   pointer to slot struct, old slot struct
+*
+* Return   0 or error codes
+* Value:
+*
+* Side
+* Effects: None.
+*
+* Notes:
+*---------------------------------------------------------------------*/
+static int process_changeinstatus (struct slot *pslot, struct slot *poldslot)
+{
+	u8 status;
+	int rc = 0;
+	u8 disable = FALSE;
+	u8 update = FALSE;
+
+	debug ("process_changeinstatus - Entry pslot[%lx], poldslot[%lx]\n", (ulong) pslot,
+	       (ulong) poldslot);
+
+	// bit 0 - HPC_SLOT_POWER
+	if ((pslot->status & 0x01) != (poldslot->status & 0x01))
+		/* ????????? DO WE NEED TO UPDATE BUS SPEED INFO HERE ??? */
+		update = TRUE;
+
+	// bit 1 - HPC_SLOT_CONNECT
+	// ignore
+
+	// bit 2 - HPC_SLOT_ATTN
+	if ((pslot->status & 0x04) != (poldslot->status & 0x04))
+		update = TRUE;
+
+	// bit 3 - HPC_SLOT_PRSNT2
+	// bit 4 - HPC_SLOT_PRSNT1
+	if (((pslot->status & 0x08) != (poldslot->status & 0x08))
+		|| ((pslot->status & 0x10) != (poldslot->status & 0x10)))
+		update = TRUE;
+
+	// bit 5 - HPC_SLOT_PWRGD
+	if ((pslot->status & 0x20) != (poldslot->status & 0x20))
+		// OFF -> ON: ignore, ON -> OFF: disable slot
+		if (poldslot->status & 0x20)
+			disable = TRUE;
+
+	// bit 6 - HPC_SLOT_BUS_SPEED
+	// ignore
+
+	// bit 7 - HPC_SLOT_LATCH
+	if ((pslot->status & 0x80) != (poldslot->status & 0x80)) {
+		update = TRUE;
+		// OPEN -> CLOSE
+		if (pslot->status & 0x80) {
+			if (SLOT_POWER (pslot->status)) {
+				// power goes on and off after closing latch
+				// check again to make sure power is still ON
+				long_delay (1 * HZ);
+				rc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &status);
+				if (SLOT_POWER (status))
+					update = TRUE;
+				else	// overwrite power in pslot to OFF
+					pslot->status &= ~HPC_SLOT_POWER;
+			}
+		}
+		// CLOSE -> OPEN 
+		else if ((SLOT_POWER (poldslot->status) == HPC_SLOT_POWER_ON)
+			|| (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED)) {
+			disable = TRUE;
+		}
+		// else - ignore
+	}
+	// bit 4 - HPC_SLOT_BLINK_ATTN
+	if ((pslot->ext_status & 0x08) != (poldslot->ext_status & 0x08))
+		update = TRUE;
+
+	if (disable) {
+		debug ("process_changeinstatus - disable slot\n");
+		pslot->flag = FALSE;
+		rc = ibmphp_disable_slot (pslot->hotplug_slot);
+	}
+
+	if (update || disable) {
+		ibmphp_update_slot_info (pslot);
+	}
+
+	debug ("%s - Exit rc[%d] disable[%x] update[%x]\n", __FUNCTION__, rc, disable, update);
+
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    process_changeinlatch
+*
+* Action:  compare old and new latch reg status, process the change
+*
+* Input:   old and current latch register status
+*
+* Return   0 or error codes
+* Value:
+*---------------------------------------------------------------------*/
+static int process_changeinlatch (u8 old, u8 new)
+{
+	struct slot myslot, *pslot;
+	u8 i;
+	u8 mask;
+	int rc = 0;
+
+	debug ("%s - Entry old[%x], new[%x]\n", __FUNCTION__, old, new);
+	// bit 0 reserved, 0 is LSB, check bit 1-6 for 6 slots
+
+	for (i = 1; i <= 6; i++) {
+		mask = 0x01 << i;
+		if ((mask & old) != (mask & new)) {
+			pslot = ibmphp_get_slot_from_physical_num (i);
+			if (pslot) {
+				memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot));
+				rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL);
+				debug ("%s - call process_changeinstatus for slot[%d]\n", __FUNCTION__, i);
+				process_changeinstatus (pslot, &myslot);
+			} else {
+				rc = -EINVAL;
+				err ("%s - Error bad pointer for slot[%d]\n", __FUNCTION__, i);
+			}
+		}
+	}
+	debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc);
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    hpc_poll_thread
+*
+* Action:  polling
+*
+* Return   0
+* Value:
+*---------------------------------------------------------------------*/
+static int hpc_poll_thread (void *data)
+{
+	debug ("%s - Entry\n", __FUNCTION__);
+	lock_kernel ();
+	daemonize ();
+	reparent_to_init ();
+
+	//  New name
+	strcpy (current->comm, "hpc_poll");
+
+	unlock_kernel ();
+
+	poll_hpc ();
+
+	tid_poll = 0;
+	debug ("%s - Exit\n", __FUNCTION__);
+	return 0;
+}
+
+
+/*----------------------------------------------------------------------
+* Name:    ibmphp_hpc_start_poll_thread
+*
+* Action:  start polling thread
+*---------------------------------------------------------------------*/
+int ibmphp_hpc_start_poll_thread (void)
+{
+	int rc = 0;
+
+	debug ("ibmphp_hpc_start_poll_thread - Entry\n");
+
+	tid_poll = kernel_thread (hpc_poll_thread, 0, 0);
+	if (tid_poll < 0) {
+		err ("ibmphp_hpc_start_poll_thread - Error, thread not started\n");
+		rc = -1;
+	}
+
+	debug ("ibmphp_hpc_start_poll_thread - Exit tid_poll[%d] rc[%d]\n", tid_poll, rc);
+	return rc;
+}
+
+/*----------------------------------------------------------------------
+* Name:    ibmphp_hpc_stop_poll_thread
+*
+* Action:  stop polling thread and cleanup
+*---------------------------------------------------------------------*/
+void ibmphp_hpc_stop_poll_thread (void)
+{
+	debug ("ibmphp_hpc_stop_poll_thread - Entry\n");
+
+	ibmphp_shutdown = TRUE;
+	ibmphp_lock_operations ();
+
+	// wait for poll thread to exit
+	down (&sem_exit);
+
+	// cleanup
+	free_hpc_access ();
+	ibmphp_unlock_operations ();
+	up (&sem_poll);
+	up (&sem_exit);
+
+	debug ("ibmphp_hpc_stop_poll_thread - Exit\n");
+}
+
+/*----------------------------------------------------------------------
+* Name:    hpc_wait_ctlr_notworking
+*
+* Action:  wait until the controller is in a not working state
+*
+* Return   0, HPC_ERROR
+* Value:
+*---------------------------------------------------------------------*/
+static int hpc_wait_ctlr_notworking (int timeout, struct controller *ctlr_ptr, void *wpg_bbar,
+				    u8 * pstatus)
+{
+	int rc = 0;
+	u8 done = FALSE;
+
+	debug_polling ("hpc_wait_ctlr_notworking - Entry timeout[%d]\n", timeout);
+
+	while (!done) {
+		*pstatus = ctrl_read (ctlr_ptr, wpg_bbar, WPG_CTLR_INDEX);
+		if (*pstatus == HPC_ERROR) {
+			rc = HPC_ERROR;
+			done = TRUE;
+		}
+		if (CTLR_WORKING (*pstatus) == HPC_CTLR_WORKING_NO)
+			done = TRUE;
+		if (!done) {
+			long_delay (1 * HZ);
+			if (timeout < 1) {
+				done = TRUE;
+				err ("HPCreadslot - Error ctlr timeout\n");
+				rc = HPC_ERROR;
+			} else
+				timeout--;
+		}
+	}
+	debug_polling ("hpc_wait_ctlr_notworking - Exit rc[%x] status[%x]\n", rc, *pstatus);
+	return rc;
+}
diff -urN linux-2.5.6-pre1/drivers/hotplug/ibmphp_pci.c linux-2.5.6-pre2/drivers/hotplug/ibmphp_pci.c
--- linux-2.5.6-pre1/drivers/hotplug/ibmphp_pci.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/drivers/hotplug/ibmphp_pci.c	Thu Feb 28 13:34:21 2002
@@ -0,0 +1,1719 @@
+/*
+ * IBM Hot Plug Controller Driver
+ * 
+ * Written By: Irene Zubarev, IBM Corporation
+ * 
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001,2002 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include "ibmphp.h"
+
+
+static int configure_device(struct pci_func *);
+static int configure_bridge(struct pci_func **, u8);
+static struct res_needed *scan_behind_bridge(struct pci_func *, u8);
+static int add_new_bus (struct bus_node *, struct resource_node *, struct resource_node *, struct resource_node *, u8);
+static u8 find_sec_number (u8 primary_busno, u8 slotno);
+
+/*
+ * NOTE..... If BIOS doesn't provide default routing, we assign:
+ * 9 for SCSI, 10 for LAN adapters, and 11 for everything else. 
+ * If adapter is bridged, then we assign 11 to it and devices behind it.
+ * We also assign the same irq numbers for multi function devices.
+ * These are PIC mode, so shouldn't matter n.e.ways (hopefully)
+ */
+static void assign_alt_irq (struct pci_func * cur_func, u8 class_code)
+{
+	int j = 0;
+	for (j = 0; j < 4; j++) {
+		if (cur_func->irq[j] == 0xff) {
+			switch (class_code) {
+				case PCI_BASE_CLASS_STORAGE:
+					cur_func->irq[j] = SCSI_IRQ;
+					break;
+				case PCI_BASE_CLASS_NETWORK:
+					cur_func->irq[j] = LAN_IRQ;
+					break;
+				default:
+					cur_func->irq[j] = OTHER_IRQ;
+					break;
+			}
+		}
+	}
+}
+
+/*
+ * Configures the device to be added (will allocate needed resources if it
+ * can), the device can be a bridge or a regular pci device, can also be
+ * multi-functional
+ * 
+ * Input: function to be added
+ * 
+ * TO DO:  The error case with Multifunction device or multi function bridge,
+ * if there is an error, will need to go through all previous functions and 
+ * unconfigure....or can add some code into unconfigure_card....
+ */
+int ibmphp_configure_card (struct pci_func *func, u8 slotno)
+{
+	u16 vendor_id;
+	u32 class;
+	u8 class_code;
+	u8 hdr_type, device, sec_number;
+	u8 function;
+	struct pci_func *newfunc;	/* for multi devices */
+	struct pci_func *cur_func, *prev_func;
+	int rc, i, j;
+	int cleanup_count;
+	u8 flag;
+	u8 valid_device = 0x00; /* to see if we are able to read from card any device info at all */
+
+	debug ("inside configure_card, func->busno = %x \n", func->busno);
+
+	device = func->device;
+	cur_func = func;
+
+	/* We only get bus and device from IRQ routing table.  So at this point,
+	 * func->busno is correct, and func->device contains only device (at the 5 
+	 * highest bits)
+	 */
+
+	/* For every function on the card */
+	for (function = 0x00; function < 0x08; function++) {
+		cur_func->function = function;
+
+		debug ("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->funcion = %x\n", cur_func->busno, device, function);
+
+		pci_read_config_word_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_VENDOR_ID, &vendor_id);
+
+		debug ("vendor_id is %x\n", vendor_id);
+		if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
+			/* found correct device!!! */
+			debug ("found valid device, vendor_id = %x\n", vendor_id);
+
+			++valid_device;
+
+			/* header: x x x x x x x x
+			 *         | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge
+			 *         |_=> 0 = single function device, 1 = multi-function device
+			 */
+
+			pci_read_config_byte_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_HEADER_TYPE, &hdr_type);
+			pci_read_config_dword_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_CLASS_REVISION, &class);
+
+			class_code = class >> 24;
+			debug ("hrd_type = %x, class = %x, class_code %x \n", hdr_type, class, class_code);
+			class >>= 8;	/* to take revision out, class = class.subclass.prog i/f */
+			if (class == PCI_CLASS_NOT_DEFINED_VGA) {
+				err ("The device %x is VGA compatible and as is not supported for hot plugging. "
+				     "Please choose another device.\n", cur_func->device);
+				return -ENODEV;
+			} else if (class == PCI_CLASS_DISPLAY_VGA) {
+				err ("The device %x is not supported for hot plugging. "
+				     "Please choose another device.\n", cur_func->device);
+				return -ENODEV;
+			}
+			switch (hdr_type) {
+				case PCI_HEADER_TYPE_NORMAL:
+					debug ("single device case.... vendor id = %x, hdr_type = %x, class = %x\n", vendor_id, hdr_type, class);
+					assign_alt_irq (cur_func, class_code);
+					if ((rc = configure_device (cur_func)) < 0) {
+						/* We need to do this in case some other BARs were properly inserted */
+						err ("was not able to configure devfunc %x on bus %x. \n",
+						     cur_func->device, cur_func->busno);
+						cleanup_count = 6;
+						goto error;
+					}	
+					cur_func->next = NULL;
+					function = 0x8;
+					break;
+				case PCI_HEADER_TYPE_MULTIDEVICE:
+					assign_alt_irq (cur_func, class_code);
+					if ((rc = configure_device (cur_func)) < 0) {
+						/* We need to do this in case some other BARs were properly inserted */
+						err ("was not able to configure devfunc %x on bus %x...bailing out\n",
+						     cur_func->device, cur_func->busno);
+						cleanup_count = 6;
+						goto error;
+					}
+					newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL);
+					if (!newfunc) {
+						err ("out of system memory \n");
+						return -ENOMEM;
+					}
+					memset (newfunc, 0, sizeof (struct pci_func));
+					newfunc->busno = cur_func->busno;
+					newfunc->device = device;
+					cur_func->next = newfunc;
+					cur_func = newfunc;
+					for (j = 0; j < 4; j++)
+						newfunc->irq[j] = cur_func->irq[j];
+					break;
+				case PCI_HEADER_TYPE_MULTIBRIDGE:
+					class >>= 8;
+					if (class != PCI_CLASS_BRIDGE_PCI) {
+						err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. "
+						     "Please insert another card.\n", cur_func->device);
+						return -ENODEV;
+					}
+					assign_alt_irq (cur_func, class_code);
+					rc = configure_bridge (&cur_func, slotno);
+					if (rc == -ENODEV) {
+						err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n");
+						err ("Bus %x, devfunc %x \n", cur_func->busno, cur_func->device);
+						return rc;
+					}
+					if (rc) {
+						/* We need to do this in case some other BARs were properly inserted */
+						err ("was not able to hot-add PPB properly.\n");
+						func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */
+						cleanup_count = 2;
+						goto error;
+					}
+
+					pci_read_config_byte_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_SECONDARY_BUS, &sec_number);
+					flag = FALSE;
+					for (i = 0; i < 32; i++) {
+						if (func->devices[i]) {
+							newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL);
+							if (!newfunc) {
+								err ("out of system memory \n");
+								return -ENOMEM;
+							}
+							memset (newfunc, 0, sizeof (struct pci_func));
+							newfunc->busno = sec_number;
+							newfunc->device = (u8) i;
+							for (j = 0; j < 4; j++)
+								newfunc->irq[j] = cur_func->irq[j];
+
+							if (flag) {
+								for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ;
+								prev_func->next = newfunc;
+							} else
+								cur_func->next = newfunc;
+
+							rc = ibmphp_configure_card (newfunc, slotno);
+							/* This could only happen if kmalloc failed */
+							if (rc) {
+								/* We need to do this in case bridge itself got configured properly, but devices behind it failed */
+								func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */
+								cleanup_count = 2;
+								goto error;
+							}
+							flag = TRUE;
+						}
+					}
+
+					newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL);
+					if (!newfunc) {
+						err ("out of system memory \n");
+						return -ENOMEM;
+					}
+					memset (newfunc, 0, sizeof (struct pci_func));
+					newfunc->busno = cur_func->busno;
+					newfunc->device = device;
+					for (j = 0; j < 4; j++)
+						newfunc->irq[j] = cur_func->irq[j];
+					for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ;
+					prev_func->next = newfunc;
+					cur_func = newfunc;
+					break;
+				case PCI_HEADER_TYPE_BRIDGE:
+					class >>= 8;
+					debug ("class now is %x\n", class);
+					if (class != PCI_CLASS_BRIDGE_PCI) {
+						err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. "
+						     "Please insert another card.\n", cur_func->device);
+						return -ENODEV;
+					}
+
+					assign_alt_irq (cur_func, class_code);
+
+					debug ("cur_func->busno b4 configure_bridge is %x\n", cur_func->busno);
+					rc = configure_bridge (&cur_func, slotno);
+					if (rc == -ENODEV) {
+						err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n");
+						err ("Bus %x, devfunc %x \n", cur_func->busno, cur_func->device);
+						return rc;
+					}
+					if (rc) {
+						/* We need to do this in case some other BARs were properly inserted */
+						func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */
+						err ("was not able to hot-add PPB properly.\n");
+						cleanup_count = 2;
+						goto error;
+					}
+					debug ("cur_func->busno = %x, device = %x, function = %x\n", cur_func->busno, device, function);
+					pci_read_config_byte_nodev (ibmphp_pci_root_ops, cur_func->busno, device, function, PCI_SECONDARY_BUS, &sec_number);
+					debug ("after configuring bridge..., sec_number = %x\n", sec_number);
+					flag = FALSE;
+					for (i = 0; i < 32; i++) {
+						if (func->devices[i]) {
+							debug ("inside for loop, device is %x\n", i);
+							newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL);
+							if (!newfunc) {
+								err (" out of system memory \n");
+								return -ENOMEM;
+							}
+							memset (newfunc, 0, sizeof (struct pci_func));
+							newfunc->busno = sec_number;
+							newfunc->device = (u8) i;
+							for (j = 0; j < 4; j++)
+								newfunc->irq[j] = cur_func->irq[j];
+
+							if (flag) {
+								for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ;
+								prev_func->next = newfunc;
+							} else
+								cur_func->next = newfunc;
+
+							rc = ibmphp_configure_card (newfunc, slotno);
+
+							/* Again, this case should not happen... For complete paranoia, will need to call remove_bus */
+							if (rc) {
+								/* We need to do this in case some other BARs were properly inserted */
+								func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */
+								cleanup_count = 2;
+								goto error;
+							}
+							flag = TRUE;
+						}
+					}
+
+					function = 0x8;
+					break;
+				default:
+					err ("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type);
+					return -ENXIO;
+					break;
+			}	/* end of switch */
+		}	/* end of valid device */
+	}	/* end of for */
+
+	if (!valid_device) {
+		err ("Cannot find any valid devices on the card.  Or unable to read from card.\n");
+		return -ENODEV;
+	}
+
+	return 0;
+
+error:
+	for (i = 0; i < cleanup_count; i++) {
+		if (cur_func->io[i]) {
+			ibmphp_remove_resource (cur_func->io[i]);
+			cur_func->io[i] = NULL;
+		} else if (cur_func->pfmem[i]) {
+			ibmphp_remove_resource (cur_func->pfmem[i]);
+			cur_func->pfmem[i] = NULL;
+		} else if (cur_func->mem[i]) {
+			ibmphp_remove_resource (cur_func->mem[i]);
+			cur_func->mem[i] = NULL;
+		}
+	}
+	return rc;
+}
+
+/*
+ * This function configures the pci BARs of a single device.  
+ * Input: pointer to the pci_func
+ * Output: configured PCI, 0, or error
+ */
+static int configure_device (struct pci_func *func)
+{
+	u32 bar[6];
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		PCI_BASE_ADDRESS_2,
+		PCI_BASE_ADDRESS_3,
+		PCI_BASE_ADDRESS_4,
+		PCI_BASE_ADDRESS_5,
+		0
+	};
+	u8 irq;
+	int count;
+	int len[6];
+	struct resource_node *io[6];
+	struct resource_node *mem[6];
+	struct resource_node *mem_tmp;
+	struct resource_node *pfmem[6];
+	u8 device;
+	u8 function;
+
+	debug ("%s - inside\n", __FUNCTION__);
+
+	device = func->device;
+	function = func->function;
+
+	for (count = 0; address[count]; count++) {	/* for 6 BARs */
+
+		/* not sure if i need this.  per scott, said maybe need smth like this
+		   if devices don't adhere 100% to the spec, so don't want to write
+		   to the reserved bits
+
+		pcibios_read_config_byte(cur_func->busno, cur_func->device, 
+		PCI_BASE_ADDRESS_0 + 4 * count, &tmp);
+		if (tmp & 0x01) // IO
+			pcibios_write_config_dword(cur_func->busno, cur_func->device, 
+			PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFD);
+		else  // Memory
+			pcibios_write_config_dword(cur_func->busno, cur_func->device, 
+			PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFF);
+		 */
+		pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0xFFFFFFFF);
+		pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]);
+
+		if (!bar[count])	/* This BAR is not implemented */
+			continue;
+
+		debug ("Device %x BAR %d wants %x\n", func->device, count, bar[count]);
+
+		if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+			debug ("inside IO SPACE\n");
+
+			len[count] = bar[count] & 0xFFFFFFFC;
+			len[count] = ~len[count] + 1;
+
+			debug ("len[count] in IO %x, count %d\n", len[count], count);
+
+			io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+
+			if (!io[count]) {
+				err ("out of system memory \n");
+				return -ENOMEM;
+			}
+			memset (io[count], 0, sizeof (struct resource_node));
+			io[count]->type = IO;
+			io[count]->busno = func->busno;
+			io[count]->devfunc = ((func->device << 3) | (func->function & 0x7));
+			io[count]->len = len[count];
+			if (ibmphp_check_resource(io[count], 0) == 0) {
+				ibmphp_add_resource (io[count]);
+				func->io[count] = io[count];
+			} else {
+				err ("cannot allocate requested io for bus %x device %x function %x len %x\n",
+				     func->busno, func->device, func->function, len[count]);
+				kfree (io[count]);
+				return -EIO;
+			}
+			pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->io[count]->start);
+	
+			/* _______________This is for debugging purposes only_____________________ */ 
+			debug ("b4 writing, the IO address is %x\n", func->io[count]->start);
+			pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]);
+			debug ("after writing.... the start address is %x\n", bar[count]);
+			/* _________________________________________________________________________*/
+
+		} else {
+			/* This is Memory */
+			if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+				debug ("PFMEM SPACE\n");
+
+				len[count] = bar[count] & 0xFFFFFFF0;
+				len[count] = ~len[count] + 1;
+
+				debug ("len[count] in PFMEM %x, count %d\n", len[count], count);
+
+				pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+				if (!pfmem[count]) {
+					err ("out of system memory \n");
+					return -ENOMEM;
+				}
+				memset (pfmem[count], 0, sizeof (struct resource_node));
+				pfmem[count]->type = PFMEM;
+				pfmem[count]->busno = func->busno;
+				pfmem[count]->devfunc = ((func->device << 3) | (func->function & 0x7));
+				pfmem[count]->len = len[count];
+				pfmem[count]->fromMem = FALSE;
+				if (ibmphp_check_resource (pfmem[count], 0) == 0) {
+					ibmphp_add_resource (pfmem[count]);
+					func->pfmem[count] = pfmem[count];
+				} else {
+					mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+					if (!mem_tmp) {
+						err ("out of system memory \n");
+						kfree (pfmem[count]);
+						return -ENOMEM;
+					}
+					memset (mem_tmp, 0, sizeof (struct resource_node));
+					mem_tmp->type = MEM;
+					mem_tmp->busno = pfmem[count]->busno;
+					mem_tmp->devfunc = pfmem[count]->devfunc;
+					mem_tmp->len = pfmem[count]->len;
+					debug ("there's no pfmem... going into mem.\n");
+					if (ibmphp_check_resource (mem_tmp, 0) == 0) {
+						ibmphp_add_resource (mem_tmp);
+						pfmem[count]->fromMem = TRUE;
+						pfmem[count]->rangeno = mem_tmp->rangeno;
+						pfmem[count]->start = mem_tmp->start;
+						pfmem[count]->end = mem_tmp->end;
+						ibmphp_add_pfmem_from_mem (pfmem[count]);
+						func->pfmem[count] = pfmem[count];
+					} else {
+						err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n",
+						     func->busno, func->device, len[count]);
+						kfree (mem_tmp);
+						kfree (pfmem[count]);
+						return -EIO;
+					}
+				}
+
+				pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->pfmem[count]->start);
+
+				/*_______________This if for debugging purposes only______________________________*/				
+				debug ("b4 writing, start addres is %x\n", func->pfmem[count]->start);
+				pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]);
+				debug ("after writing, start address is %x\n", bar[count]);
+				/*_________________________________________________________________________________*/
+
+				if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
+					debug ("inside the mem 64 case, count %d\n", count);
+					count += 1;
+					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
+					pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000);
+				}
+			} else {
+				/* regular memory */
+				debug ("REGULAR MEM SPACE\n");
+
+				len[count] = bar[count] & 0xFFFFFFF0;
+				len[count] = ~len[count] + 1;
+
+				debug ("len[count] in Mem %x, count %d\n", len[count], count);
+
+				mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+				if (!mem[count]) {
+					err ("out of system memory \n");
+					return -ENOMEM;
+				}
+				memset (mem[count], 0, sizeof (struct resource_node));
+				mem[count]->type = MEM;
+				mem[count]->busno = func->busno;
+				mem[count]->devfunc = ((func->device << 3) | (func->function & 0x7));
+				mem[count]->len = len[count];
+				if (ibmphp_check_resource (mem[count], 0) == 0) {
+					ibmphp_add_resource (mem[count]);
+					func->mem[count] = mem[count];
+				} else {
+					err ("cannot allocate requested mem for bus %x, device %x, len %x\n",
+					     func->busno, func->device, len[count]);
+					kfree (mem[count]);
+					return -EIO;
+				}
+				pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->mem[count]->start);
+				/* _______________________This is for debugging purposes only _______________________*/
+				debug ("b4 writing, start address is %x\n", func->mem[count]->start);
+				pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]);
+				debug ("after writing, the address is %x\n", bar[count]);
+				/* __________________________________________________________________________________*/
+
+				if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					debug ("inside mem 64 case, reg. mem, count %d\n", count);
+					count += 1;
+					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
+					pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000);
+				}
+			}
+		}		/* end of mem */
+	}			/* end of for */
+
+	func->bus = 0;		/* To indicate that this is not a PPB */
+	pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_PIN, &irq);
+	if ((irq > 0x00) && (irq < 0x05))
+		pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_LINE, func->irq[irq - 1]);
+
+	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_CACHE_LINE_SIZE, CACHE);
+	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_LATENCY_TIMER, LATENCY);
+
+	pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_ROM_ADDRESS, 0x00L);
+	pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_COMMAND, DEVICEENABLE);
+
+	return 0;
+}
+
+/******************************************************************************
+ * This routine configures a PCI-2-PCI bridge and the functions behind it
+ * Parameters: pci_func
+ * Returns: 
+ ******************************************************************************/
+static int configure_bridge (struct pci_func **func_passed, u8 slotno)
+{
+	int count;
+	int i;
+	int rc;
+	u8 sec_number;
+	u8 io_base;
+	u16 pfmem_base;
+	u32 bar[2];
+	u32 len[2];
+	u8 flag_io = FALSE;
+	u8 flag_mem = FALSE;
+	u8 flag_pfmem = FALSE;
+	u8 need_io_upper = FALSE;
+	u8 need_pfmem_upper = FALSE;
+	struct res_needed *amount_needed = NULL;
+	struct resource_node *io = NULL;
+	struct resource_node *bus_io[2] = {NULL, NULL};
+	struct resource_node *mem = NULL;
+	struct resource_node *bus_mem[2] = {NULL, NULL};
+	struct resource_node *mem_tmp = NULL;
+	struct resource_node *pfmem = NULL;
+	struct resource_node *bus_pfmem[2] = {NULL, NULL};
+	struct bus_node *bus;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		0
+	};
+	struct pci_func *func = *func_passed;
+	u8 function;
+	u8 device;
+	u8 irq;
+	int retval;
+
+	debug ("%s - enter\n", __FUNCTION__);
+
+	function = func->function;
+	device = func->device;
+
+	/* Configuring necessary info for the bridge so that we could see the devices
+	 * behind it
+	 */
+
+	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PRIMARY_BUS, func->busno);
+
+	/* _____________________For debugging purposes only __________________________
+	pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PRIMARY_BUS, &pri_number);
+	debug ("primary # written into the bridge is %x\n", pri_number);
+	 ___________________________________________________________________________*/
+
+	/* in EBDA, only get allocated 1 additional bus # per slot */
+	sec_number = find_sec_number (func->busno, slotno);
+	if (sec_number == 0xff) {
+		err ("cannot allocate secondary bus number for the bridged device \n");
+		return -EINVAL;
+	}
+
+	debug ("after find_sec_number, the number we got is %x\n", sec_number);
+	debug ("AFTER FIND_SEC_NUMBER, func->busno IS %x\n", func->busno);
+
+	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SECONDARY_BUS, sec_number);
+	
+	/* __________________For debugging purposes only __________________________________
+	pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SECONDARY_BUS, &sec_number);
+	debug ("sec_number after write/read is %x\n", sec_number);
+	 ________________________________________________________________________________*/
+
+	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SUBORDINATE_BUS, sec_number);
+
+	/* __________________For debugging purposes only ____________________________________
+	pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SUBORDINATE_BUS, &sec_number);
+	debug ("subordinate number after write/read is %x\n", sec_number);
+	 __________________________________________________________________________________*/
+
+	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_CACHE_LINE_SIZE, CACHE);
+	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_LATENCY_TIMER, LATENCY);
+	pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_SEC_LATENCY_TIMER, LATENCY);
+
+	debug ("func->busno is %x\n", func->busno);
+	debug ("sec_number after writing is %x\n", sec_number);
+
+
+	/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+	   !!!!!!!!!!!!!!!NEED TO ADD!!!  FAST BACK-TO-BACK ENABLE!!!!!!!!!!!!!!!!!!!! 
+	   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
+
+
+	/* First we need to allocate mem/io for the bridge itself in case it needs it */
+	for (count = 0; address[count]; count++) {	/* for 2 BARs */
+		pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0xFFFFFFFF);
+		pci_read_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], &bar[count]);
+
+		if (!bar[count]) {
+			/* This BAR is not implemented */
+			debug ("so we come here then, eh?, count = %d\n", count);
+			continue;
+		}
+		//  tmp_bar = bar[count];
+
+		debug ("Bar %d wants %x\n", count, bar[count]);
+
+		if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+			len[count] = bar[count] & 0xFFFFFFFC;
+			len[count] = ~len[count] + 1;
+
+			debug ("len[count] in IO = %x\n", len[count]);
+
+			bus_io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+		
+			if (!bus_io[count]) {
+				err ("out of system memory \n");
+				retval = -ENOMEM;
+				goto error;
+			}
+			memset (bus_io[count], 0, sizeof (struct resource_node));
+			bus_io[count]->type = IO;
+			bus_io[count]->busno = func->busno;
+			bus_io[count]->devfunc = ((func->device << 3) | (func->function & 0x7));
+			bus_io[count]->len = len[count];
+			if (ibmphp_check_resource (bus_io[count], 0) == 0) {
+				ibmphp_add_resource (bus_io[count]);
+				func->io[count] = bus_io[count];
+			} else {
+				err ("cannot allocate requested io for bus %x, device %x, len %x\n",
+				     func->busno, func->device, len[count]);
+				kfree (bus_io[count]);
+				return -EIO;
+			}
+
+			pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->io[count]->start);
+
+		} else {
+			/* This is Memory */
+			if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+				len[count] = bar[count] & 0xFFFFFFF0;
+				len[count] = ~len[count] + 1;
+
+				debug ("len[count] in PFMEM = %x\n", len[count]);
+
+				bus_pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+				if (!bus_pfmem[count]) {
+					err ("out of system memory \n");
+					retval = -ENOMEM;
+					goto error;
+				}
+				memset (bus_pfmem[count], 0, sizeof (struct resource_node));
+				bus_pfmem[count]->type = PFMEM;
+				bus_pfmem[count]->busno = func->busno;
+				bus_pfmem[count]->devfunc = ((func->device << 3) | (func->function & 0x7));
+				bus_pfmem[count]->len = len[count];
+				bus_pfmem[count]->fromMem = FALSE;
+				if (ibmphp_check_resource (bus_pfmem[count], 0) == 0) {
+					ibmphp_add_resource (bus_pfmem[count]);
+					func->pfmem[count] = bus_pfmem[count];
+				} else {
+					mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+					if (!mem_tmp) {
+						err ("out of system memory \n");
+						retval = -ENOMEM;
+						goto error;
+					}
+					memset (mem_tmp, 0, sizeof (struct resource_node));
+					mem_tmp->type = MEM;
+					mem_tmp->busno = bus_pfmem[count]->busno;
+					mem_tmp->devfunc = bus_pfmem[count]->devfunc;
+					mem_tmp->len = bus_pfmem[count]->len;
+					if (ibmphp_check_resource (mem_tmp, 0) == 0) {
+						ibmphp_add_resource (mem_tmp);
+						bus_pfmem[count]->fromMem = TRUE;
+						bus_pfmem[count]->rangeno = mem_tmp->rangeno;
+						ibmphp_add_pfmem_from_mem (bus_pfmem[count]);
+						func->pfmem[count] = bus_pfmem[count];
+					} else {
+						err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", 
+						     func->busno, func->device, len[count]);
+						kfree (mem_tmp);
+						kfree (bus_pfmem[count]);
+						return -EIO;
+					}
+				}
+
+				pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->pfmem[count]->start);
+
+				if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					count += 1;
+					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
+					pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000);
+
+				}
+			} else {
+				/* regular memory */
+				len[count] = bar[count] & 0xFFFFFFF0;
+				len[count] = ~len[count] + 1;
+
+				debug ("len[count] in Memory is %x\n", len[count]);
+
+				bus_mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+				if (!bus_mem[count]) {
+					err ("out of system memory \n");
+					retval = -ENOMEM;
+					goto error;
+				}
+				memset (bus_mem[count], 0, sizeof (struct resource_node));
+				bus_mem[count]->type = MEM;
+				bus_mem[count]->busno = func->busno;
+				bus_mem[count]->devfunc = ((func->device << 3) | (func->function & 0x7));
+				bus_mem[count]->len = len[count];
+				if (ibmphp_check_resource (bus_mem[count], 0) == 0) {
+					ibmphp_add_resource (bus_mem[count]);
+					func->mem[count] = bus_mem[count];
+				} else {
+					err ("cannot allocate requested mem for bus %x, device %x, len %x\n",
+					     func->busno, func->device, len[count]);
+					kfree (bus_mem[count]);
+					return -EIO;
+				}
+
+				pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], func->mem[count]->start);
+
+				if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					count += 1;
+					/* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */
+					pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, address[count], 0x00000000);
+
+				}
+			}
+		}		/* end of mem */
+	}			/* end of for  */
+
+	/* Now need to see how much space the devices behind the bridge needed */
+	amount_needed = scan_behind_bridge (func, sec_number);
+	if (amount_needed == NULL)
+		return -ENOMEM;
+
+	debug ("after coming back from scan_behind_bridge\n");
+	debug ("amount_needed->not_correct = %x\n", amount_needed->not_correct);
+	debug ("amount_needed->io = %x\n", amount_needed->io);
+	debug ("amount_needed->mem = %x\n", amount_needed->mem);
+	debug ("amount_needed->pfmem =  %x\n", amount_needed->pfmem);
+
+	if (amount_needed->not_correct) {		
+		debug ("amount_needed is not correct \n");
+		for (count = 0; address[count]; count++) {
+			/* for 2 BARs */
+			if (bus_io[count]) {
+				ibmphp_remove_resource (bus_io[count]);
+				func->io[count] = NULL;
+			} else if (bus_pfmem[count]) {
+				ibmphp_remove_resource (bus_pfmem[count]);
+				func->pfmem[count] = NULL;
+			} else if (bus_mem[count]) {
+				ibmphp_remove_resource (bus_mem[count]);
+				func->mem[count] = NULL;
+			}
+		}
+		kfree (amount_needed);
+		return -ENODEV;
+	}
+
+	if (!amount_needed->io) {
+		debug ("it doesn't want IO?\n");
+		flag_io = TRUE;
+	} else {
+		debug ("it wants %x IO behind the bridge \n", amount_needed->io);
+		io = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+		
+		if (!io) {
+			err ("out of system memory \n");
+			retval = -ENOMEM;
+			goto error;
+		}
+		memset (io, 0, sizeof (struct resource_node));
+		io->type = IO;
+		io->busno = func->busno;
+		io->devfunc = ((func->device << 3) | (func->function & 0x7));
+		io->len = amount_needed->io;
+		if (ibmphp_check_resource (io, 1) == 0) {
+			debug ("were we able to add io\n");
+			ibmphp_add_resource (io);
+			flag_io = TRUE;
+		}
+	}
+
+	if (!amount_needed->mem) {
+		debug ("it doesn't want n.e.memory?\n");
+		flag_mem = TRUE;
+	} else {
+		debug ("it wants %x memory behind the bridge\n", amount_needed->mem);
+		mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+		if (!mem) {
+			err ("out of system memory \n");
+			retval = -ENOMEM;
+			goto error;
+		}
+		memset (mem, 0, sizeof (struct resource_node));
+		mem->type = MEM;
+		mem->busno = func->busno;
+		mem->devfunc = ((func->device << 3) | (func->function & 0x7));
+		mem->len = amount_needed->mem;
+		if (ibmphp_check_resource (mem, 1) == 0) {
+			ibmphp_add_resource (mem);
+			flag_mem = TRUE;
+			debug ("were we able to add mem\n");
+		}
+	}
+
+	if (!amount_needed->pfmem) {
+		debug ("it doesn't want n.e.pfmem mem?\n");
+		flag_pfmem = TRUE;
+	} else {
+		debug ("it wants %x pfmemory behind the bridge\n", amount_needed->pfmem);
+		pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+		if (!pfmem) {
+			err ("out of system memory \n");
+			retval = -ENOMEM;
+			goto error;
+		}
+		memset (pfmem, 0, sizeof (struct resource_node));
+		pfmem->type = PFMEM;
+		pfmem->busno = func->busno;
+		pfmem->devfunc = ((func->device << 3) | (func->function & 0x7));
+		pfmem->len = amount_needed->pfmem;
+		pfmem->fromMem = FALSE;
+		if (ibmphp_check_resource (pfmem, 1) == 0) {
+			ibmphp_add_resource (pfmem);
+			flag_pfmem = TRUE;
+		} else {
+			mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+			if (!mem_tmp) {
+				err ("out of system memory \n");
+				retval = -ENOMEM;
+				goto error;
+			}
+			memset (mem_tmp, 0, sizeof (struct resource_node));
+			mem_tmp->type = MEM;
+			mem_tmp->busno = pfmem->busno;
+			mem_tmp->devfunc = pfmem->devfunc;
+			mem_tmp->len = pfmem->len;
+			if (ibmphp_check_resource (mem_tmp, 1) == 0) {
+				ibmphp_add_resource (mem_tmp);
+				pfmem->fromMem = TRUE;
+				pfmem->rangeno = mem_tmp->rangeno;
+				ibmphp_add_pfmem_from_mem (pfmem);
+				flag_pfmem = TRUE;
+			}
+		}
+	}
+
+	debug ("b4 if (flag_io && flag_mem && flag_pfmem)\n");
+	debug ("flag_io = %x, flag_mem = %x, flag_pfmem = %x\n", flag_io, flag_mem, flag_pfmem);
+
+	if (flag_io && flag_mem && flag_pfmem) {
+		bus = kmalloc (sizeof (struct bus_node), GFP_KERNEL);
+		if (!bus) {
+			err ("out of system memory \n");
+			retval = -ENOMEM;
+			goto error;
+		}
+		memset (bus, 0, sizeof (struct bus_node));
+		bus->busno = sec_number;
+		debug ("b4 adding new bus\n");
+		rc = add_new_bus (bus, io, mem, pfmem, func->busno);
+		if (rc) {
+			if (rc == -ENOMEM) {
+				ibmphp_remove_bus (bus, func->busno);
+				return rc;
+			}
+			retval = rc;
+			goto error;
+		}
+		pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, &io_base);
+		pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, &pfmem_base);
+
+		if ((io_base & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
+			debug ("io 32\n");
+			need_io_upper = TRUE;
+		}
+		if ((io_base & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
+			debug ("pfmem 64\n");
+			need_pfmem_upper = TRUE;
+		}
+
+		if (bus->noIORanges) {
+			pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, 0x00 | bus->rangeIO->start >> 8);
+			pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT, 0x00 | bus->rangeIO->end >> 8);	
+
+			/* _______________This is for debugging purposes only ____________________
+			pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, &temp);
+			debug ("io_base = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8);
+			pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT, &temp);
+			debug ("io_limit = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8);
+			 ________________________________________________________________________*/
+
+			if (need_io_upper) {	/* since can't support n.e.ways */
+				pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE_UPPER16, 0x0000);
+				pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT_UPPER16, 0x0000);
+			}
+		} else {
+			pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_BASE, 0x00);
+			pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_IO_LIMIT, 0x00);
+		}
+
+		if (bus->noMemRanges) {
+			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_BASE, 0x0000 | bus->rangeMem->start >> 16);
+			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_LIMIT, 0x0000 | bus->rangeMem->end >> 16);
+			
+			/* ____________________This is for debugging purposes only ________________________
+			pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_BASE, &temp);
+			debug ("mem_base = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
+			pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_LIMIT, &temp);
+			debug ("mem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
+			 __________________________________________________________________________________*/
+
+		} else {
+			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_BASE, 0xffff);
+			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_MEMORY_LIMIT, 0x0000);
+		}
+		if (bus->noPFMemRanges) {
+			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, 0x0000 | bus->rangePFMem->start >> 16);
+			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_LIMIT, 0x0000 | bus->rangePFMem->end >> 16);
+
+			/* __________________________This is for debugging purposes only _______________________
+			pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, &temp);
+			debug ("pfmem_base = %x", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
+			pci_read_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_LIMIT, &temp);
+			debug ("pfmem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16);
+			 ______________________________________________________________________________________*/
+
+			if (need_pfmem_upper) {	/* since can't support n.e.ways */
+				pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_BASE_UPPER32, 0x00000000);
+				pci_write_config_dword_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_LIMIT_UPPER32, 0x00000000);
+			}
+		} else {
+			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_BASE, 0xffff);
+			pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_PREF_MEMORY_LIMIT, 0x0000);
+		}
+
+		debug ("b4 writing control information\n");
+
+		pci_read_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_PIN, &irq);
+		if ((irq > 0x00) && (irq < 0x05))
+			pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_INTERRUPT_LINE, func->irq[irq - 1]);
+		/*    
+		pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, ctrl);
+		pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY);
+		pci_write_config_byte_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR);
+		 */
+
+		pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_COMMAND, DEVICEENABLE);
+		pci_write_config_word_nodev (ibmphp_pci_root_ops, func->busno, device, function, PCI_BRIDGE_CONTROL, 0x07);
+		for (i = 0; i < 32; i++) {
+			if (amount_needed->devices[i]) {
+				debug ("device where devices[i] is 1 = %x\n", i);
+				func->devices[i] = 1;
+			}
+		}
+		func->bus = 1;	/* For unconfiguring, to indicate it's PPB */
+		func_passed = &func;
+		debug ("func->busno b4 returning is %x\n", func->busno);
+		debug ("func->busno b4 returning in the other structure is %x\n", (*func_passed)->busno);
+		kfree (amount_needed);
+		return 0;
+	} else {
+		err ("Configuring bridge was unsuccessful... \n");
+		mem_tmp = NULL;
+		retval = -EIO;
+		goto error;
+	}
+
+error:
+	if (amount_needed)
+		kfree (amount_needed);
+	if (pfmem)
+		ibmphp_remove_resource (pfmem);
+	if (io)
+		ibmphp_remove_resource (io);
+	if (mem)
+		ibmphp_remove_resource (mem);
+	for (i = 0; i < 2; i++) {	/* for 2 BARs */
+		if (bus_io[i]) {
+			ibmphp_remove_resource (bus_io[i]);
+			func->io[i] = NULL;
+		} else if (bus_pfmem[i]) {
+			ibmphp_remove_resource (bus_pfmem[i]);
+			func->pfmem[i] = NULL;
+		} else if (bus_mem[i]) {
+			ibmphp_remove_resource (bus_mem[i]);
+			func->mem[i] = NULL;
+		}
+	}
+	return retval;
+}
+
+/*****************************************************************************
+ * This function adds up the amount of resources needed behind the PPB bridge
+ * and passes it to the configure_bridge function
+ * Input: bridge function
+ * Ouput: amount of resources needed
+ *****************************************************************************/
+static struct res_needed *scan_behind_bridge (struct pci_func * func, u8 busno)
+{
+	int count, len[6];
+	u16 vendor_id;
+	u8 hdr_type;
+	u8 device, function;
+	int howmany = 0;	/*this is to see if there are any devices behind the bridge */
+
+	u32 bar[6], class;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		PCI_BASE_ADDRESS_2,
+		PCI_BASE_ADDRESS_3,
+		PCI_BASE_ADDRESS_4,
+		PCI_BASE_ADDRESS_5,
+		0
+	};
+	struct res_needed *amount;
+
+	amount = kmalloc (sizeof (struct res_needed), GFP_KERNEL);
+	if (amount == NULL)
+		return NULL;
+	memset (amount, 0, sizeof (struct res_needed));
+
+	debug ("the bus_no behind the bridge is %x\n", busno);
+	debug ("scanning devices behind the bridge...\n");
+	for (device = 0; device < 32; device++) {
+		amount->devices[device] = 0;
+		for (function = 0; function < 8; function++) {
+
+			pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_VENDOR_ID, &vendor_id);
+
+			if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
+				/* found correct device!!! */
+				howmany++;
+
+				pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_HEADER_TYPE, &hdr_type);
+				pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_CLASS_REVISION, &class);
+
+				debug ("hdr_type behind the bridge is %x\n", hdr_type);
+				if (hdr_type & PCI_HEADER_TYPE_BRIDGE) {
+					err ("embedded bridges not supported for hot-plugging.\n");
+					amount->not_correct = TRUE;
+					return amount;
+				}
+
+				class >>= 8;	/* to take revision out, class = class.subclass.prog i/f */
+				if (class == PCI_CLASS_NOT_DEFINED_VGA) {
+					err ("The device %x is VGA compatible and as is not supported for hot plugging. "
+					     "Please choose another device.\n", device);
+					amount->not_correct = TRUE;
+					return amount;
+				} else if (class == PCI_CLASS_DISPLAY_VGA) {
+					err ("The device %x is not supported for hot plugging. "
+					     "Please choose another device.\n", device);
+					amount->not_correct = TRUE;
+					return amount;
+				}
+
+				amount->devices[device] = 1;
+
+				for (count = 0; address[count]; count++) {
+					/* for 6 BARs */
+					/*
+					pci_read_config_byte_nodev(ibmphp_pci_root_ops, busno, device, function, address[count], &tmp);
+					if (tmp & 0x01) // IO
+						pci_write_config_dword_nodev(ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFD);
+					else // MEMORY
+						pci_write_config_dword_nodev(ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFF);
+					*/
+					pci_write_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFF);
+					pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &bar[count]);
+
+					debug ("what is bar[count]? %x, count = %d\n", bar[count], count);
+
+					if (!bar[count])	/* This BAR is not implemented */
+						continue;
+
+					//tmp_bar = bar[count];
+
+					debug ("count %d device %x function %x wants %x resources \n", count, device, function, bar[count]);
+
+					if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) {
+						/* This is IO */
+						len[count] = bar[count] & 0xFFFFFFFC;
+						len[count] = ~len[count] + 1;
+						amount->io += len[count];
+					} else {
+						/* This is Memory */
+						if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+							/* pfmem */
+							len[count] = bar[count] & 0xFFFFFFF0;
+							len[count] = ~len[count] + 1;
+							amount->pfmem += len[count];
+							if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64)
+								/* takes up another dword */
+								count += 1;
+
+						} else {
+							/* regular memory */
+							len[count] = bar[count] & 0xFFFFFFF0;
+							len[count] = ~len[count] + 1;
+							amount->mem += len[count];
+							if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+								/* takes up another dword */
+								count += 1;
+							}
+						}
+					}
+				}	/* end for */
+			}	/* end if (valid) */
+		}	/* end for */
+	}	/* end for */
+
+	if (!howmany)
+		amount->not_correct = TRUE;
+	else
+		amount->not_correct = FALSE;
+	if ((amount->io) && (amount->io < IOBRIDGE))
+		amount->io = IOBRIDGE;
+	if ((amount->mem) && (amount->mem < MEMBRIDGE))
+		amount->mem = MEMBRIDGE;
+	if ((amount->pfmem) && (amount->pfmem < MEMBRIDGE))
+		amount->pfmem = MEMBRIDGE;
+	return amount;
+}
+
+/* The following 3 unconfigure_boot_ routines deal with the case when we had the card 
+ * upon bootup in the system, since we don't allocate func to such case, we need to read 
+ * the start addresses from pci config space and then find the corresponding entries in 
+ * our resource lists.  The functions return either 0, -ENODEV, or -1 (general failure)
+ * Change: we also call these functions even if we configured the card ourselves (i.e., not
+ * the bootup case), since it should work same way
+ */
+static int unconfigure_boot_device (u8 busno, u8 device, u8 function)
+{
+	u32 start_address;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		PCI_BASE_ADDRESS_2,
+		PCI_BASE_ADDRESS_3,
+		PCI_BASE_ADDRESS_4,
+		PCI_BASE_ADDRESS_5,
+		0
+	};
+	int count;
+	struct resource_node *io;
+	struct resource_node *mem;
+	struct resource_node *pfmem;
+	struct bus_node *bus;
+	u32 end_address;
+	u32 temp_end;
+	u32 size;
+	u32 tmp_address;
+
+	debug ("%s - enter\n", __FUNCTION__);
+
+	bus = ibmphp_find_res_bus (busno);
+	if (!bus) {
+		debug ("cannot find corresponding bus.\n");
+		return -EINVAL;
+	}
+
+	for (count = 0; address[count]; count++) {	/* for 6 BARs */
+		pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &start_address);
+
+		/* We can do this here, b/c by that time the device driver of the card has been stopped */
+
+		pci_write_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], 0xFFFFFFFF);
+		pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &size);
+		pci_write_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], start_address);
+
+		debug ("start_address is %x\n", start_address);
+		debug ("busno, device, function %x %x %x\n", busno, device, function);
+		if (!size) {
+			/* This BAR is not implemented */
+			debug ("is this bar no implemented?, count = %d\n", count);
+			continue;
+		}
+		tmp_address = start_address;
+		if (start_address & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+			start_address &= PCI_BASE_ADDRESS_IO_MASK;
+			size = size & 0xFFFFFFFC;
+			size = ~size + 1;
+			end_address = start_address + size - 1;
+			if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) {
+				err ("cannot find corresponding IO resource to remove\n");
+				return -EIO;
+			}
+			debug ("io->start = %x\n", io->start);
+			temp_end = io->end;
+			start_address = io->end + 1;
+			ibmphp_remove_resource (io);
+			/* This is needed b/c of the old I/O restrictions in the BIOS */
+			while (temp_end < end_address) {
+				if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) {
+					err ("cannot find corresponding IO resource to remove\n");
+					return -EIO;
+				}
+				debug ("io->start = %x\n", io->start);
+				temp_end = io->end;
+				start_address = io->end + 1;
+				ibmphp_remove_resource (io);
+			}
+
+			/* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */
+		} else {
+			/* This is Memory */
+			if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+				start_address &= PCI_BASE_ADDRESS_MEM_MASK;
+				debug ("start address of pfmem is %x\n", start_address);
+
+				if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) {
+					err ("cannot find corresponding PFMEM resource to remove\n");
+					return -EIO;
+				}
+				if (pfmem)
+					debug ("pfmem->start = %x\n", pfmem->start);
+
+				ibmphp_remove_resource (pfmem);
+
+				if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					count += 1;
+				}
+
+			} else {
+				/* regular memory */
+				start_address &= PCI_BASE_ADDRESS_MEM_MASK;
+				debug ("start address of mem is %x\n", start_address);
+				if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) {
+					err ("cannot find corresponding MEM resource to remove\n");
+					return -EIO;
+				}
+				if (mem)
+					debug ("mem->start = %x\n", mem->start);
+
+				ibmphp_remove_resource (mem);
+
+				if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					count += 1;
+				}
+			}
+		}	/* end of mem */
+	}	/* end of for */
+
+	return 0;
+}
+
+static int unconfigure_boot_bridge (u8 busno, u8 device, u8 function)
+{
+	int count;
+	int bus_no, pri_no, sub_no, sec_no = 0;
+	u32 start_address, tmp_address;
+	u8 sec_number, sub_number, pri_number;
+	struct resource_node *io = NULL;
+	struct resource_node *mem = NULL;
+	struct resource_node *pfmem = NULL;
+	struct bus_node *bus;
+	u32 address[] = {
+		PCI_BASE_ADDRESS_0,
+		PCI_BASE_ADDRESS_1,
+		0
+	};
+
+	bus_no = (int) busno;
+	debug ("busno is %x\n", busno);
+	pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PRIMARY_BUS, &pri_number);
+	debug ("%s - busno = %x, primary_number = %x\n", __FUNCTION__, busno, pri_number);
+
+	pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SECONDARY_BUS, &sec_number);
+	debug ("sec_number is %x\n", sec_number);
+	sec_no = (int) sec_number;
+	pri_no = (int) pri_number;
+	if (pri_no != bus_no) {
+		err ("primary numbers in our structures and pci config space don't match.\n");
+		return -EINVAL;
+	}
+
+	pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SECONDARY_BUS, &sec_number);
+	sec_no = (int) sec_no;
+
+	pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SUBORDINATE_BUS, &sub_number);
+	sub_no = (int) sub_number;
+	debug ("sub_no is %d, sec_no is %d\n", sub_no, sec_no);
+	if (sec_no != sub_number) {
+		err ("there're more buses behind this bridge.  Hot removal is not supported.  Please choose another card\n");
+		return -ENODEV;
+	}
+
+	bus = ibmphp_find_res_bus (sec_number);
+	debug ("bus->busno is %x\n", bus->busno);
+	debug ("sec_number is %x\n", sec_number);
+	if (!bus) {
+		err ("cannot find Bus structure for the bridged device\n");
+		return -EINVAL;
+	}
+
+	ibmphp_remove_bus (bus, busno);
+
+	for (count = 0; address[count]; count++) {
+		/* for 2 BARs */
+		pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, address[count], &start_address);
+
+		if (!start_address) {
+			/* This BAR is not implemented */
+			continue;
+		}
+
+		tmp_address = start_address;
+
+		if (start_address & PCI_BASE_ADDRESS_SPACE_IO) {
+			/* This is IO */
+			start_address &= PCI_BASE_ADDRESS_IO_MASK;
+			if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) {
+				err ("cannot find corresponding IO resource to remove\n");
+				return -EIO;
+			}
+			if (io)
+				debug ("io->start = %x\n", io->start);
+
+			ibmphp_remove_resource (io);
+
+			/* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */
+		} else {
+			/* This is Memory */
+			if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) {
+				/* pfmem */
+				start_address &= PCI_BASE_ADDRESS_MEM_MASK;
+				if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) {
+					err ("cannot find corresponding PFMEM resource to remove\n");
+					return -EINVAL;
+				}
+				if (pfmem)
+					debug ("pfmem->start = %x\n", pfmem->start);
+
+				ibmphp_remove_resource (pfmem);
+
+				if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					count += 1;
+				}
+
+			} else {
+				/* regular memory */
+				start_address &= PCI_BASE_ADDRESS_MEM_MASK;
+				if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) {
+					err ("cannot find corresponding MEM resource to remove\n");
+					return -EINVAL;
+				}
+				if (mem)
+					debug ("mem->start = %x\n", mem->start);
+
+				ibmphp_remove_resource (mem);
+
+				if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+					/* takes up another dword */
+					count += 1;
+				}
+			}
+		}	/* end of mem */
+	}	/* end of for */
+	debug ("%s - exiting, returning success\n", __FUNCTION__);
+	return 0;
+}
+
+static int unconfigure_boot_card (struct slot *slot_cur)
+{
+	u16 vendor_id;
+	u32 class;
+	u8 hdr_type;
+	u8 device;
+	u8 busno;
+	u8 function;
+	int rc;
+	u8 valid_device = 0x00; /* To see if we are ever able to find valid device and read it */
+
+	debug ("%s - enter\n", __FUNCTION__);
+
+	device = slot_cur->device;
+	busno = slot_cur->bus;
+
+	debug ("b4 for loop, device is %x\n", device);
+	/* For every function on the card */
+	for (function = 0x0; function < 0x08; function++) {
+
+		pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_VENDOR_ID, &vendor_id);
+
+		if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
+			/* found correct device!!! */
+			++valid_device;
+
+			debug ("%s - found correct device\n", __FUNCTION__);
+
+			/* header: x x x x x x x x
+			 *         | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge
+			 *         |_=> 0 = single function device, 1 = multi-function device
+			 */
+
+			pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_HEADER_TYPE, &hdr_type);
+			pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_CLASS_REVISION, &class);
+
+			debug ("hdr_type %x, class %x\n", hdr_type, class);
+			class >>= 8;	/* to take revision out, class = class.subclass.prog i/f */
+			if (class == PCI_CLASS_NOT_DEFINED_VGA) {
+				err ("The device %x function %x is VGA compatible and is not supported for hot removing. "
+				     "Please choose another device.\n", device, function);
+				return -ENODEV;
+			} else if (class == PCI_CLASS_DISPLAY_VGA) {
+				err ("The device %x function %x is not supported for hot removing. "
+				     "Please choose another device.\n", device, function);
+				return -ENODEV;
+			}
+
+			switch (hdr_type) {
+				case PCI_HEADER_TYPE_NORMAL:
+					rc = unconfigure_boot_device (busno, device, function);
+					if (rc) {
+						err ("was not able to unconfigure device %x func %x on bus %x. bailing out... \n",
+						     device, function, busno);
+						return rc;
+					}
+					function = 0x8;
+					break;
+				case PCI_HEADER_TYPE_MULTIDEVICE:
+					rc = unconfigure_boot_device (busno, device, function);
+					if (rc) {
+						err ("was not able to unconfigure device %x func %x on bus %x. bailing out... \n",
+						     device, function, busno);
+						return rc;
+					}
+					break;
+				case PCI_HEADER_TYPE_BRIDGE:
+					class >>= 8;
+					if (class != PCI_CLASS_BRIDGE_PCI) {
+						err ("This device %x function %x is not PCI-to-PCI bridge, "
+						     "and is not supported for hot-removing. "
+						     "Please try another card.\n", device, function);
+						return -ENODEV;
+					}
+					rc = unconfigure_boot_bridge (busno, device, function);
+					if (rc != 0) {
+						err ("was not able to hot-remove PPB properly.\n");
+						return rc;
+					}
+
+					function = 0x8;
+					break;
+				case PCI_HEADER_TYPE_MULTIBRIDGE:
+					class >>= 8;
+					if (class != PCI_CLASS_BRIDGE_PCI) {
+						err ("This device %x function %x is not PCI-to-PCI bridge, "
+						     "and is not supported for hot-removing. "
+						     "Please try another card.\n", device, function);
+						return -ENODEV;
+					}
+					rc = unconfigure_boot_bridge (busno, device, function);
+					if (rc != 0) {
+						err ("was not able to hot-remove PPB properly.\n");
+						return rc;
+					}
+					break;
+				default:
+					err ("MAJOR PROBLEM!!!! Cannot read device's header \n");
+					return -1;
+					break;
+			}	/* end of switch */
+		}	/* end of valid device */
+	}	/* end of for */
+
+	if (!valid_device) {
+		err ("Could not find device to unconfigure.  Or could not read the card. \n");
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * free the resources of the card (multi, single, or bridged)
+ * Parameters: slot, flag to say if this is for removing entire module or just
+ * unconfiguring the device
+ * TO DO:  will probably need to add some code in case there was some resource,
+ * to remove it... this is from when we have errors in the configure_card...
+ * 			!!!!!!!!!!!!!!!!!!!!!!!!!FOR BUSES!!!!!!!!!!!!
+ * Returns: 0, -1, -ENODEV 
+ */
+int ibmphp_unconfigure_card (struct slot **slot_cur, int the_end)
+{
+	int i;
+	int count;
+	int rc;
+	struct slot *sl = *slot_cur;
+	struct pci_func *cur_func = NULL;
+	struct pci_func *temp_func;
+
+	debug ("%s - enter\n", __FUNCTION__);
+
+	if (!the_end) {
+		/* Need to unconfigure the card */
+		rc = unconfigure_boot_card (sl);
+		if ((rc == -ENODEV) || (rc == -EIO) || (rc == -EINVAL)) {
+			/* In all other cases, will still need to get rid of func structure if it exists */
+			return rc;
+		}
+	}
+
+	if (sl->func) {
+		debug ("do we come in here? \n");
+		cur_func = sl->func;
+		while (cur_func) {
+			/* TO DO: WILL MOST LIKELY NEED TO GET RID OF THE BUS STRUCTURE FROM RESOURCES AS WELL */
+			if (cur_func->bus) {
+				/* in other words, it's a PPB */
+				count = 2;
+			} else {
+				count = 6;
+			}
+
+			for (i = 0; i < count; i++) {
+				if (cur_func->io[count]) {
+					debug ("io[%d] exists \n", count);
+					if (the_end > 0)
+						ibmphp_remove_resource (cur_func->io[count]);
+					cur_func->io[count] = NULL;
+				}
+				if (cur_func->mem[count]) {
+					debug ("mem[%d] exists \n", count);
+					if (the_end > 0)
+						ibmphp_remove_resource (cur_func->mem[count]);
+					cur_func->mem[count] = NULL;
+				}
+				if (cur_func->pfmem[count]) {
+					debug ("pfmem[%d] exists \n", count);
+					if (the_end > 0)
+						ibmphp_remove_resource (cur_func->pfmem[count]);
+					cur_func->pfmem[count] = NULL;
+				}
+			}
+
+			temp_func = cur_func->next;
+			kfree (cur_func);
+			cur_func = temp_func;
+		}
+	}
+
+	sl->func = NULL;
+	*slot_cur = sl;
+	return 0;
+}
+
+/*
+ * add a new bus resulting from hot-plugging a PPB bridge with devices
+ *
+ * Input: bus and the amount of resources needed (we know we can assign those,
+ *        since they've been checked already
+ * Output: bus added to the correct spot
+ *         0, -1, error 
+ */
+static int add_new_bus (struct bus_node *bus, struct resource_node *io, struct resource_node *mem, struct resource_node *pfmem, u8 parent_busno)
+{
+	struct range_node *io_range = NULL;
+	struct range_node *mem_range = NULL;
+	struct range_node *pfmem_range = NULL;
+	struct bus_node *cur_bus = NULL;
+
+	/* Trying to find the parent bus number */
+	cur_bus	= ibmphp_find_res_bus (parent_busno);
+	if (!cur_bus) {
+		err ("strange, cannot find bus which is supposed to be at the system... something is terribly wrong...\n");
+		return -ENODEV;
+	}
+
+	list_add (&bus->bus_list, &cur_bus->bus_list);
+
+	if (io) {
+		io_range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
+		if (!io_range) {
+			err ("out of system memory \n");
+			return -ENOMEM;
+		}
+		memset (io_range, 0, sizeof (struct range_node));
+		io_range->start = io->start;
+		io_range->end = io->end;
+		io_range->rangeno = 1;
+		bus->noIORanges = 1;
+		bus->rangeIO = io_range;
+	}
+	if (mem) {
+		mem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
+		if (!mem_range) {
+			err ("out of system memory \n");
+			return -ENOMEM;
+		}
+		memset (mem_range, 0, sizeof (struct range_node));
+		mem_range->start = mem->start;
+		mem_range->end = mem->end;
+		mem_range->rangeno = 1;
+		bus->noMemRanges = 1;
+		bus->rangeMem = mem_range;
+	}
+	if (pfmem) {
+		pfmem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
+		if (!pfmem_range) {	
+			err ("out of system memory \n");
+			return -ENOMEM;
+		}
+		memset (pfmem_range, 0, sizeof (struct range_node));
+		pfmem_range->start = pfmem->start;
+		pfmem_range->end = pfmem->end;
+		pfmem_range->rangeno = 1;
+		bus->noPFMemRanges = 1;
+		bus->rangePFMem = pfmem_range;
+	}
+	return 0;
+}
+
+/*
+ * find the 1st available bus number for PPB to set as its secondary bus
+ * Parameters: bus_number of the primary bus
+ * Returns: bus_number of the secondary bus or 0xff in case of failure
+ */
+static u8 find_sec_number (u8 primary_busno, u8 slotno)
+{
+	int min, max;
+	u8 busno;
+	struct bus_info *bus;
+
+	bus = ibmphp_find_same_bus_num (primary_busno);
+	if (!bus) {
+		err ("cannot get slot range of the bus from the BIOS\n");
+		return 0xff;
+	}
+	max = bus->slot_max;
+	min = bus->slot_min;
+	if ((slotno > max) || (slotno < min)) {
+		err ("got the wrong range\n");
+		return 0xff;
+	}
+	busno = (u8) (slotno - (u8) min);
+	busno += primary_busno + 0x01;
+	if (!ibmphp_find_res_bus (busno))
+		return busno;
+	return 0xff;
+}
+
diff -urN linux-2.5.6-pre1/drivers/hotplug/ibmphp_res.c linux-2.5.6-pre2/drivers/hotplug/ibmphp_res.c
--- linux-2.5.6-pre1/drivers/hotplug/ibmphp_res.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/drivers/hotplug/ibmphp_res.c	Thu Feb 28 13:34:21 2002
@@ -0,0 +1,2067 @@
+/*
+ * IBM Hot Plug Controller Driver
+ *
+ * Written By: Irene Zubarev, IBM Corporation
+ *
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001,2002 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to <gregkh@us.ibm.com>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include "ibmphp.h"
+
+static int flags = 0;		/* for testing */
+
+static void update_resources (struct bus_node *bus_cur, int type, int rangeno);
+static int once_over (void);
+static int remove_ranges (struct bus_node *, struct bus_node *);
+static int update_bridge_ranges (struct bus_node **);
+static int add_range (int type, struct range_node *, struct bus_node *);
+static void fix_resources (struct bus_node *);
+static inline struct bus_node *find_bus_wprev (u8, struct bus_node **, u8);
+
+static LIST_HEAD(gbuses);
+
+static struct bus_node * alloc_error_bus (struct ebda_pci_rsrc * curr)
+{
+	struct bus_node * newbus;
+
+	newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL);
+	if (!newbus) {
+		err ("out of system memory \n");
+		return NULL;
+	}
+
+	memset (newbus, 0, sizeof (struct bus_node));
+	newbus->busno = curr->bus_num;
+	list_add_tail (&newbus->bus_list, &gbuses);
+	return newbus;
+}
+
+static struct resource_node * alloc_resources (struct ebda_pci_rsrc * curr)
+{
+	struct resource_node *rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+	if (!rs) {
+		err ("out of system memory \n");
+		return NULL;
+	}
+	memset (rs, 0, sizeof (struct resource_node));
+	rs->busno = curr->bus_num;
+	rs->devfunc = curr->dev_fun;
+	rs->start = curr->start_addr;
+	rs->end = curr->end_addr;
+	rs->len = curr->end_addr - curr->start_addr + 1;
+	return rs;
+}
+
+static int alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus)
+{
+	struct bus_node * newbus;
+	struct range_node *newrange;
+	u8 num_ranges = 0;
+
+	if (first_bus) {
+		newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL);
+		if (!newbus) {
+			err ("out of system memory. \n");
+			return -ENOMEM;
+		}
+		memset (newbus, 0, sizeof (struct bus_node));
+		newbus->busno = curr->bus_num;
+	} else {
+		newbus = *new_bus;
+		switch (flag) {
+			case MEM:
+				num_ranges = newbus->noMemRanges;
+				break;
+			case PFMEM:
+				num_ranges = newbus->noPFMemRanges;
+				break;
+			case IO:
+				num_ranges = newbus->noIORanges;
+				break;
+		}
+	}
+
+	newrange = kmalloc (sizeof (struct range_node), GFP_KERNEL);
+	if (!newrange) {
+		if (first_bus)
+			kfree (newbus);
+		err ("out of system memory \n");
+		return -ENOMEM;
+	}
+	memset (newrange, 0, sizeof (struct range_node));
+	newrange->start = curr->start_addr;
+	newrange->end = curr->end_addr;
+		
+	if (first_bus || (!num_ranges))
+		newrange->rangeno = 1;
+	else {
+		/* need to insert our range */
+		add_range (flag, newrange, newbus);
+		debug ("%d resource Primary Bus inserted on bus %x [%x - %x]\n", flag, newbus->busno, newrange->start, newrange->end);
+	}
+
+	switch (flag) {
+		case MEM:
+			newbus->rangeMem = newrange;
+			if (first_bus)
+				newbus->noMemRanges = 1;
+			else {
+				debug ("First Memory Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+				++newbus->noMemRanges;
+				fix_resources (newbus);
+			}
+			break;
+		case IO:
+			newbus->rangeIO = newrange;
+			if (first_bus)
+				newbus->noIORanges = 1;
+			else {
+				debug ("First IO Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+				++newbus->noIORanges;
+				fix_resources (newbus);
+			}
+			break;
+		case PFMEM:
+			newbus->rangePFMem = newrange;
+			if (first_bus)
+				newbus->noPFMemRanges = 1;
+			else {	
+				debug ("1st PFMemory Primary on Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+				++newbus->noPFMemRanges;
+				fix_resources (newbus);
+			}
+
+			break;
+	}
+
+	*new_bus = newbus;
+	*new_range = newrange;
+	return 0;
+}
+
+
+/* Notes:
+ * 1. The ranges are ordered.  The buses are not ordered.  (First come)
+ *
+ * 2. If cannot allocate out of PFMem range, allocate from Mem ranges.  PFmemFromMem
+ * are not sorted. (no need since use mem node). To not change the entire code, we
+ * also add mem node whenever this case happens so as not to change
+ * ibmphp_check_mem_resource etc (and since it really is taking Mem resource)
+ */
+
+/*****************************************************************************
+ * This is the Resource Management initialization function.  It will go through
+ * the Resource list taken from EBDA and fill in this module's data structures
+ *
+ * THIS IS NOT TAKING INTO CONSIDERATION IO RESTRICTIONS OF PRIMARY BUSES, 
+ * SINCE WE'RE GOING TO ASSUME FOR NOW WE DON'T HAVE THOSE ON OUR BUSES FOR NOW
+ *
+ * Input: ptr to the head of the resource list from EBDA
+ * Output: 0, -1 or error codes
+ ***************************************************************************/
+int ibmphp_rsrc_init (void)
+{
+	struct ebda_pci_rsrc *curr;
+	struct range_node *newrange = NULL;
+	struct bus_node *newbus = NULL;
+	struct bus_node *bus_cur;
+	struct bus_node *bus_prev;
+	struct list_head *tmp;
+	struct resource_node *new_io = NULL;
+	struct resource_node *new_mem = NULL;
+	struct resource_node *new_pfmem = NULL;
+	int rc;
+	struct list_head *tmp_ebda;
+
+	list_for_each (tmp_ebda, &ibmphp_ebda_pci_rsrc_head) {
+		curr = list_entry (tmp_ebda, struct ebda_pci_rsrc, ebda_pci_rsrc_list);
+		if (!(curr->rsrc_type & PCIDEVMASK)) {
+			/* EBDA still lists non PCI devices, so ignore... */
+			debug ("this is not a PCI DEVICE in rsrc_init, please take care\n");
+			// continue;
+		}
+
+		/* this is a primary bus resource */
+		if (curr->rsrc_type & PRIMARYBUSMASK) {
+			/* memory */
+			if ((curr->rsrc_type & RESTYPE) == MMASK) {
+				/* no bus structure exists in place yet */
+				if (list_empty (&gbuses)) {
+					if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1)))
+						return rc;
+					list_add_tail (&newbus->bus_list, &gbuses);
+					debug ("gbuses = NULL, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+				} else {
+					bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1);
+					/* found our bus */
+					if (bus_cur) {
+						rc = alloc_bus_range (&bus_cur, &newrange, curr, MEM, 0);
+						if (rc)
+							return rc;
+					} else {
+						/* went through all the buses and didn't find ours, need to create a new bus node */
+						if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1)))
+							return rc;
+
+						list_add_tail (&newbus->bus_list, &gbuses);
+						debug ("New Bus, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+					}
+				}
+			} else if ((curr->rsrc_type & RESTYPE) == PFMASK) {
+				/* prefetchable memory */
+				if (list_empty (&gbuses)) {
+					/* no bus structure exists in place yet */
+					if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1)))
+						return rc;
+					list_add_tail (&newbus->bus_list, &gbuses);
+					debug ("gbuses = NULL, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+				} else {
+					bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1);
+					if (bus_cur) {
+						/* found our bus */
+						rc = alloc_bus_range (&bus_cur, &newrange, curr, PFMEM, 0);
+						if (rc)
+							return rc;
+					} else {
+						/* went through all the buses and didn't find ours, need to create a new bus node */
+						if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1)))
+							return rc;
+						list_add_tail (&newbus->bus_list, &gbuses);
+						debug ("1st Bus, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+					}
+				}
+			} else if ((curr->rsrc_type & RESTYPE) == IOMASK) {
+				/* IO */
+				if (list_empty (&gbuses)) {
+					/* no bus structure exists in place yet */
+					if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1)))
+						return rc;
+					list_add_tail (&newbus->bus_list, &gbuses);
+					debug ("gbuses = NULL, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+				} else {
+					bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1);
+					if (bus_cur) {
+						rc = alloc_bus_range (&bus_cur, &newrange, curr, IO, 0);
+						if (rc)
+							return rc;
+					} else {
+						/* went through all the buses and didn't find ours, need to create a new bus node */
+						if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1)))
+							return rc;
+						list_add_tail (&newbus->bus_list, &gbuses);
+						debug ("1st Bus, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
+					}
+				}
+
+			} else {
+				;	/* type is reserved  WHAT TO DO IN THIS CASE???
+					   NOTHING TO DO??? */
+			}
+		} else {
+			/* regular pci device resource */
+			if ((curr->rsrc_type & RESTYPE) == MMASK) {
+				/* Memory resource */
+				new_mem = alloc_resources (curr);
+				if (!new_mem)
+					return -ENOMEM;
+				new_mem->type = MEM;
+				/*
+				 * if it didn't find the bus, means PCI dev
+				 * came b4 the Primary Bus info, so need to
+				 * create a bus rangeno becomes a problem...
+				 * assign a -1 and then update once the range
+				 * actually appears...
+				 */
+				if (ibmphp_add_resource (new_mem) < 0) {
+					newbus = alloc_error_bus (curr);
+					if (!newbus)
+						return -ENOMEM;
+					newbus->firstMem = new_mem;
+					++newbus->needMemUpdate;
+					new_mem->rangeno = -1;
+				}
+				debug ("Memory resource for device %x, bus %x, [%x - %x]\n", new_mem->devfunc, new_mem->busno, new_mem->start, new_mem->end);
+
+			} else if ((curr->rsrc_type & RESTYPE) == PFMASK) {
+				/* PFMemory resource */
+				new_pfmem = alloc_resources (curr);
+				if (!new_pfmem)
+					return -ENOMEM;
+				new_pfmem->type = PFMEM;
+				new_pfmem->fromMem = FALSE;
+				if (ibmphp_add_resource (new_pfmem) < 0) {
+					newbus = alloc_error_bus (curr);
+					if (!newbus)
+						return -ENOMEM;
+					newbus->firstPFMem = new_pfmem;
+					++newbus->needPFMemUpdate;
+					new_pfmem->rangeno = -1;
+				}
+
+				debug ("PFMemory resource for device %x, bus %x, [%x - %x]\n", new_pfmem->devfunc, new_pfmem->busno, new_pfmem->start, new_pfmem->end);
+			} else if ((curr->rsrc_type & RESTYPE) == IOMASK) {
+				/* IO resource */
+				new_io = alloc_resources (curr);
+				if (!new_io)
+					return -ENOMEM;
+				new_io->type = IO;
+
+				/*
+				 * if it didn't find the bus, means PCI dev
+				 * came b4 the Primary Bus info, so need to
+				 * create a bus rangeno becomes a problem...
+				 * Can assign a -1 and then update once the
+				 * range actually appears...
+				 */
+				if (ibmphp_add_resource (new_io) < 0) {
+					newbus = alloc_error_bus (curr);
+					if (!newbus)
+						return -ENOMEM;
+					newbus->firstIO = new_io;
+					++newbus->needIOUpdate;
+					new_io->rangeno = -1;
+				}
+				debug ("IO resource for device %x, bus %x, [%x - %x]\n", new_io->devfunc, new_io->busno, new_io->start, new_io->end);
+			}
+		}
+	}
+
+	debug ("after the while loop in rsrc_init \n");
+
+	list_for_each (tmp, &gbuses) {
+		bus_cur = list_entry (tmp, struct bus_node, bus_list);
+		/* This is to get info about PPB resources, since EBDA doesn't put this info into the primary bus info */
+		rc = update_bridge_ranges (&bus_cur);
+		if (rc)
+			return rc;
+	}
+	debug ("b4 once_over in rsrc_init \n");
+	rc = once_over ();  /* This is to align ranges (so no -1) */
+	if (rc)
+		return rc;
+	debug ("after once_over in rsrc_init \n");
+	return 0;
+}
+
+/********************************************************************************
+ * This function adds a range into a sorted list of ranges per bus for a particular
+ * range type, it then calls another routine to update the range numbers on the
+ * pci devices' resources for the appropriate resource
+ *
+ * Input: type of the resource, range to add, current bus
+ * Output: 0 or -1, bus and range ptrs 
+ ********************************************************************************/
+static int add_range (int type, struct range_node *range, struct bus_node *bus_cur)
+{
+	struct range_node *range_cur = NULL;
+	struct range_node *range_prev;
+	int count = 0, i_init;
+	int noRanges = 0;
+
+	switch (type) {
+		case MEM:
+			range_cur = bus_cur->rangeMem;
+			noRanges = bus_cur->noMemRanges;
+			break;
+		case PFMEM:
+			range_cur = bus_cur->rangePFMem;
+			noRanges = bus_cur->noPFMemRanges;
+			break;
+		case IO:
+			range_cur = bus_cur->rangeIO;
+			noRanges = bus_cur->noIORanges;
+			break;
+	}
+
+	range_prev = NULL;
+	while (range_cur) {
+		if (range->start < range_cur->start)
+			break;
+		range_prev = range_cur;
+		range_cur = range_cur->next;
+		count = count + 1;
+	}
+	if (!count) {
+		/* our range will go at the beginning of the list */
+		switch (type) {
+			case MEM:
+				bus_cur->rangeMem = range;
+				break;
+			case PFMEM:
+				bus_cur->rangePFMem = range;
+				break;
+			case IO:
+				bus_cur->rangeIO = range;
+				break;
+		}
+		range->next = range_cur;
+		range->rangeno = 1;
+		i_init = 0;
+	} else if (!range_cur) {
+		/* our range will go at the end of the list */
+		range->next = NULL;
+		range_prev->next = range;
+		range->rangeno = range_prev->rangeno + 1;
+		return 0;
+	} else {
+		/* the range is in the middle */
+		range_prev->next = range;
+		range->next = range_cur;
+		range->rangeno = range_cur->rangeno;
+		i_init = range_prev->rangeno;
+	}
+
+	for (count = i_init; count < noRanges; ++count) {
+		++range_cur->rangeno;
+		range_cur = range_cur->next;
+	}
+
+	update_resources (bus_cur, type, i_init + 1);
+	return 0;
+}
+
+/*******************************************************************************
+ * This routine goes through the list of resources of type 'type' and updates
+ * the range numbers that they correspond to.  It was called from add_range fnc
+ *
+ * Input: bus, type of the resource, the rangeno starting from which to update
+ ******************************************************************************/
+static void update_resources (struct bus_node *bus_cur, int type, int rangeno)
+{
+	struct resource_node *res = NULL;
+	u8 eol = FALSE;	/* end of list indicator */
+
+	switch (type) {
+		case MEM:
+			if (bus_cur->firstMem) 
+				res = bus_cur->firstMem;
+			break;
+		case PFMEM:
+			if (bus_cur->firstPFMem)
+				res = bus_cur->firstPFMem;
+			break;
+		case IO:
+			if (bus_cur->firstIO)
+				res = bus_cur->firstIO;
+			break;
+	}
+
+	if (res) {
+		while (res) {
+			if (res->rangeno == rangeno)
+				break;
+			if (res->next)
+				res = res->next;
+			else if (res->nextRange)
+				res = res->nextRange;
+			else {
+				eol = TRUE;
+				break;
+			}
+		}
+
+		if (!eol) {
+			/* found the range */
+			while (res) {
+				++res->rangeno;
+				res = res->next;
+			}
+		}
+	}
+}
+
+static void fix_me (struct resource_node *res, struct bus_node *bus_cur, struct range_node *range)
+{
+	char * str = "";
+	switch (res->type) {
+		case IO:
+			str = "io";
+			break;
+		case MEM:
+			str = "mem";
+			break;
+		case PFMEM:
+			str = "pfmem";
+			break;
+	}
+
+	while (res) {
+		if (res->rangeno == -1) {
+			while (range) {
+				if ((res->start >= range->start) && (res->end <= range->end)) {
+					res->rangeno = range->rangeno;
+					debug ("%s->rangeno in fix_resources is %d\n", str, res->rangeno);
+					switch (res->type) {
+						case IO:
+							--bus_cur->needIOUpdate;
+							break;
+						case MEM:
+							--bus_cur->needMemUpdate;
+							break;
+						case PFMEM:
+							--bus_cur->needPFMemUpdate;
+							break;
+					}
+					break;
+				}
+				range = range->next;
+			}
+		}
+		if (res->next)
+			res = res->next;
+		else
+			res = res->nextRange;
+	}
+
+}
+
+/*****************************************************************************
+ * This routine reassigns the range numbers to the resources that had a -1
+ * This case can happen only if upon initialization, resources taken by pci dev
+ * appear in EBDA before the resources allocated for that bus, since we don't
+ * know the range, we assign -1, and this routine is called after a new range
+ * is assigned to see the resources with unknown range belong to the added range
+ *
+ * Input: current bus
+ * Output: none, list of resources for that bus are fixed if can be
+ *******************************************************************************/
+static void fix_resources (struct bus_node *bus_cur)
+{
+	struct range_node *range;
+	struct resource_node *res;
+
+	debug ("%s - bus_cur->busno = %d\n", __FUNCTION__, bus_cur->busno);
+
+	if (bus_cur->needIOUpdate) {
+		res = bus_cur->firstIO;
+		range = bus_cur->rangeIO;
+		fix_me (res, bus_cur, range);
+	}
+	if (bus_cur->needMemUpdate) {
+		res = bus_cur->firstMem;
+		range = bus_cur->rangeMem;
+		fix_me (res, bus_cur, range);
+	}
+	if (bus_cur->needPFMemUpdate) {
+		res = bus_cur->firstPFMem;
+		range = bus_cur->rangePFMem;
+		fix_me (res, bus_cur, range);
+	}
+}
+
+/*******************************************************************************
+ * This routine adds a resource to the list of resources to the appropriate bus 
+ * based on their resource type and sorted by their starting addresses.  It assigns
+ * the ptrs to next and nextRange if needed.
+ *
+ * Input: 3 diff. resources (nulled out if not needed)
+ * Output: ptrs assigned (to the node)
+ * 0 or -1
+ *******************************************************************************/
+int ibmphp_add_resource (struct resource_node *res)
+{
+	struct resource_node *res_cur;
+	struct resource_node *res_prev;
+	struct bus_node *bus_cur;
+	struct range_node *range_cur = NULL;
+	struct resource_node *res_start = NULL;
+
+	debug ("%s - enter\n", __FUNCTION__);
+	
+	bus_cur = find_bus_wprev (res->busno, NULL, 0);
+	
+	if (!bus_cur) {
+		/* didn't find a bus, smth's wrong!!! */
+		err ("no bus in the system, either pci_dev's wrong or allocation failed\n");
+		return -ENODEV;
+	}
+
+	/* Normal case */
+	switch (res->type) {
+		case IO:
+			range_cur = bus_cur->rangeIO;
+			res_start = bus_cur->firstIO;
+			break;
+		case MEM:
+			range_cur = bus_cur->rangeMem;
+			res_start = bus_cur->firstMem;
+			break;
+		case PFMEM:
+			range_cur = bus_cur->rangePFMem;
+			res_start = bus_cur->firstPFMem;
+			break;
+		default:
+			err ("cannot read the type of the resource to add... problem \n");
+			return -EINVAL;
+	}
+	while (range_cur) {
+		if ((res->start >= range_cur->start) && (res->end <= range_cur->end)) {
+			res->rangeno = range_cur->rangeno;
+			break;
+		}
+		range_cur = range_cur->next;
+	}
+
+	/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+	 * this is again the case of rangeno = -1
+	 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+	 */
+
+	if (!range_cur) {
+		switch (res->type) {
+			case IO:
+				++bus_cur->needIOUpdate;					
+				break;
+			case MEM:
+				++bus_cur->needMemUpdate;
+				break;
+			case PFMEM:
+				++bus_cur->needPFMemUpdate;
+				break;
+		}
+		res->rangeno = -1;
+	}
+	
+	debug ("The range is %d\n", res->rangeno);
+	if (!res_start) {
+		/* no first{IO,Mem,Pfmem} on the bus, 1st IO/Mem/Pfmem resource ever */
+		switch (res->type) {
+			case IO:
+				bus_cur->firstIO = res;					
+				break;
+			case MEM:
+				bus_cur->firstMem = res;
+				break;
+			case PFMEM:
+				bus_cur->firstPFMem = res;
+				break;
+		}	
+		res->next = NULL;
+		res->nextRange = NULL;
+	} else {
+		res_cur = res_start;
+		res_prev = NULL;
+
+		debug ("res_cur->rangeno is %d\n", res_cur->rangeno);
+
+		while (res_cur) {
+			if (res_cur->rangeno >= res->rangeno)
+				break;
+			res_prev = res_cur;
+			if (res_cur->next)
+				res_cur = res_cur->next;
+			else
+				res_cur = res_cur->nextRange;
+		}
+
+		if (!res_cur) {
+			/* at the end of the resource list */
+			debug ("i should be here, [%x - %x]\n", res->start, res->end);
+			res_prev->nextRange = res;
+			res->next = NULL;
+			res->nextRange = NULL;
+		} else if (res_cur->rangeno == res->rangeno) {
+			/* in the same range */
+			while (res_cur) {
+				if (res->start < res_cur->start)
+					break;
+				res_prev = res_cur;
+				res_cur = res_cur->next;
+			}
+			if (!res_cur) {
+				/* the last resource in this range */
+				res_prev->next = res;
+				res->next = NULL;
+				res->nextRange = res_prev->nextRange;
+				res_prev->nextRange = NULL;
+			} else if (res->start < res_cur->start) {
+				/* at the beginning or middle of the range */
+				if (!res_prev)	{
+					switch (res->type) {
+						case IO:
+							bus_cur->firstIO = res;
+							break;
+						case MEM:
+							bus_cur->firstMem = res;
+							break;
+						case PFMEM:
+							bus_cur->firstPFMem = res;
+							break;
+					}
+				} else if (res_prev->rangeno == res_cur->rangeno)
+					res_prev->next = res;
+				else
+					res_prev->nextRange = res;
+
+				res->next = res_cur;
+				res->nextRange = NULL;
+			}
+		} else {
+			/* this is the case where it is 1st occurence of the range */
+			if (!res_prev) {
+				/* at the beginning of the resource list */
+				res->next = NULL;
+				switch (res->type) {
+					case IO:
+						res->nextRange = bus_cur->firstIO;
+						bus_cur->firstIO = res;
+						break;
+					case MEM:
+						res->nextRange = bus_cur->firstMem;
+						bus_cur->firstMem = res;
+						break;
+					case PFMEM:
+						res->nextRange = bus_cur->firstPFMem;
+						bus_cur->firstPFMem = res;
+						break;
+				}
+			} else if (res_cur->rangeno > res->rangeno) {
+				/* in the middle of the resource list */
+				res_prev->nextRange = res;
+				res->next = NULL;
+				res->nextRange = res_cur;
+			}
+		}
+	}
+
+	debug ("%s - exit\n", __FUNCTION__);
+	return 0;
+}
+
+/****************************************************************************
+ * This routine will remove the resource from the list of resources
+ *
+ * Input: io, mem, and/or pfmem resource to be deleted
+ * Ouput: modified resource list
+ *        0 or error code
+ ****************************************************************************/
+int ibmphp_remove_resource (struct resource_node *res)
+{
+	struct bus_node *bus_cur;
+	struct resource_node *res_cur = NULL;
+	struct resource_node *res_prev;
+	struct resource_node *mem_cur;
+	char * type = "";
+
+	bus_cur = find_bus_wprev (res->busno, NULL, 0);
+
+	if (!bus_cur) {
+		err ("cannot find corresponding bus of the io resource to remove  "
+			"bailing out...\n");
+		return -ENODEV;
+	}
+
+	switch (res->type) {
+		case IO:
+			res_cur = bus_cur->firstIO;
+			type = "io";
+			break;
+		case MEM:
+			res_cur = bus_cur->firstMem;
+			type = "mem";
+			break;
+		case PFMEM:
+			res_cur = bus_cur->firstPFMem;
+			type = "pfmem";
+			break;
+		default:
+			err ("unknown type for resource to remove \n");
+			return -EINVAL;
+	}
+	res_prev = NULL;
+
+	while (res_cur) {
+		/* ???????????DO WE _NEED_ TO BE CHECKING FOR END AS WELL?????????? */
+		if ((res_cur->start == res->start) && (res_cur->end == res->end))
+			break;
+		res_prev = res_cur;
+		if (res_cur->next)
+			res_cur = res_cur->next;
+		else
+			res_cur = res_cur->nextRange;
+	}
+
+	if (!res_cur) {
+		if (res->type == PFMEM) {
+			/* 
+			 * case where pfmem might be in the PFMemFromMem list
+			 * so will also need to remove the corresponding mem
+			 * entry
+			 */
+			res_cur = bus_cur->firstPFMemFromMem;
+			res_prev = NULL;
+
+			while (res_cur) {
+				if ((res_cur->start == res->start) && (res_cur->end == res->end)) {
+					mem_cur = bus_cur->firstMem;
+					while (mem_cur) {
+						if ((mem_cur->start == res_cur->start)
+						    && (mem_cur->end == res_cur->end))
+							break;
+						if (mem_cur->next)
+							mem_cur = mem_cur->next;
+						else
+							mem_cur = mem_cur->nextRange;
+					}
+					if (!mem_cur) {
+						err ("cannot find corresponding mem node for pfmem...\n");
+						return -EINVAL;
+					}
+
+					ibmphp_remove_resource (mem_cur);
+					if (!res_prev)
+						bus_cur->firstPFMemFromMem = res_cur->next;
+					else
+						res_prev->next = res_cur->next;
+					kfree (res_cur);
+					return 0;
+				}
+				res_prev = res_cur;
+				if (res_cur->next)
+					res_cur = res_cur->next;
+				else
+					res_cur = res_cur->nextRange;
+			}
+			if (!res_cur) {
+				err ("cannot find pfmem to delete...\n");
+				return -EINVAL;
+			}
+		} else {
+			err ("the %s resource is not in the list to be deleted...\n", type);
+			return -EINVAL;
+		}
+	}
+	if (!res_prev) {
+		/* first device to be deleted */
+		if (res_cur->next) {
+			switch (res->type) {
+				case IO:
+					bus_cur->firstIO = res_cur->next;
+					break;
+				case MEM:
+					bus_cur->firstMem = res_cur->next;
+					break;
+				case PFMEM:
+					bus_cur->firstPFMem = res_cur->next;
+					break;
+			}
+		} else if (res_cur->nextRange) {
+			switch (res->type) {
+				case IO:
+					bus_cur->firstIO = res_cur->nextRange;
+					break;
+				case MEM:
+					bus_cur->firstMem = res_cur->nextRange;
+					break;
+				case PFMEM:
+					bus_cur->firstPFMem = res_cur->nextRange;
+					break;
+			}
+		} else {
+			switch (res->type) {
+				case IO:
+					bus_cur->firstIO = NULL;
+					break;
+				case MEM:
+					bus_cur->firstMem = NULL;
+					break;
+				case PFMEM:
+					bus_cur->firstPFMem = NULL;
+					break;
+			}
+		}
+		kfree (res_cur);
+		return 0;
+	} else {
+		if (res_cur->next) {
+			if (res_prev->rangeno == res_cur->rangeno)
+				res_prev->next = res_cur->next;
+			else
+				res_prev->nextRange = res_cur->next;
+		} else if (res_cur->nextRange) {
+			res_prev->next = NULL;
+			res_prev->nextRange = res_cur->nextRange;
+		} else {
+			res_prev->next = NULL;
+			res_prev->nextRange = NULL;
+		}
+		kfree (res_cur);
+		return 0;
+	}
+
+	return 0;
+}
+
+static struct range_node * find_range (struct bus_node *bus_cur, struct resource_node * res)
+{
+	struct range_node * range = NULL;
+
+	switch (res->type) {
+		case IO:
+			range = bus_cur->rangeIO;
+			break;
+		case MEM:
+			range = bus_cur->rangeMem;
+			break;
+		case PFMEM:
+			range = bus_cur->rangePFMem;
+			break;
+		default:
+			err ("cannot read resource type in find_range \n");
+	}
+
+	while (range) {
+		if (res->rangeno == range->rangeno)
+			break;
+		range = range->next;
+	}
+	return range;
+}
+
+/*****************************************************************************
+ * This routine will check to make sure the io/mem/pfmem->len that the device asked for 
+ * can fit w/i our list of available IO/MEM/PFMEM resources.  If cannot, returns -EINVAL,
+ * otherwise, returns 0
+ *
+ * Input: resource
+ * Ouput: the correct start and end address are inputted into the resource node,
+ *        0 or -EINVAL
+ *****************************************************************************/
+int ibmphp_check_resource (struct resource_node *res, u8 bridge)
+{
+	struct bus_node *bus_cur;
+	struct range_node *range = NULL;
+	struct resource_node *res_prev;
+	struct resource_node *res_cur = NULL;
+	u32 len_cur = 0, start_cur = 0, len_tmp = 0;
+	int noranges = 0;
+	u32 tmp_start;		/* this is to make sure start address is divisible by the length needed */
+	u32 tmp_divide;
+	u8 flag = FALSE;
+
+	if (!res)
+		return -EINVAL;
+
+	if (bridge) {
+		/* The rules for bridges are different, 4K divisible for IO, 1M for (pf)mem*/
+		if (res->type == IO)
+			tmp_divide = IOBRIDGE;
+		else
+			tmp_divide = MEMBRIDGE;
+	} else
+		tmp_divide = res->len;
+
+	bus_cur = find_bus_wprev (res->busno, NULL, 0);
+
+	if (!bus_cur) {
+		/* didn't find a bus, smth's wrong!!! */
+		err ("no bus in the system, either pci_dev's wrong or allocation failed \n");
+		return -EINVAL;
+	}
+
+	debug ("%s - enter\n", __FUNCTION__);
+	debug ("bus_cur->busno is %d\n", bus_cur->busno);
+
+	/* This is a quick fix to not mess up with the code very much.  i.e.,
+	 * 2000-2fff, len = 1000, but when we compare, we need it to be fff */
+	res->len -= 1;
+
+	switch (res->type) {
+		case IO:
+			res_cur = bus_cur->firstIO;
+			noranges = bus_cur->noIORanges;
+			break;
+		case MEM:
+			res_cur = bus_cur->firstMem;
+			noranges = bus_cur->noMemRanges;
+			break;
+		case PFMEM:
+			res_cur = bus_cur->firstPFMem;
+			noranges = bus_cur->noPFMemRanges;
+			break;
+		default:
+			err ("wrong type of resource to check \n");
+			return -EINVAL;
+	}
+	res_prev = NULL;
+
+	while (res_cur) {
+		range = find_range (bus_cur, res_cur);
+		debug ("%s - rangeno = %d\n", __FUNCTION__, res_cur->rangeno);
+
+		if (!range) {
+			err ("no range for the device exists... bailing out...\n");
+			return -EINVAL;
+		}
+
+		/* found our range */
+		if (!res_prev) {
+			/* first time in the loop */
+			if ((res_cur->start != range->start) && ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) {
+				debug ("len_tmp = %x\n", len_tmp);
+
+				if ((len_tmp < len_cur) || (len_cur == 0)) {
+
+					if ((range->start % tmp_divide) == 0) {
+						/* just perfect, starting address is divisible by length */
+						flag = TRUE;
+						len_cur = len_tmp;
+						start_cur = range->start;
+					} else {
+						/* Needs adjusting */
+						tmp_start = range->start;
+						flag = FALSE;
+
+						while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) {
+							if ((tmp_start % tmp_divide) == 0) {
+								flag = TRUE;
+								len_cur = len_tmp;
+								start_cur = tmp_start;
+								break;
+							}
+							tmp_start += tmp_divide - tmp_start % tmp_divide;
+							if (tmp_start >= res_cur->start - 1)
+								break;
+						}
+					}
+			
+					if (flag && len_cur == res->len) {
+						debug ("but we are not here, right?\n");
+						res->start = start_cur;
+						res->len += 1; /* To restore the balance */
+						res->end = res->start + res->len - 1;
+						return 0;
+					}
+				}
+			}
+		}
+		if (!res_cur->next) {
+			/* last device on the range */
+			if ((range->end != res_cur->end) && ((len_tmp = range->end - (res_cur->end + 1)) >= res->len)) {
+				debug ("len_tmp = %x\n", len_tmp);
+				if ((len_tmp < len_cur) || (len_cur == 0)) {
+
+					if (((res_cur->end + 1) % tmp_divide) == 0) {
+						/* just perfect, starting address is divisible by length */
+						flag = TRUE;
+						len_cur = len_tmp;
+						start_cur = res_cur->end + 1;
+					} else {
+						/* Needs adjusting */
+						tmp_start = res_cur->end + 1;
+						flag = FALSE;
+
+						while ((len_tmp = range->end - tmp_start) >= res->len) {
+							if ((tmp_start % tmp_divide) == 0) {
+								flag = TRUE;
+								len_cur = len_tmp;
+								start_cur = tmp_start;
+								break;
+							}
+							tmp_start += tmp_divide - tmp_start % tmp_divide;
+							if (tmp_start >= range->end)
+								break;
+						}
+					}
+					if (flag && len_cur == res->len) {
+						res->start = start_cur;
+						res->len += 1; /* To restore the balance */
+						res->end = res->start + res->len - 1;
+						return 0;
+					}
+				}
+			}
+		}
+
+		if (res_prev) {
+			if (res_prev->rangeno != res_cur->rangeno) {
+				/* 1st device on this range */
+				if ((res_cur->start != range->start) && 
+					((len_tmp = res_cur->start - 1 - range->start) >= res->len)) {
+					if ((len_tmp < len_cur) || (len_cur == 0)) {
+						if ((range->start % tmp_divide) == 0) {	
+							/* just perfect, starting address is divisible by length */
+							flag = TRUE;
+							len_cur = len_tmp;
+							start_cur = range->start;
+						} else {
+							/* Needs adjusting */
+							tmp_start = range->start;
+							flag = FALSE;
+
+							while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) {
+								if ((tmp_start % tmp_divide) == 0) {
+									flag = TRUE;
+									len_cur = len_tmp;
+									start_cur = tmp_start;
+									break;
+								}
+								tmp_start += tmp_divide - tmp_start % tmp_divide;
+								if (tmp_start >= res_cur->start - 1)
+									break;
+							}
+						}
+
+						if (flag && len_cur == res->len) {
+							res->start = start_cur;
+							res->len += 1; /* To restore the balance */
+							res->end = res->start + res->len - 1;
+							return 0;
+						}
+					}
+				}
+			} else {
+				/* in the same range */
+				if ((len_tmp = res_cur->start - 1 - res_prev->end - 1) >= res->len) {
+					if ((len_tmp < len_cur) || (len_cur == 0)) {
+						if (((res_prev->end + 1) % tmp_divide) == 0) {
+							/* just perfect, starting address's divisible by length */
+							flag = TRUE;
+							len_cur = len_tmp;
+							start_cur = res_prev->end + 1;
+						} else {
+							/* Needs adjusting */
+							tmp_start = res_prev->end + 1;
+							flag = FALSE;
+
+							while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) {
+								if ((tmp_start % tmp_divide) == 0) {
+									flag = TRUE;
+									len_cur = len_tmp;
+									start_cur = tmp_start;
+									break;
+								}
+								tmp_start += tmp_divide - tmp_start % tmp_divide;
+								if (tmp_start >= res_cur->start - 1)
+									break;
+							}
+						}
+
+						if (flag && len_cur == res->len) {
+							res->start = start_cur;
+							res->len += 1; /* To restore the balance */
+							res->end = res->start + res->len - 1;
+							return 0;
+						}
+					}
+				}
+			}
+		}
+		/* end if (res_prev) */
+		res_prev = res_cur;
+		if (res_cur->next)
+			res_cur = res_cur->next;
+		else
+			res_cur = res_cur->nextRange;
+	}	/* end of while */
+
+
+	if (!res_prev) {
+		/* 1st device ever */
+		/* need to find appropriate range */
+		switch (res->type) {
+			case IO:
+				range = bus_cur->rangeIO;
+				break;
+			case MEM:
+				range = bus_cur->rangeMem;
+				break;
+			case PFMEM:
+				range = bus_cur->rangePFMem;
+				break;
+		}
+		while (range) {
+			if ((len_tmp = range->end - range->start) >= res->len) {
+				if ((len_tmp < len_cur) || (len_cur == 0)) {
+					if ((range->start % tmp_divide) == 0) {
+						/* just perfect, starting address's divisible by length */
+						flag = TRUE;
+						len_cur = len_tmp;
+						start_cur = range->start;
+					} else {
+						/* Needs adjusting */
+						tmp_start = range->start;
+						flag = FALSE;
+
+						while ((len_tmp = range->end - tmp_start) >= res->len) {
+							if ((tmp_start % tmp_divide) == 0) {
+								flag = TRUE;
+								len_cur = len_tmp;
+								start_cur = tmp_start;
+								break;
+							}
+							tmp_start += tmp_divide - tmp_start % tmp_divide;
+							if (tmp_start >= range->end)
+								break;
+						}
+					}
+
+					if (flag && len_cur == res->len) {
+						res->start = start_cur;
+						res->len += 1; /* To restore the balance */
+						res->end = res->start + res->len - 1;
+						return 0;
+					}
+				}
+			}
+			range = range->next;
+		}		/* end of while */
+
+		if ((!range) && (len_cur == 0)) {
+			/* have gone through the list of devices and ranges and haven't found n.e.thing */
+			err ("no appropriate range.. bailing out...\n");
+			return -EINVAL;
+		} else if (len_cur) {
+			res->start = start_cur;
+			res->len += 1; /* To restore the balance */
+			res->end = res->start + res->len - 1;
+			return 0;
+		}
+	}
+
+	if (!res_cur) {
+		debug ("prev->rangeno = %d, noranges = %d\n", res_prev->rangeno, noranges);
+		if (res_prev->rangeno < noranges) {
+			/* if there're more ranges out there to check */
+			switch (res->type) {
+				case IO:
+					range = bus_cur->rangeIO;
+					break;
+				case MEM:
+					range = bus_cur->rangeMem;
+					break;
+				case PFMEM:
+					range = bus_cur->rangePFMem;
+					break;
+			}
+			while (range) {
+				if ((len_tmp = range->end - range->start) >= res->len) {
+					if ((len_tmp < len_cur) || (len_cur == 0)) {
+						if ((range->start % tmp_divide) == 0) {
+							/* just perfect, starting address's divisible by length */
+							flag = TRUE;
+							len_cur = len_tmp;
+							start_cur = range->start;
+						} else {
+							/* Needs adjusting */
+							tmp_start = range->start;
+							flag = FALSE;
+
+							while ((len_tmp = range->end - tmp_start) >= res->len) {
+								if ((tmp_start % tmp_divide) == 0) {
+									flag = TRUE;
+									len_cur = len_tmp;
+									start_cur = tmp_start;
+									break;
+								}
+								tmp_start += tmp_divide - tmp_start % tmp_divide;
+								if (tmp_start >= range->end)
+									break;
+							}
+						}
+
+						if (flag && len_cur == res->len) {
+							res->start = start_cur;
+							res->len += 1; /* To restore the balance */
+							res->end = res->start + res->len - 1;
+							return 0;
+						}
+					}
+				}
+				range = range->next;
+			}	/* end of while */
+
+			if ((!range) && (len_cur == 0)) {
+				/* have gone through the list of devices and ranges and haven't found n.e.thing */
+				err ("no appropriate range.. bailing out...\n");
+				return -EINVAL;
+			} else if (len_cur) {
+				res->start = start_cur;
+				res->len += 1; /* To restore the balance */
+				res->end = res->start + res->len - 1;
+				return 0;
+			}
+		} else {
+			/* no more ranges to check on */
+			if (len_cur) {
+				res->start = start_cur;
+				res->len += 1; /* To restore the balance */
+				res->end = res->start + res->len - 1;
+				return 0;
+			} else {
+				/* have gone through the list of devices and haven't found n.e.thing */
+				err ("no appropriate range.. bailing out...\n");
+				return -EINVAL;
+			}
+		}
+	}	/* end if(!res_cur) */
+	return -EINVAL;
+}
+
+/********************************************************************************
+ * This routine is called from remove_card if the card contained PPB.
+ * It will remove all the resources on the bus as well as the bus itself
+ * Input: Bus
+ * Ouput: 0, -ENODEV
+ ********************************************************************************/
+int ibmphp_remove_bus (struct bus_node *bus, u8 parent_busno)
+{
+	struct resource_node *res_cur;
+	struct resource_node *res_tmp;
+	struct bus_node *prev_bus;
+	int rc;
+
+	prev_bus = find_bus_wprev (parent_busno, NULL, 0);	
+
+	if (!prev_bus) {
+		err ("something terribly wrong. Cannot find parent bus to the one to remove\n");
+		return -ENODEV;
+	}
+
+	debug ("In ibmphp_remove_bus... prev_bus->busno is %x\n", prev_bus->busno);
+
+	rc = remove_ranges (bus, prev_bus);
+	if (rc)
+		return rc;
+
+	if (bus->firstIO) {
+		res_cur = bus->firstIO;
+		while (res_cur) {
+			res_tmp = res_cur;
+			if (res_cur->next)
+				res_cur = res_cur->next;
+			else
+				res_cur = res_cur->nextRange;
+			kfree (res_tmp);
+			res_tmp = NULL;
+		}
+		bus->firstIO = NULL;
+	}
+	if (bus->firstMem) {
+		res_cur = bus->firstMem;
+		while (res_cur) {
+			res_tmp = res_cur;
+			if (res_cur->next)
+				res_cur = res_cur->next;
+			else
+				res_cur = res_cur->nextRange;
+			kfree (res_tmp);
+			res_tmp = NULL;
+		}
+		bus->firstMem = NULL;
+	}
+	if (bus->firstPFMem) {
+		res_cur = bus->firstPFMem;
+		while (res_cur) {
+			res_tmp = res_cur;
+			if (res_cur->next)
+				res_cur = res_cur->next;
+			else
+				res_cur = res_cur->nextRange;
+			kfree (res_tmp);
+			res_tmp = NULL;
+		}
+		bus->firstPFMem = NULL;
+	}
+
+	if (bus->firstPFMemFromMem) {
+		res_cur = bus->firstPFMemFromMem;
+		while (res_cur) {
+			res_tmp = res_cur;
+			res_cur = res_cur->next;
+
+			kfree (res_tmp);
+			res_tmp = NULL;
+		}
+		bus->firstPFMemFromMem = NULL;
+	}
+
+	list_del (&bus->bus_list);
+	kfree (bus);
+	return 0;
+}
+
+/******************************************************************************
+ * This routine deletes the ranges from a given bus, and the entries from the 
+ * parent's bus in the resources
+ * Input: current bus, previous bus
+ * Output: 0, -EINVAL
+ ******************************************************************************/
+static int remove_ranges (struct bus_node *bus_cur, struct bus_node *bus_prev)
+{
+	struct range_node *range_cur;
+	struct range_node *range_tmp;
+	int i;
+	struct resource_node *res = NULL;
+
+	if (bus_cur->noIORanges) {
+		range_cur = bus_cur->rangeIO;
+		for (i = 0; i < bus_cur->noIORanges; i++) {
+			if (ibmphp_find_resource (bus_prev, range_cur->start, &res, IO) < 0)
+				return -EINVAL;
+			ibmphp_remove_resource (res);
+
+			range_tmp = range_cur;
+			range_cur = range_cur->next;
+			kfree (range_tmp);
+			range_tmp = NULL;
+		}
+		bus_cur->rangeIO = NULL;
+	}
+	if (bus_cur->noMemRanges) {
+		range_cur = bus_cur->rangeMem;
+		for (i = 0; i < bus_cur->noMemRanges; i++) {
+			if (ibmphp_find_resource (bus_prev, range_cur->start, &res, MEM) < 0) 
+				return -EINVAL;
+
+			ibmphp_remove_resource (res);
+			range_tmp = range_cur;
+			range_cur = range_cur->next;
+			kfree (range_tmp);
+			range_tmp = NULL;
+		}
+		bus_cur->rangeMem = NULL;
+	}
+	if (bus_cur->noPFMemRanges) {
+		range_cur = bus_cur->rangePFMem;
+		for (i = 0; i < bus_cur->noPFMemRanges; i++) {
+			if (ibmphp_find_resource (bus_prev, range_cur->start, &res, PFMEM) < 0) 
+				return -EINVAL;
+
+			ibmphp_remove_resource (res);
+			range_tmp = range_cur;
+			range_cur = range_cur->next;
+			kfree (range_tmp);
+			range_tmp = NULL;
+		}
+		bus_cur->rangePFMem = NULL;
+	}
+	return 0;
+}
+
+/*
+ * find the resource node in the bus 
+ * Input: Resource needed, start address of the resource, type or resource
+ */
+int ibmphp_find_resource (struct bus_node *bus, u32 start_address, struct resource_node **res, int flag)
+{
+	struct resource_node *res_cur = NULL;
+	char * type = "";
+
+	switch (flag) {
+		case IO:
+			res_cur = bus->firstIO;
+			type = "io";
+			break;
+		case MEM:
+			res_cur = bus->firstMem;
+			type = "mem";
+			break;
+		case PFMEM:
+			res_cur = bus->firstPFMem;
+			type = "pfmem";
+			break;
+		default:
+			err ("wrong type of flag \n");
+			return -EINVAL;
+	}
+	
+	while (res_cur) {
+		if (res_cur->start == start_address) {
+			*res = res_cur;
+			break;
+		}
+		if (res_cur->next)
+			res_cur = res_cur->next;
+		else
+			res_cur = res_cur->nextRange;
+	}
+
+	if (!res_cur) {
+		if (flag == PFMEM) {
+			res_cur = bus->firstPFMemFromMem;
+			while (res_cur) {
+				if (res_cur->start == start_address) {
+					*res = res_cur;
+					break;
+				}
+				res_cur = res_cur->next;
+			}
+			if (!res_cur) {
+				err ("SOS...cannot find %s resource in the bus. \n", type);
+				return -EINVAL;
+			}
+		} else {
+			err ("SOS... cannot find %s resource in the bus. \n", type);
+			return -EINVAL;
+		}
+	}
+
+	if (*res)
+		debug ("*res->start = %x \n", (*res)->start);
+
+	return 0;
+}
+
+/***********************************************************************
+ * This routine will free the resource structures used by the
+ * system.  It is called from cleanup routine for the module
+ * Parameters: none
+ * Returns: none
+ ***********************************************************************/
+void ibmphp_free_resources (void)
+{
+	struct bus_node *bus_cur = NULL;
+	struct bus_node *bus_tmp;
+	struct range_node *range_cur;
+	struct range_node *range_tmp;
+	struct resource_node *res_cur;
+	struct resource_node *res_tmp;
+	struct list_head *tmp;
+	struct list_head *next;
+	int i = 0;
+	flags = 1;
+
+	list_for_each_safe (tmp, next, &gbuses) {
+		bus_cur = list_entry (tmp, struct bus_node, bus_list);
+		if (bus_cur->noIORanges) {
+			range_cur = bus_cur->rangeIO;
+			for (i = 0; i < bus_cur->noIORanges; i++) {
+				if (!range_cur)
+					break;
+				range_tmp = range_cur;
+				range_cur = range_cur->next;
+				kfree (range_tmp);
+				range_tmp = NULL;
+			}
+		}
+		if (bus_cur->noMemRanges) {
+			range_cur = bus_cur->rangeMem;
+			for (i = 0; i < bus_cur->noMemRanges; i++) {
+				if (!range_cur)
+					break;
+				range_tmp = range_cur;
+				range_cur = range_cur->next;
+				kfree (range_tmp);
+				range_tmp = NULL;
+			}
+		}
+		if (bus_cur->noPFMemRanges) {
+			range_cur = bus_cur->rangePFMem;
+			for (i = 0; i < bus_cur->noPFMemRanges; i++) {
+				if (!range_cur)
+					break;
+				range_tmp = range_cur;
+				range_cur = range_cur->next;
+				kfree (range_tmp);
+				range_tmp = NULL;
+			}
+		}
+
+		if (bus_cur->firstIO) {
+			res_cur = bus_cur->firstIO;
+			while (res_cur) {
+				res_tmp = res_cur;
+				if (res_cur->next)
+					res_cur = res_cur->next;
+				else
+					res_cur = res_cur->nextRange;
+				kfree (res_tmp);
+				res_tmp = NULL;
+			}
+			bus_cur->firstIO = NULL;
+		}
+		if (bus_cur->firstMem) {
+			res_cur = bus_cur->firstMem;
+			while (res_cur) {
+				res_tmp = res_cur;
+				if (res_cur->next)
+					res_cur = res_cur->next;
+				else
+					res_cur = res_cur->nextRange;
+				kfree (res_tmp);
+				res_tmp = NULL;
+			}
+			bus_cur->firstMem = NULL;
+		}
+		if (bus_cur->firstPFMem) {
+			res_cur = bus_cur->firstPFMem;
+			while (res_cur) {
+				res_tmp = res_cur;
+				if (res_cur->next)
+					res_cur = res_cur->next;
+				else
+					res_cur = res_cur->nextRange;
+				kfree (res_tmp);
+				res_tmp = NULL;
+			}
+			bus_cur->firstPFMem = NULL;
+		}
+
+		if (bus_cur->firstPFMemFromMem) {
+			res_cur = bus_cur->firstPFMemFromMem;
+			while (res_cur) {
+				res_tmp = res_cur;
+				res_cur = res_cur->next;
+
+				kfree (res_tmp);
+				res_tmp = NULL;
+			}
+			bus_cur->firstPFMemFromMem = NULL;
+		}
+
+		bus_tmp = bus_cur;
+		list_del (&bus_cur->bus_list);
+		kfree (bus_tmp);
+		bus_tmp = NULL;
+	}
+}
+
+/*********************************************************************************
+ * This function will go over the PFmem resources to check if the EBDA allocated
+ * pfmem out of memory buckets of the bus.  If so, it will change the range numbers
+ * and a flag to indicate that this resource is out of memory. It will also move the
+ * Pfmem out of the pfmem resource list to the PFMemFromMem list, and will create
+ * a new Mem node
+ * This routine is called right after initialization
+ *******************************************************************************/
+static int once_over (void)
+{
+	struct resource_node *pfmem_cur;
+	struct resource_node *pfmem_prev;
+	struct resource_node *mem;
+	struct bus_node *bus_cur;
+	struct list_head *tmp;
+
+	list_for_each (tmp, &gbuses) {
+		bus_cur = list_entry (tmp, struct bus_node, bus_list);
+		if ((!bus_cur->rangePFMem) && (bus_cur->firstPFMem)) {
+			for (pfmem_cur = bus_cur->firstPFMem, pfmem_prev = NULL; pfmem_cur; pfmem_prev = pfmem_cur, pfmem_cur = pfmem_cur->next) {
+				pfmem_cur->fromMem = TRUE;
+				if (pfmem_prev)
+					pfmem_prev->next = pfmem_cur->next;
+				else
+					bus_cur->firstPFMem = pfmem_cur->next;
+
+				if (!bus_cur->firstPFMemFromMem)
+					pfmem_cur->next = NULL;
+				else
+					/* we don't need to sort PFMemFromMem since we're using mem node for
+					   all the real work anyways, so just insert at the beginning of the
+					   list
+					 */
+					pfmem_cur->next = bus_cur->firstPFMemFromMem;
+
+				bus_cur->firstPFMemFromMem = pfmem_cur;
+
+				mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);		
+				if (!mem) {
+					err ("out of system memory \n");
+					return -ENOMEM;
+				}
+				memset (mem, 0, sizeof (struct resource_node));
+				mem->type = MEM;
+				mem->busno = pfmem_cur->busno;
+				mem->devfunc = pfmem_cur->devfunc;
+				mem->start = pfmem_cur->start;
+				mem->end = pfmem_cur->end;
+				mem->len = pfmem_cur->len;
+				if (ibmphp_add_resource (mem) < 0)
+					err ("Trouble...trouble... EBDA allocated pfmem from mem, but system doesn't display it has this space... unless not PCI device...\n");
+				pfmem_cur->rangeno = mem->rangeno;
+			}	/* end for pfmem */
+		}	/* end if */
+	}	/* end list_for_each bus */
+	return 0; 
+}
+
+int ibmphp_add_pfmem_from_mem (struct resource_node *pfmem)
+{
+	struct bus_node *bus_cur = find_bus_wprev (pfmem->busno, NULL, 0);
+
+	if (!bus_cur) {
+		err ("cannot find bus of pfmem to add...\n");
+		return -ENODEV;
+	}
+
+	if (bus_cur->firstPFMemFromMem)
+		pfmem->next = bus_cur->firstPFMemFromMem;
+	else
+		pfmem->next = NULL;
+
+	bus_cur->firstPFMemFromMem = pfmem;
+
+	return 0;
+}
+
+/* This routine just goes through the buses to see if the bus already exists.
+ * It is called from ibmphp_find_sec_number, to find out a secondary bus number for
+ * bridged cards
+ * Parameters: bus_number
+ * Returns: Bus pointer or NULL
+ */
+struct bus_node *ibmphp_find_res_bus (u8 bus_number)
+{
+	return find_bus_wprev (bus_number, NULL, 0);
+}
+
+static inline struct bus_node *find_bus_wprev (u8 bus_number, struct bus_node **prev, u8 flag)
+{
+	struct bus_node *bus_cur;
+	struct list_head *tmp;
+	struct list_head *tmp_prev;
+
+	list_for_each (tmp, &gbuses) {
+		tmp_prev = tmp->prev;
+		bus_cur = list_entry (tmp, struct bus_node, bus_list);
+		if (flag) 
+			*prev = list_entry (tmp_prev, struct bus_node, bus_list);
+		if (bus_cur->busno == bus_number) 
+			return bus_cur;
+	}
+
+	return NULL;
+}
+
+void ibmphp_print_test (void)
+{
+	int i = 0;
+	struct bus_node *bus_cur = NULL;
+	struct range_node *range;
+	struct resource_node *res;
+	struct list_head *tmp;
+
+	if ((!list_empty(&gbuses)) && flags) {
+		err ("The GBUSES is not NULL?!?!?!?!?\n");
+		return;
+	}
+
+	list_for_each (tmp, &gbuses) {
+		bus_cur = list_entry (tmp, struct bus_node, bus_list);
+		debug ("This is bus # %d.  There are \n", bus_cur->busno);
+		debug ("IORanges = %d\t", bus_cur->noIORanges);
+		debug ("MemRanges = %d\t", bus_cur->noMemRanges);
+		debug ("PFMemRanges = %d\n", bus_cur->noPFMemRanges);
+		debug ("The IO Ranges are as follows:\n");
+		if (bus_cur->rangeIO) {
+			range = bus_cur->rangeIO;
+			for (i = 0; i < bus_cur->noIORanges; i++) {
+				debug ("rangeno is %d\n", range->rangeno);
+				debug ("[%x - %x]\n", range->start, range->end);
+				range = range->next;
+			}
+		}
+
+		debug ("The Mem Ranges are as follows:\n");
+		if (bus_cur->rangeMem) {
+			range = bus_cur->rangeMem;
+			for (i = 0; i < bus_cur->noMemRanges; i++) {
+				debug ("rangeno is %d\n", range->rangeno);
+				debug ("[%x - %x]\n", range->start, range->end);
+				range = range->next;
+			}
+		}
+
+		debug ("The PFMem Ranges are as follows:\n");
+
+		if (bus_cur->rangePFMem) {
+			range = bus_cur->rangePFMem;
+			for (i = 0; i < bus_cur->noPFMemRanges; i++) {
+				debug ("rangeno is %d\n", range->rangeno);
+				debug ("[%x - %x]\n", range->start, range->end);
+				range = range->next;
+			}
+		}
+
+		debug ("The resources on this bus are as follows\n");
+
+		debug ("IO...\n");
+		if (bus_cur->firstIO) {
+			res = bus_cur->firstIO;
+			while (res) {
+				debug ("The range # is %d\n", res->rangeno);
+				debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				if (res->next)
+					res = res->next;
+				else if (res->nextRange)
+					res = res->nextRange;
+				else
+					break;
+			}
+		}
+		debug ("Mem...\n");
+		if (bus_cur->firstMem) {
+			res = bus_cur->firstMem;
+			while (res) {
+				debug ("The range # is %d\n", res->rangeno);
+				debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				if (res->next)
+					res = res->next;
+				else if (res->nextRange)
+					res = res->nextRange;
+				else
+					break;
+			}
+		}
+		debug ("PFMem...\n");
+		if (bus_cur->firstPFMem) {
+			res = bus_cur->firstPFMem;
+			while (res) {
+				debug ("The range # is %d\n", res->rangeno);
+				debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				if (res->next)
+					res = res->next;
+				else if (res->nextRange)
+					res = res->nextRange;
+				else
+					break;
+			}
+		}
+
+		debug ("PFMemFromMem...\n");
+		if (bus_cur->firstPFMemFromMem) {
+			res = bus_cur->firstPFMemFromMem;
+			while (res) {
+				debug ("The range # is %d\n", res->rangeno);
+				debug ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
+				debug ("[%x - %x], len=%x\n", res->start, res->end, res->len);
+				res = res->next;
+			}
+		}
+	}
+}
+
+/* This routine will read the windows for any PPB we have and update the
+ * range info for the secondary bus, and will also input this info into
+ * primary bus, since BIOS doesn't. This is for PPB that are in the system
+ * on bootup
+ * Input: primary busno
+ * Returns: none
+ * Note: this function doesn't take into account IO restrictions etc,
+ *	 so will only work for bridges with no video/ISA devices behind them It
+ *	 also will not work for onboard PPB's that can have more than 1 *bus
+ *	 behind them All these are TO DO.
+ *	 Also need to add more error checkings... (from fnc returns etc)
+ */
+static int update_bridge_ranges (struct bus_node **bus)
+{
+	u8 sec_busno, device, function, busno, hdr_type, start_io_address, end_io_address;
+	u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address;
+	u32 start_address, end_address, upper_start, upper_end;
+	struct bus_node *bus_sec;
+	struct bus_node *bus_cur;
+	struct resource_node *io;
+	struct resource_node *mem;
+	struct resource_node *pfmem;
+	struct range_node *range;
+	bus_cur = *bus;
+	busno = bus_cur->busno;
+
+	debug ("inside update_bridge_ranges \n");
+	debug ("bus_cur->busno = %x\n", bus_cur->busno);
+
+	for (device = 0; device < 32; device++) {
+		for (function = 0x00; function < 0x08; function++) {
+			pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_VENDOR_ID, &vendor_id);
+
+			if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
+				/* found correct device!!! */
+				pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_HEADER_TYPE, &hdr_type);
+
+				switch (hdr_type) {
+					case PCI_HEADER_TYPE_NORMAL:
+						function = 0x8;
+						break;
+					case PCI_HEADER_TYPE_MULTIDEVICE:
+						break;
+					case PCI_HEADER_TYPE_BRIDGE:
+						function = 0x8;
+					case PCI_HEADER_TYPE_MULTIBRIDGE:
+						/* We assume here that only 1 bus behind the bridge 
+						   TO DO: add functionality for several:
+						   temp = secondary;
+						   while (temp < subordinate) {
+						   ...
+						   temp++;
+						   }
+						 */
+						pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_SECONDARY_BUS, &sec_busno);
+						bus_sec = find_bus_wprev (sec_busno, NULL, 0); 
+						pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_BASE, &start_io_address);
+						pci_read_config_byte_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_LIMIT, &end_io_address);
+						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_BASE_UPPER16, &upper_io_start);
+						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_IO_LIMIT_UPPER16, &upper_io_end);
+						start_address = (start_io_address & PCI_IO_RANGE_MASK) << 8;
+						start_address |= (upper_io_start << 16);
+						end_address = (end_io_address & PCI_IO_RANGE_MASK) << 8;
+						end_address |= (upper_io_end << 16);
+
+						if ((start_address) && (start_address <= end_address)) {
+
+							range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
+
+							if (!range) {
+								err ("out of system memory \n");
+								return -ENOMEM;
+							}
+							memset (range, 0, sizeof (struct range_node));
+							range->start = start_address;
+							range->end = end_address + 0xfff;
+
+							if (bus_sec->noIORanges > 0) 
+								add_range (IO, range, bus_sec);
+							else {
+								/* 1st IO Range on the bus */
+								range->rangeno = 1;
+								bus_sec->rangeIO = range;
+							}
+
+							++bus_sec->noIORanges;
+							fix_resources (bus_sec);
+						
+							io = kmalloc (sizeof (struct resource_node), GFP_KERNEL);							
+							if (!io) {
+								kfree (range);
+								err ("out of system memory \n");
+								return -ENOMEM;
+							}
+							memset (io, 0, sizeof (struct resource_node));
+							io->type = IO;
+							io->busno = bus_cur->busno;
+							io->devfunc = ((device << 3) | (function & 0x7));
+							io->start = start_address;
+							io->end = end_address + 0xfff;
+							io->len = io->end - io->start + 1;
+
+							ibmphp_add_resource (io);
+						}
+
+						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_MEMORY_BASE, &start_mem_address);
+						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_MEMORY_LIMIT, &end_mem_address);
+
+						start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
+						end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
+
+						if ((start_address) && (start_address <= end_address)) {
+
+							range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
+							if (!range) {
+								err ("out of system memory \n");
+								return -ENOMEM;
+							}
+							memset (range, 0, sizeof (struct range_node));
+							range->start = start_address;
+							range->end = end_address + 0xfffff;
+
+							if (bus_sec->noMemRanges > 0) 
+								add_range (MEM, range, bus_sec);
+							else {
+								/* 1st Mem Range on the bus */
+								range->rangeno = 1;
+								bus_sec->rangeMem = range;
+							}
+
+							++bus_sec->noMemRanges;
+							fix_resources (bus_sec);
+
+							mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+							if (!mem) {
+								kfree (range);
+								err ("out of system memory \n");
+								return -ENOMEM;
+							}
+							memset (mem, 0, sizeof (struct resource_node));
+							mem->type = MEM;
+							mem->busno = bus_cur->busno;
+							mem->devfunc = ((device << 3) | (function & 0x7));
+							mem->start = start_address;
+							mem->end = end_address + 0xfffff;
+							mem->len = mem->end - mem->start + 1;
+							ibmphp_add_resource (mem);
+						}
+						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_MEMORY_BASE, &start_mem_address);
+						pci_read_config_word_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_MEMORY_LIMIT, &end_mem_address);
+						pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_BASE_UPPER32, &upper_start);
+						pci_read_config_dword_nodev (ibmphp_pci_root_ops, busno, device, function, PCI_PREF_LIMIT_UPPER32, &upper_end);
+						start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
+						end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
+#if BITS_PER_LONG == 64
+						start_address |= ((long) upper_start) << 32;
+						end_address |= ((long) upper_end) << 32;
+#endif
+
+						if ((start_address) && (start_address <= end_address)) {
+
+							range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
+							if (!range) {
+								err ("out of system memory \n");
+								return -ENOMEM;
+							}
+							memset (range, 0, sizeof (struct range_node));
+							range->start = start_address;
+							range->end = end_address + 0xfffff;
+
+							if (bus_sec->noPFMemRanges > 0)
+								add_range (PFMEM, range, bus_sec);
+							else {
+								/* 1st PFMem Range on the bus */
+								range->rangeno = 1;
+								bus_sec->rangePFMem = range;
+							}
+
+							++bus_sec->noPFMemRanges;
+							fix_resources (bus_sec);
+
+							pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
+							if (!pfmem) {
+								kfree (range);
+								err ("out of system memory \n");
+								return -ENOMEM;
+							}
+							memset (pfmem, 0, sizeof (struct resource_node));
+							pfmem->type = PFMEM;
+							pfmem->busno = bus_cur->busno;
+							pfmem->devfunc = ((device << 3) | (function & 0x7));
+							pfmem->start = start_address;
+							pfmem->end = end_address + 0xfffff;
+							pfmem->len = pfmem->end - pfmem->start + 1;
+							pfmem->fromMem = FALSE;
+							ibmphp_add_resource (pfmem);
+						}
+						break;
+				}	/* end of switch */
+			}	/* end if vendor */
+		}	/* end for function */
+	}	/* end for device */
+
+	bus = &bus_cur;
+	return 0;
+}
diff -urN linux-2.5.6-pre1/drivers/hotplug/pci_hotplug_core.c linux-2.5.6-pre2/drivers/hotplug/pci_hotplug_core.c
--- linux-2.5.6-pre1/drivers/hotplug/pci_hotplug_core.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/drivers/hotplug/pci_hotplug_core.c	Thu Feb 28 13:34:21 2002
@@ -1,8 +1,8 @@
 /*
  * PCI HotPlug Controller Core
  *
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (c) 2001 IBM Corp.
+ * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001-2002 IBM Corp.
  *
  * All rights reserved.
  *
@@ -23,6 +23,8 @@
  *
  * Send feedback to <greg@kroah.com>
  *
+ * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs
+ *
  */
 
 #include <linux/config.h>
@@ -54,7 +56,7 @@
 /* local variables */
 static int debug;
 
-#define DRIVER_VERSION	"0.3"
+#define DRIVER_VERSION	"0.4"
 #define DRIVER_AUTHOR	"Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC	"PCI Hot Plug PCI Core"
 
@@ -74,7 +76,6 @@
 };
 
 static struct super_operations pcihpfs_ops;
-static struct address_space_operations pcihpfs_aops;
 static struct file_operations pcihpfs_dir_operations;
 static struct file_operations default_file_operations;
 static struct inode_operations pcihpfs_dir_inode_operations;
@@ -112,7 +113,6 @@
 		inode->i_blksize = PAGE_CACHE_SIZE;
 		inode->i_blocks = 0;
 		inode->i_rdev = NODEV;
-		inode->i_mapping->a_ops = &pcihpfs_aops;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 		switch (mode & S_IFMT) {
 		default:
@@ -154,18 +154,6 @@
  	return pcihpfs_mknod (dir, dentry, mode | S_IFREG, 0);
 }
 
-static int pcihpfs_link (struct dentry *old_dentry, struct inode *dir,
-			 struct dentry *dentry)
-{
-	struct inode *inode = old_dentry->d_inode;
-
-	inode->i_nlink++;
-	atomic_inc(&inode->i_count);
- 	dget(dentry);
-	d_instantiate(dentry, inode);
-	return 0;
-}
-
 static inline int pcihpfs_positive (struct dentry *dentry)
 {
 	return dentry->d_inode && !d_unhashed(dentry);
@@ -196,29 +184,15 @@
 	if (pcihpfs_empty(dentry)) {
 		struct inode *inode = dentry->d_inode;
 
+		lock_kernel();
 		inode->i_nlink--;
+		unlock_kernel();
 		dput(dentry);
 		error = 0;
 	}
 	return error;
 }
 
-static int pcihpfs_rename (struct inode *old_dir, struct dentry *old_dentry,
-			   struct inode *new_dir, struct dentry *new_dentry)
-{
-	int error = -ENOTEMPTY;
-
-	if (pcihpfs_empty(new_dentry)) {
-		struct inode *inode = new_dentry->d_inode;
-		if (inode) {
-			inode->i_nlink--;
-			dput(new_dentry);
-		}
-		error = 0;
-	}
-	return error;
-}
-
 #define pcihpfs_rmdir pcihpfs_unlink
 
 /* default file operations */
@@ -238,6 +212,7 @@
 {
 	loff_t retval = -EINVAL;
 
+	lock_kernel();
 	switch(orig) {
 	case 0:
 		if (offset > 0) {
@@ -254,6 +229,7 @@
 	default:
 		break;
 	}
+	unlock_kernel();
 	return retval;
 }
 
@@ -265,18 +241,9 @@
 	return 0;
 }
 
-static int default_sync_file (struct file *file, struct dentry *dentry, int datasync)
-{
-	return 0;
-}
-
-static struct address_space_operations pcihpfs_aops = {
-};
-
 static struct file_operations pcihpfs_dir_operations = {
 	read:		generic_read_dir,
 	readdir:	dcache_readdir,
-	fsync:		default_sync_file,
 };
 
 static struct file_operations default_file_operations = {
@@ -284,8 +251,6 @@
 	write:		default_write_file,
 	open:		default_open,
 	llseek:		default_file_lseek,
-	fsync:		default_sync_file,
-	mmap:		generic_file_mmap,
 };
 
 /* file ops for the "power" files */
@@ -296,8 +261,6 @@
 	write:		power_write_file,
 	open:		default_open,
 	llseek:		default_file_lseek,
-	fsync:		default_sync_file,
-	mmap:		generic_file_mmap,
 };
 
 /* file ops for the "attention" files */
@@ -308,8 +271,6 @@
 	write:		attention_write_file,
 	open:		default_open,
 	llseek:		default_file_lseek,
-	fsync:		default_sync_file,
-	mmap:		generic_file_mmap,
 };
 
 /* file ops for the "latch" files */
@@ -319,8 +280,6 @@
 	write:		default_write_file,
 	open:		default_open,
 	llseek:		default_file_lseek,
-	fsync:		default_sync_file,
-	mmap:		generic_file_mmap,
 };
 
 /* file ops for the "presence" files */
@@ -330,8 +289,6 @@
 	write:		default_write_file,
 	open:		default_open,
 	llseek:		default_file_lseek,
-	fsync:		default_sync_file,
-	mmap:		generic_file_mmap,
 };
 
 /* file ops for the "test" files */
@@ -341,19 +298,15 @@
 	write:		test_write_file,
 	open:		default_open,
 	llseek:		default_file_lseek,
-	fsync:		default_sync_file,
-	mmap:		generic_file_mmap,
 };
 
 static struct inode_operations pcihpfs_dir_inode_operations = {
 	create:		pcihpfs_create,
 	lookup:		pcihpfs_lookup,
-	link:		pcihpfs_link,
 	unlink:		pcihpfs_unlink,
 	mkdir:		pcihpfs_mkdir,
 	rmdir:		pcihpfs_rmdir,
 	mknod:		pcihpfs_mknod,
-	rename:		pcihpfs_rename,
 };
 
 static struct super_operations pcihpfs_ops = {
@@ -485,7 +438,7 @@
 
 	if (!parent) {
 		dbg("Ah! can not find a parent!\n");
-		return -EFAULT;
+		return -EINVAL;
 	}
 
 	*dentry = NULL;
@@ -686,7 +639,7 @@
 
 		default:
 			err ("Illegal value specified for power\n");
-			retval = -EFAULT;
+			retval = -EINVAL;
 	}
 
 exit:	
@@ -1019,7 +972,7 @@
 	if (slot == NULL)
 		return -ENODEV;
 	if ((slot->info == NULL) || (slot->ops == NULL))
-		return -EFAULT;
+		return -EINVAL;
 
 	core = kmalloc (sizeof (struct hotplug_slot_core), GFP_KERNEL);
 	if (!core)
@@ -1030,7 +983,7 @@
 	if (get_slot_from_name (slot->name) != NULL) {
 		spin_unlock (&list_lock);
 		kfree (core);
-		return -EFAULT;
+		return -EINVAL;
 	}
 
 	slot->core_priv = core;
@@ -1076,6 +1029,12 @@
 	return 0;
 }
 
+static inline void update_inode_time (struct inode *inode)
+{
+	if (inode)
+		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+}
+
 /**
  * pci_hp_change_slot_info - changes the slot's information structure in the core
  * @name: the name of the slot whose info has changed
@@ -1089,6 +1048,7 @@
 int pci_hp_change_slot_info (const char *name, struct hotplug_slot_info *info)
 {
 	struct hotplug_slot *temp;
+	struct hotplug_slot_core *core;
 
 	if (info == NULL)
 		return -ENODEV;
@@ -1100,6 +1060,24 @@
 		return -ENODEV;
 	}
 
+	/*
+	 * check all fields in the info structure, and update timestamps
+	 * for the files referring to the fields that have now changed.
+	 */
+	core = temp->core_priv;
+	if ((core->power_dentry) &&
+	    (temp->info->power_status != info->power_status))
+		update_inode_time (core->power_dentry->d_inode);
+	if ((core->attention_dentry) &&
+	    (temp->info->attention_status != info->attention_status))
+		update_inode_time (core->attention_dentry->d_inode);
+	if ((core->latch_dentry) &&
+	    (temp->info->latch_status != info->latch_status))
+		update_inode_time (core->latch_dentry->d_inode);
+	if ((core->adapter_dentry) &&
+	    (temp->info->adapter_status != info->adapter_status))
+		update_inode_time (core->adapter_dentry->d_inode);
+
 	memcpy (temp->info, info, sizeof (struct hotplug_slot_info));
 	spin_unlock (&list_lock);
 	return 0;
diff -urN linux-2.5.6-pre1/drivers/ide/aec62xx.c linux-2.5.6-pre2/drivers/ide/aec62xx.c
--- linux-2.5.6-pre1/drivers/ide/aec62xx.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/ide/aec62xx.c	Thu Feb 28 13:34:21 2002
@@ -48,7 +48,6 @@
 
 static int aec62xx_get_info(char *, char **, off_t, int);
 extern int (*aec62xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
 static struct pci_dev *bmide_dev;
 
 static int aec62xx_get_info (char *buffer, char **addr, off_t offset, int count)
@@ -203,22 +202,18 @@
 
 static byte pci_bus_clock_list (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
 {
-	int bus_speed = system_bus_clock();
-
 	for ( ; chipset_table->xfer_speed ; chipset_table++)
 		if (chipset_table->xfer_speed == speed) {
-			return ((byte) ((bus_speed <= 33) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34));
+			return ((byte) ((system_bus_speed <= 33) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34));
 		}
 	return 0x00;
 }
 
 static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
 {
-	int bus_speed = system_bus_clock();
-
 	for ( ; chipset_table->xfer_speed ; chipset_table++)
 		if (chipset_table->xfer_speed == speed) {
-			return ((byte) ((bus_speed <= 33) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34));
+			return ((byte) ((system_bus_speed <= 33) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34));
 		}
 	return 0x00;
 }
@@ -314,8 +309,8 @@
 	unsigned long dma_base	= hwif->dma_base;
 	byte speed		= -1;
 
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
+	if (drive->type != ATA_DISK)
+		return ide_dma_off_quietly;
 
 	if (((id->dma_ultra & 0x0010) ||
 	     (id->dma_ultra & 0x0008) ||
@@ -360,7 +355,7 @@
 	byte speed		= -1;
 	byte ultra66		= eighty_ninty_three(drive);
 
-	if (drive->media != ide_disk)
+	if (drive->type != ATA_DISK)
 		return ((int) ide_dma_off_quietly);
 
 	if ((id->dma_ultra & 0x0010) && (ultra) && (ultra66)) {
@@ -522,11 +517,11 @@
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 #endif /* CONFIG_AEC62XX_TUNING */
 
-unsigned int __init pci_init_aec62xx (struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_aec62xx (struct pci_dev *dev)
 {
 	if (dev->resource[PCI_ROM_RESOURCE].start) {
 		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+		printk("%s: ROM enabled at 0x%08lx\n", dev->name, dev->resource[PCI_ROM_RESOURCE].start);
 	}
 
 #if defined(DISPLAY_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
diff -urN linux-2.5.6-pre1/drivers/ide/ali14xx.c linux-2.5.6-pre2/drivers/ide/ali14xx.c
--- linux-2.5.6-pre1/drivers/ide/ali14xx.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/drivers/ide/ali14xx.c	Thu Feb 28 13:34:21 2002
@@ -119,15 +119,14 @@
 	byte param1, param2, param3, param4;
 	unsigned long flags;
 	ide_pio_data_t d;
-	int bus_speed = system_bus_clock();
 
 	pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
 
 	/* calculate timing, according to PIO mode */
 	time1 = d.cycle_time;
 	time2 = ide_pio_timings[pio].active_time;
-	param3 = param1 = (time2 * bus_speed + 999) / 1000;
-	param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
+	param3 = param1 = (time2 * system_bus_speed + 999) / 1000;
+	param4 = param2 = (time1 * system_bus_speed + 999) / 1000 - param1;
 	if (pio < 3) {
 		param3 += 8;
 		param4 += 8;
diff -urN linux-2.5.6-pre1/drivers/ide/alim15x3.c linux-2.5.6-pre2/drivers/ide/alim15x3.c
--- linux-2.5.6-pre1/drivers/ide/alim15x3.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/drivers/ide/alim15x3.c	Thu Feb 28 13:34:21 2002
@@ -247,7 +247,6 @@
 	int s_time, a_time, c_time;
 	byte s_clc, a_clc, r_clc;
 	unsigned long flags;
-	int bus_speed = system_bus_clock();
 	int port = hwif->index ? 0x5c : 0x58;
 	int portFIFO = hwif->channel ? 0x55 : 0x54;
 	byte cd_dma_fifo = 0;
@@ -255,18 +254,18 @@
 	pio = ide_get_best_pio_mode(drive, pio, 5, &d);
 	s_time = ide_pio_timings[pio].setup_time;
 	a_time = ide_pio_timings[pio].active_time;
-	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
+	if ((s_clc = (s_time * system_bus_speed + 999) / 1000) >= 8)
 		s_clc = 0;
-	if ((a_clc = (a_time * bus_speed + 999) / 1000) >= 8)
+	if ((a_clc = (a_time * system_bus_speed + 999) / 1000) >= 8)
 		a_clc = 0;
 	c_time = ide_pio_timings[pio].cycle_time;
 
 #if 0
-	if ((r_clc = ((c_time - s_time - a_time) * bus_speed + 999) / 1000) >= 16)
+	if ((r_clc = ((c_time - s_time - a_time) * system_bus_speed + 999) / 1000) >= 16)
 		r_clc = 0;
 #endif
 
-	if (!(r_clc = (c_time * bus_speed + 999) / 1000 - a_clc - s_clc)) {
+	if (!(r_clc = (c_time * system_bus_speed + 999) / 1000 - a_clc - s_clc)) {
 		r_clc = 1;
 	} else {
 		if (r_clc >= 16)
@@ -279,7 +278,7 @@
 	 * PIO mode => ATA FIFO on, ATAPI FIFO off
 	 */
 	pci_read_config_byte(dev, portFIFO, &cd_dma_fifo);
-	if (drive->media==ide_disk) {
+	if (drive->type == ATA_DISK) {
 		if (hwif->index) {
 			pci_write_config_byte(dev, portFIFO, (cd_dma_fifo & 0x0F) | 0x50);
 		} else {
@@ -425,9 +424,9 @@
 	} else if ((m5229_revision < 0xC2) &&
 #ifndef CONFIG_WDC_ALI15X3
 		   ((chip_is_1543c_e && strstr(id->model, "WDC ")) ||
-		    (drive->media!=ide_disk))) {
+		    (drive->type != ATA_DISK))) {
 #else /* CONFIG_WDC_ALI15X3 */
-		   (drive->media!=ide_disk)) {
+		   (drive->type != ATA_DISK)) {
 #endif /* CONFIG_WDC_ALI15X3 */
 		return 0;
 	} else {
@@ -442,7 +441,7 @@
 	ide_dma_action_t dma_func	= ide_dma_on;
 	byte can_ultra_dma		= ali15x3_can_ultra(drive);
 
-	if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
+	if ((m5229_revision<=0x20) && (drive->type != ATA_DISK))
 		return hwif->dmaproc(ide_dma_off_quietly, drive);
 
 	if ((id != NULL) && ((id->capability & 1) != 0) && hwif->autodma) {
@@ -495,7 +494,7 @@
 		case ide_dma_check:
 			return ali15x3_config_drive_for_dma(drive);
 		case ide_dma_write:
-			if ((m5229_revision < 0xC2) && (drive->media != ide_disk))
+			if ((m5229_revision < 0xC2) && (drive->type != ATA_DISK))
 				return 1;	/* try PIO instead of DMA */
 			break;
 		default:
@@ -505,7 +504,7 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_ali15x3(struct pci_dev *dev)
 {
 	unsigned long fixdma_base = pci_resource_start(dev, 4);
 
@@ -524,7 +523,7 @@
 		outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
 
 		if (inb(fixdma_base+2) & 0x80)
-			printk("%s: simplex device: DMA will fail!!\n", name);
+			printk("%s: simplex device: DMA will fail!!\n", dev->name);
 	}
 
 #if defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS)
diff -urN linux-2.5.6-pre1/drivers/ide/amd74xx.c linux-2.5.6-pre2/drivers/ide/amd74xx.c
--- linux-2.5.6-pre1/drivers/ide/amd74xx.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/drivers/ide/amd74xx.c	Thu Feb 28 13:34:21 2002
@@ -34,7 +34,6 @@
 
 static int amd74xx_get_info(char *, char **, off_t, int);
 extern int (*amd74xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
 static struct pci_dev *bmide_dev;
 
 static int amd74xx_get_info (char *buffer, char **addr, off_t offset, int count)
@@ -406,13 +405,13 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-unsigned int __init pci_init_amd74xx (struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_amd74xx(struct pci_dev *dev)
 {
 	unsigned long fixdma_base = pci_resource_start(dev, 4);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (!amd74xx_swdma_check(dev))
-		printk("%s: disabling single-word DMA support (revision < C4)\n", name);
+		printk("%s: disabling single-word DMA support (revision < C4)\n", dev->name);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	if (!fixdma_base) {
@@ -426,7 +425,7 @@
 		outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
 
 		if (inb(fixdma_base+2) & 0x80)
-			printk("%s: simplex device: DMA will fail!!\n", name);
+			printk("%s: simplex device: DMA will fail!!\n", dev->name);
 	}
 #if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!amd74xx_proc) {
diff -urN linux-2.5.6-pre1/drivers/ide/cmd640.c linux-2.5.6-pre2/drivers/ide/cmd640.c
--- linux-2.5.6-pre1/drivers/ide/cmd640.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/drivers/ide/cmd640.c	Thu Feb 28 13:34:21 2002
@@ -23,7 +23,7 @@
  *
  *  A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com,
  *  bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz,
- *  chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de,
+ *  chrisc@dbass.demon.co.uk, dalecki@evision-ventures.com,
  *  derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de,
  *  flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net,
  *  j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net,
@@ -596,14 +596,13 @@
 {
 	int setup_time, active_time, recovery_time, clock_time;
 	byte setup_count, active_count, recovery_count, recovery_count2, cycle_count;
-	int bus_speed = system_bus_clock();
 
 	if (pio_mode > 5)
 		pio_mode = 5;
 	setup_time  = ide_pio_timings[pio_mode].setup_time;
 	active_time = ide_pio_timings[pio_mode].active_time;
 	recovery_time = cycle_time - (setup_time + active_time);
-	clock_time = 1000 / bus_speed;
+	clock_time = 1000 / system_bus_speed;
 	cycle_count = (cycle_time + clock_time - 1) / clock_time;
 
 	setup_count = (setup_time + clock_time - 1) / clock_time;
diff -urN linux-2.5.6-pre1/drivers/ide/cmd64x.c linux-2.5.6-pre2/drivers/ide/cmd64x.c
--- linux-2.5.6-pre1/drivers/ide/cmd64x.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/ide/cmd64x.c	Thu Feb 28 13:34:21 2002
@@ -88,7 +88,6 @@
 static int cmd64x_get_info(char *, char **, off_t, int);
 static int cmd680_get_info(char *, char **, off_t, int);
 extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
 static struct pci_dev *bmide_dev;
 
 static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
@@ -283,8 +282,6 @@
 	int setup_time, active_time, recovery_time, clock_time, pio_mode, cycle_time;
 	byte recovery_count2, cycle_count;
 	int setup_count, active_count, recovery_count;
-	int bus_speed = system_bus_clock();
-	/*byte b;*/
 	ide_pio_data_t  d;
 
 	switch (mode_wanted) {
@@ -309,7 +306,7 @@
 	setup_time  = ide_pio_timings[pio_mode].setup_time;
 	active_time = ide_pio_timings[pio_mode].active_time;
 	recovery_time = cycle_time - (setup_time + active_time);
-	clock_time = 1000 / bus_speed;
+	clock_time = 1000 / system_bus_speed;
 	cycle_count = (cycle_time + clock_time - 1) / clock_time;
 
 	setup_count = (setup_time + clock_time - 1) / clock_time;
@@ -450,7 +447,8 @@
 	u8 regU			= 0;
 	u8 regD			= 0;
 
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))	return 1;
+	if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0))
+		return 1;
 
 	(void) pci_read_config_byte(dev, pciD, &regD);
 	(void) pci_read_config_byte(dev, pciU, &regU);
@@ -643,8 +641,8 @@
 			break;
 	}
 
-	if (drive->media != ide_disk) {
-		cmdprintk("CMD64X: drive->media != ide_disk at double check, inital check failed!!\n");
+	if (drive->type != ATA_DISK) {
+		cmdprintk("CMD64X: drive is not a disk at double check, inital check failed!!\n");
 		return ((int) ide_dma_off);
 	}
 
@@ -790,7 +788,7 @@
 	}
 
 	if ((id != NULL) && ((id->capability & 1) != 0) &&
-	    hwif->autodma && (drive->media == ide_disk)) {
+	    hwif->autodma && (drive->type == ATA_DISK)) {
 		/* Consult the list of known "bad" drives */
 		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
 			dma_func = ide_dma_off;
@@ -956,7 +954,7 @@
 	return 0;
 }
 
-void cmd680_reset (ide_drive_t *drive)
+static void cmd680_reset (ide_drive_t *drive)
 {
 #if 0
 	ide_hwif_t *hwif	= HWIF(drive);
@@ -968,9 +966,9 @@
 #endif
 }
 
-unsigned int cmd680_pci_init (struct pci_dev *dev, const char *name)
+static unsigned int cmd680_pci_init(struct pci_dev *dev)
 {
-	u8 tmpbyte	= 0;	
+	u8 tmpbyte	= 0;
 	pci_write_config_byte(dev, 0x80, 0x00);
 	pci_write_config_byte(dev, 0x84, 0x00);
 	pci_read_config_byte(dev, 0x8A, &tmpbyte);
@@ -994,7 +992,7 @@
 	return 0;
 }
 
-unsigned int cmd64x_pci_init (struct pci_dev *dev, const char *name)
+static unsigned int cmd64x_pci_init(struct pci_dev *dev)
 {
 	unsigned char mrdmode;
 	unsigned int class_rev;
@@ -1005,7 +1003,7 @@
 #ifdef __i386__
 	if (dev->resource[PCI_ROM_RESOURCE].start) {
 		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+		printk("%s: ROM enabled at 0x%08lx\n", dev->name, dev->resource[PCI_ROM_RESOURCE].start);
 	}
 #endif
 
@@ -1013,7 +1011,7 @@
 		case PCI_DEVICE_ID_CMD_643:
 			break;
 		case PCI_DEVICE_ID_CMD_646:
-			printk("%s: chipset revision 0x%02X, ", name, class_rev);
+			printk("%s: chipset revision 0x%02X, ", dev->name, class_rev);
 			switch(class_rev) {
 				case 0x07:
 				case 0x05:
@@ -1083,11 +1081,11 @@
 	return 0;
 }
 
-unsigned int __init pci_init_cmd64x (struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_cmd64x(struct pci_dev *dev)
 {
 	if (dev->device == PCI_DEVICE_ID_CMD_680)
-		return cmd680_pci_init (dev, name);
-	return cmd64x_pci_init (dev, name);
+		return cmd680_pci_init (dev);
+	return cmd64x_pci_init (dev);
 }
 
 unsigned int cmd680_ata66 (ide_hwif_t *hwif)
diff -urN linux-2.5.6-pre1/drivers/ide/cs5530.c linux-2.5.6-pre2/drivers/ide/cs5530.c
--- linux-2.5.6-pre1/drivers/ide/cs5530.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/ide/cs5530.c	Thu Feb 28 13:34:21 2002
@@ -37,7 +37,6 @@
 
 static int cs5530_get_info(char *, char **, off_t, int);
 extern int (*cs5530_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
 static struct pci_dev *bmide_dev;
 
 static int cs5530_get_info (char *buffer, char **addr, off_t offset, int count)
@@ -251,7 +250,7 @@
 /*
  * Initialize the cs5530 bridge for reliable IDE DMA operation.
  */
-unsigned int __init pci_init_cs5530 (struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_cs5530(struct pci_dev *dev)
 {
 	struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
 	unsigned short pcicmd = 0;
@@ -278,11 +277,11 @@
 		}
 	}
 	if (!master_0) {
-		printk("%s: unable to locate PCI MASTER function\n", name);
+		printk("%s: unable to locate PCI MASTER function\n", dev->name);
 		return 0;
 	}
 	if (!cs5530_0) {
-		printk("%s: unable to locate CS5530 LEGACY function\n", name);
+		printk("%s: unable to locate CS5530 LEGACY function\n", dev->name);
 		return 0;
 	}
 
diff -urN linux-2.5.6-pre1/drivers/ide/cy82c693.c linux-2.5.6-pre2/drivers/ide/cy82c693.c
--- linux-2.5.6-pre1/drivers/ide/cy82c693.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/drivers/ide/cy82c693.c	Thu Feb 28 13:34:21 2002
@@ -141,7 +141,6 @@
 static void compute_clocks (byte pio, pio_clocks_t *p_pclk)
 {
 	int clk1, clk2;
-	int bus_speed = system_bus_clock();	/* get speed of PCI bus */
 
 	/* we don't check against CY82C693's min and max speed,
 	 * so you can play with the idebus=xx parameter
@@ -151,17 +150,17 @@
 		pio = CY82C693_MAX_PIO;
 
 	/* let's calc the address setup time clocks */
-	p_pclk->address_time = (byte)calc_clk(ide_pio_timings[pio].setup_time, bus_speed);
+	p_pclk->address_time = (byte)calc_clk(ide_pio_timings[pio].setup_time, system_bus_speed);
 
 	/* let's calc the active and recovery time clocks */
-	clk1 = calc_clk(ide_pio_timings[pio].active_time, bus_speed);
+	clk1 = calc_clk(ide_pio_timings[pio].active_time, system_bus_speed);
 
 	/* calc recovery timing */
 	clk2 =	ide_pio_timings[pio].cycle_time -
 		ide_pio_timings[pio].active_time -
 		ide_pio_timings[pio].setup_time;
 
-	clk2 = calc_clk(clk2, bus_speed);
+	clk2 = calc_clk(clk2, system_bus_speed);
 
 	clk1 = (clk1<<4)|clk2;	/* combine active and recovery clocks */
 
@@ -384,7 +383,7 @@
  * the device prior to INIT.
  */
 
-unsigned int __init pci_init_cy82c693(struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_cy82c693(struct pci_dev *dev)
 {
 #ifdef CY82C693_SETDMA_CLOCK
         byte data;
@@ -400,7 +399,7 @@
         data = IN_BYTE(CY82_DATA_PORT);
 
 #if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n", name, data);
+	printk (KERN_INFO "%s: Peripheral Configuration Register: 0x%X\n", dev->name, data);
 #endif /* CY82C693_DEBUG_INFO */
 
         /*
@@ -421,7 +420,7 @@
         OUT_BYTE(data, CY82_DATA_PORT);
 
 #if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", name, data);
+	printk (KERN_INFO "%s: New Peripheral Configuration Register: 0x%X\n", dev->name, data);
 #endif /* CY82C693_DEBUG_INFO */
 
 #endif /* CY82C693_SETDMA_CLOCK */
@@ -434,7 +433,7 @@
 void __init ide_init_cy82c693(ide_hwif_t *hwif)
 {
 	hwif->chipset = ide_cy82c693;
-	hwif->tuneproc = &cy82c693_tune_drive;
+	hwif->tuneproc = cy82c693_tune_drive;
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
 	hwif->autodma = 0;
@@ -442,7 +441,7 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
 		hwif->highmem = 1;
-		hwif->dmaproc = &cy82c693_dmaproc;
+		hwif->dmaproc = cy82c693_dmaproc;
 		if (!noautodma)
 			hwif->autodma = 1;
 	}
diff -urN linux-2.5.6-pre1/drivers/ide/hpt34x.c linux-2.5.6-pre2/drivers/ide/hpt34x.c
--- linux-2.5.6-pre1/drivers/ide/hpt34x.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/drivers/ide/hpt34x.c	Thu Feb 28 13:34:21 2002
@@ -56,7 +56,6 @@
 
 static int hpt34x_get_info(char *, char **, off_t, int);
 extern int (*hpt34x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
 static struct pci_dev *bmide_dev;
 
 static int hpt34x_get_info (char *buffer, char **addr, off_t offset, int count)
@@ -210,7 +209,7 @@
 	struct hd_driveid *id	= drive->id;
 	byte speed		= 0x00;
 
-	if (drive->media != ide_disk)
+	if (drive->type != ATA_DISK)
 		return ((int) ide_dma_off_quietly);
 
 	hpt34x_clear_chipset(drive);
@@ -333,7 +332,7 @@
 			outb(reading, dma_base);		/* specify r/w */
 			outb(inb(dma_base+2)|6, dma_base+2);	/* clear INTR & ERROR flags */
 			drive->waiting_for_dma = 1;
-			if (drive->media != ide_disk)
+			if (drive->type != ATA_DISK)
 				return 0;
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);	/* issue cmd to drive */
 			OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
@@ -357,7 +356,7 @@
  */
 #define	HPT34X_PCI_INIT_REG		0x80
 
-unsigned int __init pci_init_hpt34x (struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_hpt34x(struct pci_dev *dev)
 {
 	int i = 0;
 	unsigned long hpt34xIoBase = pci_resource_start(dev, 4);
diff -urN linux-2.5.6-pre1/drivers/ide/hpt366.c linux-2.5.6-pre2/drivers/ide/hpt366.c
--- linux-2.5.6-pre1/drivers/ide/hpt366.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/drivers/ide/hpt366.c	Thu Feb 28 13:34:21 2002
@@ -355,7 +355,6 @@
 #if defined(DISPLAY_HPT366_TIMINGS) && defined(CONFIG_PROC_FS)
 static int hpt366_get_info(char *, char **, off_t, int);
 extern int (*hpt366_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
 
 static int hpt366_get_info (char *buffer, char **addr, off_t offset, int count)
 {
@@ -579,7 +578,7 @@
 
 static int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
 {
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
+	if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0))
 		return -1;
 
 	if (!drive->init_speed)
@@ -664,7 +663,7 @@
 	byte ultra66		= eighty_ninty_three(drive);
 	int  rval;
 
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
+	if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0))
 		return ((int) ide_dma_off_quietly);
 
 	if ((id->dma_ultra & 0x0020) &&
@@ -1097,7 +1096,7 @@
 	udelay(100);
 }
 
-unsigned int __init pci_init_hpt366 (struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_hpt366(struct pci_dev *dev)
 {
 	byte test = 0;
 
diff -urN linux-2.5.6-pre1/drivers/ide/ht6560b.c linux-2.5.6-pre2/drivers/ide/ht6560b.c
--- linux-2.5.6-pre1/drivers/ide/ht6560b.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/drivers/ide/ht6560b.c	Thu Feb 28 13:34:21 2002
@@ -143,7 +143,7 @@
 	if (select != current_select || timing != current_timing) {
 		current_select = select;
 		current_timing = timing;
-		if (drive->media != ide_disk || !drive->present)
+		if (drive->type != ATA_DISK || !drive->present)
 			select |= HT_PREFETCH_MODE;
 		(void) inb(HT_CONFIG_PORT);
 		(void) inb(HT_CONFIG_PORT);
@@ -207,7 +207,6 @@
 	int active_time, recovery_time;
 	int active_cycles, recovery_cycles;
 	ide_pio_data_t d;
-	int bus_speed = system_bus_clock();
 	
         if (pio) {
 		pio = ide_get_best_pio_mode(drive, pio, 5, &d);
@@ -224,8 +223,8 @@
 		/*
 		 *  Cycle times should be Vesa bus cycles
 		 */
-		active_cycles   = (active_time   * bus_speed + 999) / 1000;
-		recovery_cycles = (recovery_time * bus_speed + 999) / 1000;
+		active_cycles   = (active_time   * system_bus_speed + 999) / 1000;
+		recovery_cycles = (recovery_time * system_bus_speed + 999) / 1000;
 		/*
 		 *  Upper and lower limits
 		 */
diff -urN linux-2.5.6-pre1/drivers/ide/ide-cd.c linux-2.5.6-pre2/drivers/ide/ide-cd.c
--- linux-2.5.6-pre1/drivers/ide/ide-cd.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/drivers/ide/ide-cd.c	Thu Feb 28 13:34:21 2002
@@ -2906,15 +2906,10 @@
 	return 0;
 }
 
-int ide_cdrom_init(void);
-int ide_cdrom_reinit (ide_drive_t *drive);
+static int ide_cdrom_reinit (ide_drive_t *drive);
 
-static ide_driver_t ide_cdrom_driver = {
-	name:			"ide-cdrom",
-	media:			ide_cdrom,
-	busy:			0,
-	supports_dma:		1,
-	supports_dsc_overlap:	1,
+static struct ata_operations ide_cdrom_driver = {
+	owner:			THIS_MODULE,
 	cleanup:		ide_cdrom_cleanup,
 	standby:		NULL,
 	flushcache:		NULL,
@@ -2929,7 +2924,6 @@
 	capacity:		ide_cdrom_capacity,
 	special:		NULL,
 	proc:			NULL,
-	driver_init:		ide_cdrom_init,
 	driver_reinit:		ide_cdrom_reinit,
 };
 
@@ -2939,7 +2933,7 @@
 MODULE_PARM(ignore, "s");
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
-int ide_cdrom_reinit (ide_drive_t *drive)
+static int ide_cdrom_reinit (ide_drive_t *drive)
 {
 	struct cdrom_info *info;
 	int failed = 0;
@@ -2957,17 +2951,20 @@
 	}
 	memset (info, 0, sizeof (struct cdrom_info));
 	drive->driver_data = info;
-	DRIVER(drive)->busy++;
+
+	/* ATA-PATTERN */
+	ata_ops(drive)->busy++;
 	if (ide_cdrom_setup (drive)) {
-		DRIVER(drive)->busy--;
+		ata_ops(drive)->busy--;
 		if (ide_cdrom_cleanup (drive))
 			printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
 		return 1;
 	}
-	DRIVER(drive)->busy--;
+	ata_ops(drive)->busy--;
+
 	failed--;
 
-	ide_register_module(&ide_cdrom_driver);
+	revalidate_drives();
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -2977,12 +2974,11 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, &ide_cdrom_driver, failed)) != NULL)
+	while ((drive = ide_scan_devices(ATA_ROM, "ide-cdrom", &ide_cdrom_driver, failed)) != NULL)
 		if (ide_cdrom_cleanup (drive)) {
 			printk ("%s: cleanup_module() called while still busy\n", drive->name);
 			failed++;
 		}
-	ide_unregister_module (&ide_cdrom_driver);
 }
  
 int ide_cdrom_init(void)
@@ -2992,7 +2988,7 @@
 	int failed = 0;
 
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, NULL, failed++)) != NULL) {
+	while ((drive = ide_scan_devices (ATA_ROM, "ide-cdrom", NULL, failed++)) != NULL) {
 		/* skip drives that we were told to ignore */
 		if (ignore != NULL) {
 			if (strstr(ignore, drive->name)) {
@@ -3016,17 +3012,20 @@
 		}
 		memset (info, 0, sizeof (struct cdrom_info));
 		drive->driver_data = info;
-		DRIVER(drive)->busy++;
+
+		/* ATA-PATTERN */
+		ata_ops(drive)->busy++;
 		if (ide_cdrom_setup (drive)) {
-			DRIVER(drive)->busy--;
+			ata_ops(drive)->busy--;
 			if (ide_cdrom_cleanup (drive))
 				printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
 			continue;
 		}
-		DRIVER(drive)->busy--;
+		ata_ops(drive)->busy--;
+
 		failed--;
 	}
-	ide_register_module(&ide_cdrom_driver);
+	revalidate_drives();
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
diff -urN linux-2.5.6-pre1/drivers/ide/ide-disk.c linux-2.5.6-pre2/drivers/ide/ide-disk.c
--- linux-2.5.6-pre1/drivers/ide/ide-disk.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/drivers/ide/ide-disk.c	Thu Feb 28 13:34:21 2002
@@ -378,11 +378,6 @@
 	return drive->removable;	/* if removable, always assume it was changed */
 }
 
-static void idedisk_revalidate (ide_drive_t *drive)
-{
-	ide_revalidate_drive(drive);
-}
-
 /*
  * Queries for true maximum capacity of the drive.
  * Returns maximum LBA address (> 0) of the drive, 0 if failed.
@@ -915,13 +910,22 @@
 	ide_add_setting(drive,	"max_failures",		SETTING_RW,					-1,			-1,			TYPE_INT,	0,	65535,				1,	1,	&drive->max_failures,		NULL);
 }
 
-static void idedisk_setup (ide_drive_t *drive)
+/* This is just a hook for the overall driver tree.
+ *
+ * FIXME: This is soon goig to replace the custom linked list games played up
+ * to great extend between the different components of the IDE drivers.
+ */
+
+static struct device_driver idedisk_devdrv = {};
+
+static void idedisk_setup(ide_drive_t *drive)
 {
 	int i;
-	
+
 	struct hd_driveid *id = drive->id;
 	unsigned long capacity;
-	
+	int drvid = -1;
+
 	idedisk_add_settings(drive);
 
 	if (id == NULL)
@@ -933,7 +937,7 @@
 	 */
 	if (drive->removable && !drive_is_flashcard(drive)) {
 		/*
-		 * Removable disks (eg. SYQUEST); ignore 'WD' drives 
+		 * Removable disks (eg. SYQUEST); ignore 'WD' drives.
 		 */
 		if (id->model[0] != 'W' || id->model[1] != 'D') {
 			drive->doorlocking = 1;
@@ -942,13 +946,26 @@
 	for (i = 0; i < MAX_DRIVES; ++i) {
 		ide_hwif_t *hwif = HWIF(drive);
 
-		if (drive != &hwif->drives[i]) continue;
+		if (drive != &hwif->drives[i])
+		    continue;
+		drvid = i;
 		hwif->gd->de_arr[i] = drive->de;
 		if (drive->removable)
 			hwif->gd->flags[i] |= GENHD_FL_REMOVABLE;
 		break;
 	}
 
+	/* Register us within the device tree.
+	 */
+
+	if (drvid != -1) {
+	    sprintf(drive->device.bus_id, "%d", drvid);
+	    sprintf(drive->device.name, "ide-disk");
+	    drive->device.driver = &idedisk_devdrv;
+	    drive->device.parent = &HWIF(drive)->device;
+	    device_register(&drive->device);
+	}
+
 	/* Extract geometry if we did not already have one for the drive */
 	if (!drive->cyl || !drive->head || !drive->sect) {
 		drive->cyl     = drive->bios_cyl  = id->cyls;
@@ -1023,6 +1040,12 @@
 
 static int idedisk_cleanup (ide_drive_t *drive)
 {
+
+	/* FIXME: we will have to think twice whatever this is the proper place
+	 * to do it.
+	 */
+
+	put_device(&drive->device);
 	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
 		if (do_idedisk_flushcache(drive))
 			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
@@ -1030,18 +1053,13 @@
 	return ide_unregister_subdriver(drive);
 }
 
-int idedisk_init (void);
-int idedisk_reinit(ide_drive_t *drive);
+static int idedisk_reinit(ide_drive_t *drive);
 
 /*
  *      IDE subdriver functions, registered with ide.c
  */
-static ide_driver_t idedisk_driver = {
-	name:			"ide-disk",
-	media:			ide_disk,
-	busy:			0,
-	supports_dma:		1,
-	supports_dsc_overlap:	0,
+static struct ata_operations idedisk_driver = {
+	owner:			THIS_MODULE,
 	cleanup:		idedisk_cleanup,
 	standby:		do_idedisk_standby,
 	flushcache:		do_idedisk_flushcache,
@@ -1051,18 +1069,17 @@
 	open:			idedisk_open,
 	release:		idedisk_release,
 	media_change:		idedisk_media_change,
-	revalidate:		idedisk_revalidate,
+	revalidate:		ide_revalidate_drive,
 	pre_reset:		idedisk_pre_reset,
 	capacity:		idedisk_capacity,
 	special:		idedisk_special,
 	proc:			idedisk_proc,
-	driver_init:		idedisk_init,
 	driver_reinit:		idedisk_reinit,
 };
 
 MODULE_DESCRIPTION("ATA DISK Driver");
 
-int idedisk_reinit (ide_drive_t *drive)
+static int idedisk_reinit(ide_drive_t *drive)
 {
 	int failed = 0;
 
@@ -1072,18 +1089,19 @@
 		printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
 		return 1;
 	}
-	DRIVER(drive)->busy++;
+
+	ata_ops(drive)->busy++;
 	idedisk_setup(drive);
 	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
 		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
-		(void) idedisk_cleanup(drive);
-		DRIVER(drive)->busy--;
+		idedisk_cleanup(drive);
+		ata_ops(drive)->busy--;
 		return 1;
 	}
-	DRIVER(drive)->busy--;
+	ata_ops(drive)->busy--;
 	failed--;
 
-	ide_register_module(&idedisk_driver);
+	revalidate_drives();
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -1093,7 +1111,7 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL) {
+	while ((drive = ide_scan_devices(ATA_DISK, "ide-disk", &idedisk_driver, failed)) != NULL) {
 		if (idedisk_cleanup (drive)) {
 			printk (KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name);
 			failed++;
@@ -1105,7 +1123,6 @@
 			ide_remove_proc_entries(drive->proc, idedisk_proc);
 #endif
 	}
-	ide_unregister_module(&idedisk_driver);
 }
 
 int idedisk_init (void)
@@ -1114,23 +1131,23 @@
 	int failed = 0;
 	
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, NULL, failed++)) != NULL) {
+	while ((drive = ide_scan_devices(ATA_DISK, "ide-disk", NULL, failed++)) != NULL) {
 		if (ide_register_subdriver (drive, &idedisk_driver)) {
 			printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
 			continue;
 		}
-		DRIVER(drive)->busy++;
+		ata_ops(drive)->busy++;
 		idedisk_setup(drive);
 		if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
 			printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
-			(void) idedisk_cleanup(drive);
-			DRIVER(drive)->busy--;
+			idedisk_cleanup(drive);
+			ata_ops(drive)->busy--;
 			continue;
 		}
-		DRIVER(drive)->busy--;
+		ata_ops(drive)->busy--;
 		failed--;
 	}
-	ide_register_module(&idedisk_driver);
+	revalidate_drives();
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
diff -urN linux-2.5.6-pre1/drivers/ide/ide-dma.c linux-2.5.6-pre2/drivers/ide/ide-dma.c
--- linux-2.5.6-pre1/drivers/ide/ide-dma.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/drivers/ide/ide-dma.c	Thu Feb 28 13:34:21 2002
@@ -470,7 +470,7 @@
 	ide_hwif_t *hwif = HWIF(drive);
 
 #ifdef CONFIG_IDEDMA_ONLYDISK
-	if (drive->media != ide_disk)
+	if (drive->type != ATA_DISK)
 		config_allows_dma = 0;
 #endif
 
@@ -555,7 +555,7 @@
 {
 	u64 addr = BLK_BOUNCE_HIGH;
 
-	if (on && drive->media == ide_disk && HWIF(drive)->highmem) {
+	if (on && drive->type == ATA_DISK && HWIF(drive)->highmem) {
 		if (!PCI_DMA_BUS_IS_PHYS)
 			addr = BLK_BOUNCE_ANY;
 		else
@@ -613,7 +613,7 @@
 			outb(reading, dma_base);			/* specify r/w */
 			outb(inb(dma_base+2)|6, dma_base+2);		/* clear INTR & ERROR flags */
 			drive->waiting_for_dma = 1;
-			if (drive->media != ide_disk)
+			if (drive->type != ATA_DISK)
 				return 0;
 #ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
 			ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL);	/* issue cmd to drive */
diff -urN linux-2.5.6-pre1/drivers/ide/ide-features.c linux-2.5.6-pre2/drivers/ide/ide-features.c
--- linux-2.5.6-pre1/drivers/ide/ide-features.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/ide/ide-features.c	Thu Feb 28 13:34:21 2002
@@ -70,22 +70,6 @@
 }
 
 /*
- *
- */
-char *ide_media_verbose (ide_drive_t *drive)
-{
-	switch (drive->media) {
-		case ide_scsi:		return("scsi   ");
-		case ide_disk:		return("disk   ");
-		case ide_optical:	return("optical");
-		case ide_cdrom:		return("cdrom  ");
-		case ide_tape:		return("tape   ");
-		case ide_floppy:	return("floppy ");
-		default:		return("???????");
-	}
-}
-
-/*
  * A Verbose noise maker for debugging on the attempted dmaing calls.
  */
 char *ide_dmafunc_verbose (ide_dma_action_t dmafunc)
diff -urN linux-2.5.6-pre1/drivers/ide/ide-floppy.c linux-2.5.6-pre2/drivers/ide/ide-floppy.c
--- linux-2.5.6-pre1/drivers/ide/ide-floppy.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/drivers/ide/ide-floppy.c	Thu Feb 28 13:34:21 2002
@@ -1827,14 +1827,6 @@
 }
 
 /*
- *	Revalidate the new media. Should set blk_size[]
- */
-static void idefloppy_revalidate (ide_drive_t *drive)
-{
-	ide_revalidate_drive(drive);
-}
-
-/*
  *	Return the current floppy capacity to ide.c.
  */
 static unsigned long idefloppy_capacity (ide_drive_t *drive)
@@ -2046,18 +2038,13 @@
 
 #endif	/* CONFIG_PROC_FS */
 
-int idefloppy_init(void);
-int idefloppy_reinit(ide_drive_t *drive);
+static int idefloppy_reinit(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
  */
-static ide_driver_t idefloppy_driver = {
-	name:			"ide-floppy",
-	media:			ide_floppy,
-	busy:			0,
-	supports_dma:		1,
-	supports_dsc_overlap:	0,
+static struct ata_operations idefloppy_driver = {
+	owner:			THIS_MODULE,
 	cleanup:		idefloppy_cleanup,
 	standby:		NULL,
 	flushcache:		NULL,
@@ -2067,22 +2054,21 @@
 	open:			idefloppy_open,
 	release:		idefloppy_release,
 	media_change:		idefloppy_media_change,
-	revalidate:		idefloppy_revalidate,
+	revalidate:		ide_revalidate_drive,
 	pre_reset:		NULL,
 	capacity:		idefloppy_capacity,
 	special:		NULL,
 	proc:			idefloppy_proc,
-	driver_init:		idefloppy_init,
 	driver_reinit:		idefloppy_reinit,
 };
 
-int idefloppy_reinit (ide_drive_t *drive)
+static int idefloppy_reinit (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy;
 	int failed = 0;
 
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
+	while ((drive = ide_scan_devices(ATA_FLOPPY, "ide-floppy", NULL, failed++)) != NULL) {
 		if (!idefloppy_identify_device (drive, drive->id)) {
 			printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
 			continue;
@@ -2100,12 +2086,15 @@
 			kfree (floppy);
 			continue;
 		}
-		DRIVER(drive)->busy++;
+
+		/* ATA-PATTERN */
+		ata_ops(drive)->busy++;
 		idefloppy_setup (drive, floppy);
-		DRIVER(drive)->busy--;
+		ata_ops(drive)->busy--;
+
 		failed--;
 	}
-	ide_register_module(&idefloppy_driver);
+	revalidate_drives();
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -2117,7 +2106,7 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, &idefloppy_driver, failed)) != NULL) {
+	while ((drive = ide_scan_devices(ATA_FLOPPY, "ide-floppy", &idefloppy_driver, failed)) != NULL) {
 		if (idefloppy_cleanup (drive)) {
 			printk ("%s: cleanup_module() called while still busy\n", drive->name);
 			failed++;
@@ -2130,7 +2119,6 @@
 			ide_remove_proc_entries(drive->proc, idefloppy_proc);
 #endif
 	}
-	ide_unregister_module(&idefloppy_driver);
 }
 
 /*
@@ -2144,7 +2132,7 @@
 
 	printk("ide-floppy driver " IDEFLOPPY_VERSION "\n");
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
+	while ((drive = ide_scan_devices (ATA_FLOPPY, "ide-floppy", NULL, failed++)) != NULL) {
 		if (!idefloppy_identify_device (drive, drive->id)) {
 			printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
 			continue;
@@ -2162,12 +2150,14 @@
 			kfree (floppy);
 			continue;
 		}
-		DRIVER(drive)->busy++;
+		/* ATA-PATTERN */
+		ata_ops(drive)->busy++;
 		idefloppy_setup (drive, floppy);
-		DRIVER(drive)->busy--;
+		ata_ops(drive)->busy--;
+
 		failed--;
 	}
-	ide_register_module(&idefloppy_driver);
+	revalidate_drives();
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
diff -urN linux-2.5.6-pre1/drivers/ide/ide-geometry.c linux-2.5.6-pre2/drivers/ide/ide-geometry.c
--- linux-2.5.6-pre1/drivers/ide/ide-geometry.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/drivers/ide/ide-geometry.c	Thu Feb 28 13:34:21 2002
@@ -1,94 +1,16 @@
 /*
  * linux/drivers/ide/ide-geometry.c
+ *
+ * Sun Feb 24 23:13:03 CET 2002: Patch by Andries Brouwer to remove the
+ * confused CMOS probe applied. This is solving more problems then it my
+ * (unexpectedly) introduce.
  */
+
 #include <linux/config.h>
 #include <linux/ide.h>
 #include <linux/mc146818rtc.h>
 #include <asm/io.h>
 
-#ifdef CONFIG_BLK_DEV_IDE
-
-/*
- * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
- * controller that is BIOS compatible with ST-506, and thus showing up in our
- * BIOS table, but not register compatible, and therefore not present in CMOS.
- *
- * Furthermore, we will assume that our ST-506 drives <if any> are the primary
- * drives in the system -- the ones reflected as drive 1 or 2.  The first
- * drive is stored in the high nibble of CMOS byte 0x12, the second in the low
- * nibble.  This will be either a 4 bit drive type or 0xf indicating use byte
- * 0x19 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.  A non-zero value
- * means we have an AT controller hard disk for that drive.
- *
- * Of course, there is no guarantee that either drive is actually on the
- * "primary" IDE interface, but we don't bother trying to sort that out here.
- * If a drive is not actually on the primary interface, then these parameters
- * will be ignored.  This results in the user having to supply the logical
- * drive geometry as a boot parameter for each drive not on the primary i/f.
- */
-/*
- * The only "perfect" way to handle this would be to modify the setup.[cS] code
- * to do BIOS calls Int13h/Fn08h and Int13h/Fn48h to get all of the drive info
- * for us during initialization.  I have the necessary docs -- any takers?  -ml
- */
-/*
- * I did this, but it doesnt work - there is no reasonable way to find the
- * correspondence between the BIOS numbering of the disks and the Linux
- * numbering. -aeb
- *
- * The code below is bad. One of the problems is that drives 1 and 2
- * may be SCSI disks (even when IDE disks are present), so that
- * the geometry we read here from BIOS is attributed to the wrong disks.
- * Consequently, also the former "drive->present = 1" below was a mistake.
- *
- * Eventually the entire routine below should be removed.
- *
- * 17-OCT-2000 rjohnson@analogic.com Added spin-locks for reading CMOS
- * chip.
- */
-
-void probe_cmos_for_drives (ide_hwif_t *hwif)
-{
-#ifdef __i386__
-	extern struct drive_info_struct drive_info;
-	byte cmos_disks, *BIOS = (byte *) &drive_info;
-	int unit;
-	unsigned long flags;
-
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (hwif->chipset == ide_pdc4030 && hwif->channel != 0)
-		return;
-#endif /* CONFIG_BLK_DEV_PDC4030 */
-	spin_lock_irqsave(&rtc_lock, flags);
-	cmos_disks = CMOS_READ(0x12);
-	spin_unlock_irqrestore(&rtc_lock, flags);
-	/* Extract drive geometry from CMOS+BIOS if not already setup */
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		ide_drive_t *drive = &hwif->drives[unit];
-
-		if ((cmos_disks & (0xf0 >> (unit*4)))
-		   && !drive->present && !drive->nobios) {
-			unsigned short cyl = *(unsigned short *)BIOS;
-			unsigned char head = *(BIOS+2);
-			unsigned char sect = *(BIOS+14);
-			if (cyl > 0 && head > 0 && sect > 0 && sect < 64) {
-				drive->cyl   = drive->bios_cyl  = cyl;
-				drive->head  = drive->bios_head = head;
-				drive->sect  = drive->bios_sect = sect;
-				drive->ctl   = *(BIOS+8);
-			} else {
-				printk("hd%c: C/H/S=%d/%d/%d from BIOS ignored\n",
-				       unit+'a', cyl, head, sect);
-			}
-		}
-
-		BIOS += 16;
-	}
-#endif
-}
-#endif /* CONFIG_BLK_DEV_IDE */
-
-
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 
 extern ide_drive_t * get_info_ptr(kdev_t);
@@ -105,14 +27,14 @@
 	unsigned long total;
 
 	/*
-	 * The specs say: take geometry as obtained from Identify,
-	 * compute total capacity C*H*S from that, and truncate to
-	 * 1024*255*63. Now take S=63, H the first in the sequence
-	 * 4, 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total.
-	 * [Please tell aeb@cwi.nl in case this computes a
-	 * geometry different from what OnTrack uses.]
+	 * The specs say: take geometry as obtained from Identify, compute
+	 * total capacity C*H*S from that, and truncate to 1024*255*63. Now
+	 * take S=63, H the first in the sequence 4, 8, 16, 32, 64, 128, 255
+	 * such that 63*H*1024 >= total.  [Please tell aeb@cwi.nl in case this
+	 * computes a geometry different from what OnTrack uses.]
 	 */
-	total = DRIVER(drive)->capacity(drive);
+
+	total = ata_ops(drive)->capacity(drive);
 
 	*s = 63;
 
diff -urN linux-2.5.6-pre1/drivers/ide/ide-pci.c linux-2.5.6-pre2/drivers/ide/ide-pci.c
--- linux-2.5.6-pre1/drivers/ide/ide-pci.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/ide/ide-pci.c	Thu Feb 28 13:34:21 2002
@@ -9,7 +9,7 @@
 
 /*
  *  This module provides support for automatic detection and
- *  configuration of all PCI IDE interfaces present in a system.  
+ *  configuration of all PCI IDE interfaces present in a system.
  */
 
 /*
@@ -32,339 +32,139 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#define DEVID_PIIXa	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_0})
-#define DEVID_PIIXb	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_1})
-#define DEVID_MPIIX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371MX})
-#define DEVID_PIIX3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371SB_1})
-#define DEVID_PIIX4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371AB})
-#define DEVID_ICH0	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801AB_1})
-#define DEVID_PIIX4E2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82443MX_1})
-#define DEVID_ICH	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801AA_1})
-#define DEVID_PIIX4U2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82372FB_1})
-#define DEVID_PIIX4NX	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82451NX})
-#define DEVID_ICH2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_9})
-#define DEVID_ICH2M	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_8})
-#define DEVID_ICH3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_10})
-#define DEVID_VIA_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C561})
-#define DEVID_MR_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C576_1})
-#define DEVID_VP_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_1})
-#define DEVID_PDC20246	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
-#define DEVID_PDC20262	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262})
-#define DEVID_PDC20265	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265})
-#define DEVID_PDC20267	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267})
-#define DEVID_PDC20268  ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268})
-#define DEVID_PDC20268R ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R})
-#define DEVID_PDC20269	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269})
-#define DEVID_PDC20275	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275})
-#define DEVID_RZ1000	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1000})
-#define DEVID_RZ1001	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_RZ1001})
-#define DEVID_SAMURAI	((ide_pci_devid_t){PCI_VENDOR_ID_PCTECH,  PCI_DEVICE_ID_PCTECH_SAMURAI_IDE})
-#define DEVID_CMD640	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_640})
-#define DEVID_CMD643	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_643})
-#define DEVID_CMD646	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_646})
-#define DEVID_CMD648	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_648})
-#define DEVID_CMD649	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_649})
-#define DEVID_CMD680	((ide_pci_devid_t){PCI_VENDOR_ID_CMD,     PCI_DEVICE_ID_CMD_680})
-#define DEVID_SIS5513	((ide_pci_devid_t){PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_5513})
-#define DEVID_OPTI621	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C621})
-#define DEVID_OPTI621V	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C558})
-#define DEVID_OPTI621X	((ide_pci_devid_t){PCI_VENDOR_ID_OPTI,    PCI_DEVICE_ID_OPTI_82C825})
-#define DEVID_TRM290	((ide_pci_devid_t){PCI_VENDOR_ID_TEKRAM,  PCI_DEVICE_ID_TEKRAM_DC290})
-#define DEVID_NS87410	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87410})
-#define DEVID_NS87415	((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87415})
-#define DEVID_HT6565	((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK,  PCI_DEVICE_ID_HOLTEK_6565})
-#define DEVID_AEC6210	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP850UF})
-#define DEVID_AEC6260	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP860})
-#define DEVID_AEC6260R	((ide_pci_devid_t){PCI_VENDOR_ID_ARTOP,   PCI_DEVICE_ID_ARTOP_ATP860R})
-#define DEVID_W82C105	((ide_pci_devid_t){PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105})
-#define DEVID_UM8673F	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8673F})
-#define DEVID_UM8886A	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886A})
-#define DEVID_UM8886BF	((ide_pci_devid_t){PCI_VENDOR_ID_UMC,     PCI_DEVICE_ID_UMC_UM8886BF})
-#define DEVID_HPT34X	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT343})
-#define DEVID_HPT366	((ide_pci_devid_t){PCI_VENDOR_ID_TTI,     PCI_DEVICE_ID_TTI_HPT366})
-#define DEVID_ALI15X3	((ide_pci_devid_t){PCI_VENDOR_ID_AL,      PCI_DEVICE_ID_AL_M5229})
-#define DEVID_CY82C693	((ide_pci_devid_t){PCI_VENDOR_ID_CONTAQ,  PCI_DEVICE_ID_CONTAQ_82C693})
-#define DEVID_HINT	((ide_pci_devid_t){0x3388,                0x8013})
-#define DEVID_CS5530	((ide_pci_devid_t){PCI_VENDOR_ID_CYRIX,   PCI_DEVICE_ID_CYRIX_5530_IDE})
-#define DEVID_AMD7401	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_COBRA_7401})
-#define DEVID_AMD7409	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7409})
-#define DEVID_AMD7411	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7411})
-#define DEVID_AMD7441	((ide_pci_devid_t){PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7441})
-#define DEVID_PDCADMA	((ide_pci_devid_t){PCI_VENDOR_ID_PDC,     PCI_DEVICE_ID_PDC_1841})
-#define DEVID_SLC90E66	((ide_pci_devid_t){PCI_VENDOR_ID_EFAR,    PCI_DEVICE_ID_EFAR_SLC90E66_1})
-#define DEVID_OSB4	((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE})
-#define DEVID_CSB5	((ide_pci_devid_t){PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE})
-#define DEVID_ITE8172G	((ide_pci_devid_t){PCI_VENDOR_ID_ITE,     PCI_DEVICE_ID_ITE_IT8172G})
+/* Missing PCI device IDs: */
+#define PCI_VENDOR_ID_HINT 0x3388
+#define PCI_DEVICE_ID_HINT 0x8013
 
 #define	IDE_IGNORE	((void *)-1)
 #define IDE_NO_DRIVER	((void *)-2)
 
 #ifdef CONFIG_BLK_DEV_AEC62XX
-extern unsigned int pci_init_aec62xx(struct pci_dev *, const char *);
+extern unsigned int pci_init_aec62xx(struct pci_dev *);
 extern unsigned int ata66_aec62xx(ide_hwif_t *);
 extern void ide_init_aec62xx(ide_hwif_t *);
 extern void ide_dmacapable_aec62xx(ide_hwif_t *, unsigned long);
-#define PCI_AEC62XX	&pci_init_aec62xx
-#define ATA66_AEC62XX	&ata66_aec62xx
-#define INIT_AEC62XX	&ide_init_aec62xx
-#define DMA_AEC62XX	&ide_dmacapable_aec62xx
-#else
-#define PCI_AEC62XX	NULL
-#define ATA66_AEC62XX	NULL
-#define INIT_AEC62XX	IDE_NO_DRIVER
-#define DMA_AEC62XX	NULL
 #endif
 
 #ifdef CONFIG_BLK_DEV_ALI15X3
-extern unsigned int pci_init_ali15x3(struct pci_dev *, const char *);
+extern unsigned int pci_init_ali15x3(struct pci_dev *);
 extern unsigned int ata66_ali15x3(ide_hwif_t *);
 extern void ide_init_ali15x3(ide_hwif_t *);
 extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long);
-#define PCI_ALI15X3	&pci_init_ali15x3
-#define ATA66_ALI15X3	&ata66_ali15x3
-#define INIT_ALI15X3	&ide_init_ali15x3
-#define DMA_ALI15X3	&ide_dmacapable_ali15x3
-#else
-#define PCI_ALI15X3	NULL
-#define ATA66_ALI15X3	NULL
-#define INIT_ALI15X3	IDE_NO_DRIVER
-#define DMA_ALI15X3	NULL
 #endif
 
 #ifdef CONFIG_BLK_DEV_AMD74XX
-extern unsigned int pci_init_amd74xx(struct pci_dev *, const char *);
+extern unsigned int pci_init_amd74xx(struct pci_dev *);
 extern unsigned int ata66_amd74xx(ide_hwif_t *);
 extern void ide_init_amd74xx(ide_hwif_t *);
 extern void ide_dmacapable_amd74xx(ide_hwif_t *, unsigned long);
-#define PCI_AMD74XX	&pci_init_amd74xx
-#define ATA66_AMD74XX	&ata66_amd74xx
-#define INIT_AMD74XX	&ide_init_amd74xx
-#define DMA_AMD74XX	&ide_dmacapable_amd74xx
-#else
-#define PCI_AMD74XX	NULL
-#define ATA66_AMD74XX	NULL
-#define INIT_AMD74XX	IDE_NO_DRIVER
-#define DMA_AMD74XX	NULL
 #endif
 
 #ifdef CONFIG_BLK_DEV_CMD64X
-extern unsigned int pci_init_cmd64x(struct pci_dev *, const char *);
+extern unsigned int pci_init_cmd64x(struct pci_dev *);
 extern unsigned int ata66_cmd64x(ide_hwif_t *);
 extern void ide_init_cmd64x(ide_hwif_t *);
 extern void ide_dmacapable_cmd64x(ide_hwif_t *, unsigned long);
-#define PCI_CMD64X	&pci_init_cmd64x
-#define ATA66_CMD64X	&ata66_cmd64x
-#define INIT_CMD64X	&ide_init_cmd64x
-#else
-#define PCI_CMD64X	NULL
-#define ATA66_CMD64X	NULL
-#ifdef __sparc_v9__
-#define INIT_CMD64X	IDE_IGNORE
-#else
-#define INIT_CMD64X	IDE_NO_DRIVER
-#endif
 #endif
 
 #ifdef CONFIG_BLK_DEV_CY82C693
-extern unsigned int pci_init_cy82c693(struct pci_dev *, const char *);
+extern unsigned int pci_init_cy82c693(struct pci_dev *);
 extern void ide_init_cy82c693(ide_hwif_t *);
-#define PCI_CY82C693	&pci_init_cy82c693
-#define INIT_CY82C693	&ide_init_cy82c693
-#else
-#define PCI_CY82C693	NULL
-#define INIT_CY82C693	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_CS5530
-extern unsigned int pci_init_cs5530(struct pci_dev *, const char *);
+extern unsigned int pci_init_cs5530(struct pci_dev *);
 extern void ide_init_cs5530(ide_hwif_t *);
-#define PCI_CS5530	&pci_init_cs5530
-#define INIT_CS5530	&ide_init_cs5530
-#else
-#define PCI_CS5530	NULL
-#define INIT_CS5530	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_HPT34X
-extern unsigned int pci_init_hpt34x(struct pci_dev *, const char *);
+extern unsigned int pci_init_hpt34x(struct pci_dev *);
 extern void ide_init_hpt34x(ide_hwif_t *);
-#define PCI_HPT34X	&pci_init_hpt34x
-#define INIT_HPT34X	&ide_init_hpt34x
-#else
-#define PCI_HPT34X	NULL
-#define INIT_HPT34X	IDE_IGNORE
 #endif
 
 #ifdef CONFIG_BLK_DEV_HPT366
 extern byte hpt363_shared_irq;
 extern byte hpt363_shared_pin;
-extern unsigned int pci_init_hpt366(struct pci_dev *, const char *);
+
+extern unsigned int pci_init_hpt366(struct pci_dev *);
 extern unsigned int ata66_hpt366(ide_hwif_t *);
 extern void ide_init_hpt366(ide_hwif_t *);
 extern void ide_dmacapable_hpt366(ide_hwif_t *, unsigned long);
-#define PCI_HPT366	&pci_init_hpt366
-#define ATA66_HPT366	&ata66_hpt366
-#define INIT_HPT366	&ide_init_hpt366
-#define DMA_HPT366	&ide_dmacapable_hpt366
 #else
+/* FIXME: those have to be killed */
 static byte hpt363_shared_irq;
 static byte hpt363_shared_pin;
-#define PCI_HPT366	NULL
-#define ATA66_HPT366	NULL
-#define INIT_HPT366	IDE_NO_DRIVER
-#define DMA_HPT366	NULL
 #endif
 
 #ifdef CONFIG_BLK_DEV_NS87415
 extern void ide_init_ns87415(ide_hwif_t *);
-#define INIT_NS87415	&ide_init_ns87415
-#else
-#define INIT_NS87415	IDE_IGNORE
 #endif
 
 #ifdef CONFIG_BLK_DEV_OPTI621
 extern void ide_init_opti621(ide_hwif_t *);
-#define INIT_OPTI621	&ide_init_opti621
-#else
-#define INIT_OPTI621	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_PDC_ADMA
-extern unsigned int pci_init_pdcadma(struct pci_dev *, const char *);
+extern unsigned int pci_init_pdcadma(struct pci_dev *);
 extern unsigned int ata66_pdcadma(ide_hwif_t *);
 extern void ide_init_pdcadma(ide_hwif_t *);
 extern void ide_dmacapable_pdcadma(ide_hwif_t *, unsigned long);
-#define PCI_PDCADMA	&pci_init_pdcadma
-#define ATA66_PDCADMA	&ata66_pdcadma
-#define INIT_PDCADMA	&ide_init_pdcadma
-#define DMA_PDCADMA	&ide_dmacapable_pdcadma
-#else
-#define PCI_PDCADMA	IDE_IGNORE
-#define ATA66_PDCADMA	IDE_IGNORE
-#define INIT_PDCADMA	IDE_IGNORE
-#define DMA_PDCADMA	IDE_IGNORE
 #endif
 
 #ifdef CONFIG_BLK_DEV_PDC202XX
-extern unsigned int pci_init_pdc202xx(struct pci_dev *, const char *);
+extern unsigned int pci_init_pdc202xx(struct pci_dev *);
 extern unsigned int ata66_pdc202xx(ide_hwif_t *);
 extern void ide_init_pdc202xx(ide_hwif_t *);
-#define PCI_PDC202XX	&pci_init_pdc202xx
-#define ATA66_PDC202XX	&ata66_pdc202xx
-#define INIT_PDC202XX	&ide_init_pdc202xx
-#else
-#define PCI_PDC202XX	IDE_IGNORE
-#define ATA66_PDC202XX	IDE_IGNORE
-#define INIT_PDC202XX	IDE_IGNORE
 #endif
 
 #ifdef CONFIG_BLK_DEV_PIIX
-extern unsigned int pci_init_piix(struct pci_dev *, const char *);
+extern unsigned int pci_init_piix(struct pci_dev *);
 extern unsigned int ata66_piix(ide_hwif_t *);
 extern void ide_init_piix(ide_hwif_t *);
-#define PCI_PIIX	&pci_init_piix
-#define ATA66_PIIX	&ata66_piix
-#define INIT_PIIX	&ide_init_piix
-#else
-#define PCI_PIIX	NULL
-#define ATA66_PIIX	NULL
-#define INIT_PIIX	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_IT8172
-extern unsigned int pci_init_it8172(struct pci_dev *, const char *);
-extern unsigned int ata66_it8172(ide_hwif_t *);
+extern unsigned int pci_init_it8172(struct pci_dev *);
 extern void ide_init_it8172(ide_hwif_t *);
-#define PCI_IT8172	&pci_init_it8172
-#define INIT_IT8172	&ide_init_it8172
-#else
-#define PCI_IT8172	NULL
-#define ATA66_IT8172	NULL
-#define INIT_IT8172	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_RZ1000
 extern void ide_init_rz1000(ide_hwif_t *);
-#define INIT_RZ1000	&ide_init_rz1000
-#else
-#define INIT_RZ1000	IDE_IGNORE
 #endif
 
-#define INIT_SAMURAI	NULL
-
 #ifdef CONFIG_BLK_DEV_SVWKS
-extern unsigned int pci_init_svwks(struct pci_dev *, const char *);
+extern unsigned int pci_init_svwks(struct pci_dev *);
 extern unsigned int ata66_svwks(ide_hwif_t *);
 extern void ide_init_svwks(ide_hwif_t *);
-#define PCI_SVWKS	&pci_init_svwks
-#define ATA66_SVWKS	&ata66_svwks
-#define INIT_SVWKS	&ide_init_svwks
-#else
-#define PCI_SVWKS	NULL
-#define ATA66_SVWKS	NULL
-#define INIT_SVWKS	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_SIS5513
-extern unsigned int pci_init_sis5513(struct pci_dev *, const char *);
+extern unsigned int pci_init_sis5513(struct pci_dev *);
 extern unsigned int ata66_sis5513(ide_hwif_t *);
 extern void ide_init_sis5513(ide_hwif_t *);
-#define PCI_SIS5513	&pci_init_sis5513
-#define ATA66_SIS5513	&ata66_sis5513
-#define INIT_SIS5513	&ide_init_sis5513
-#else
-#define PCI_SIS5513	NULL
-#define ATA66_SIS5513	NULL
-#define INIT_SIS5513	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_SLC90E66
-extern unsigned int pci_init_slc90e66(struct pci_dev *, const char *);
+extern unsigned int pci_init_slc90e66(struct pci_dev *);
 extern unsigned int ata66_slc90e66(ide_hwif_t *);
 extern void ide_init_slc90e66(ide_hwif_t *);
-#define PCI_SLC90E66	&pci_init_slc90e66
-#define ATA66_SLC90E66	&ata66_slc90e66
-#define INIT_SLC90E66	&ide_init_slc90e66
-#else
-#define PCI_SLC90E66	NULL
-#define ATA66_SLC90E66	NULL
-#define INIT_SLC90E66	IDE_NO_DRIVER
 #endif
 
 #ifdef CONFIG_BLK_DEV_SL82C105
-extern unsigned int pci_init_sl82c105(struct pci_dev *, const char *);
+extern unsigned int pci_init_sl82c105(struct pci_dev *);
 extern void dma_init_sl82c105(ide_hwif_t *, unsigned long);
 extern void ide_init_sl82c105(ide_hwif_t *);
-#define PCI_W82C105	&pci_init_sl82c105
-#define DMA_W82C105	&dma_init_sl82c105
-#define INIT_W82C105	&ide_init_sl82c105
-#else
-#define PCI_W82C105	NULL
-#define DMA_W82C105	NULL
-#define INIT_W82C105	IDE_IGNORE
 #endif
 
 #ifdef CONFIG_BLK_DEV_TRM290
 extern void ide_init_trm290(ide_hwif_t *);
-#define INIT_TRM290	&ide_init_trm290
-#else
-#define INIT_TRM290	IDE_IGNORE
 #endif
 
 #ifdef CONFIG_BLK_DEV_VIA82CXXX
-extern unsigned int pci_init_via82cxxx(struct pci_dev *, const char *);
+extern unsigned int pci_init_via82cxxx(struct pci_dev *);
 extern unsigned int ata66_via82cxxx(ide_hwif_t *);
 extern void ide_init_via82cxxx(ide_hwif_t *);
 extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long);
-#define PCI_VIA82CXXX	&pci_init_via82cxxx
-#define ATA66_VIA82CXXX	&ata66_via82cxxx
-#define INIT_VIA82CXXX	&ide_init_via82cxxx
-#define DMA_VIA82CXXX	&ide_dmacapable_via82cxxx
-#else
-#define PCI_VIA82CXXX	NULL
-#define ATA66_VIA82CXXX	NULL
-#define INIT_VIA82CXXX	IDE_NO_DRIVER
-#define DMA_VIA82CXXX	NULL
 #endif
 
 typedef struct ide_pci_enablebit_s {
@@ -373,117 +173,158 @@
 	byte	val;	/* value of masked reg when "enabled" */
 } ide_pci_enablebit_t;
 
+/* Flags used to untangle quirk handling.
+ */
+#define ATA_F_DMA	0x01
+#define ATA_F_NODMA	0x02	/* no DMA mode supported at all */
+#define ATA_F_NOADMA	0x04	/* DMA has to be enabled explicitely */
+#define ATA_F_FIXIRQ	0x08	/* fixed irq wiring */
+#define ATA_F_SER	0x10	/* serialize on first and second channel interrupts */
+#define ATA_F_IRQ	0x20	/* trust IRQ information from config */
+#define ATA_F_PHACK	0x40	/* apply PROMISE hacks */
+#define ATA_F_HPTHACK	0x80	/* apply HPT366 hacks */
+
 typedef struct ide_pci_device_s {
-	ide_pci_devid_t		devid;
-	char			*name;
-	unsigned int		(*init_chipset)(struct pci_dev *dev, const char *name);
+	unsigned short		vendor;
+	unsigned short		device;
+	unsigned int		(*init_chipset)(struct pci_dev *dev);
 	unsigned int		(*ata66_check)(ide_hwif_t *hwif);
-	void 			(*init_hwif)(ide_hwif_t *hwif);
+	void			(*init_hwif)(ide_hwif_t *hwif);
 	void			(*dma_init)(ide_hwif_t *hwif, unsigned long dmabase);
 	ide_pci_enablebit_t	enablebits[2];
-	byte			bootable;
+	unsigned int		bootable;
 	unsigned int		extra;
+	unsigned int		flags;
 } ide_pci_device_t;
 
-static ide_pci_device_t ide_pci_chipsets[] __initdata = {
-	{DEVID_PIIXa,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIXb,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_MPIIX,	"MPIIX",	NULL,		NULL,		INIT_PIIX,	NULL,		{{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX3,	"PIIX3",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIX4,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_ICH0,	"ICH0",		PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4E2,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH,	"ICH",		PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4U2,	"PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4NX,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH2,	"ICH2",		PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH2M,	"ICH2-M",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH3,	"ICH3",		PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_VIA_IDE,	"VIA_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_MR_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
-	{DEVID_VP_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
-#ifdef CONFIG_PDC202XX_FORCE
-        {DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
-        {DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-        {DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	48 },
-        {DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-#else /* !CONFIG_PDC202XX_FORCE */
-	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
-	{DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-	{DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-	{DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
+static ide_pci_device_t pci_chipsets[] __initdata = {
+#ifdef CONFIG_BLK_DEV_PIIX
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, NULL, NULL, ide_init_piix,	NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, NULL, NULL, ide_init_piix,	NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, NULL, NULL, ide_init_piix, NULL, {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}}, ON_BOARD, 0, ATA_F_NODMA },
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, pci_init_piix, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, pci_init_piix, NULL,	ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1, pci_init_piix, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1, pci_init_piix, NULL, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1, pci_init_piix, ata66_piix, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1, pci_init_piix, ata66_piix, ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_init_piix, NULL,	ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, ATA_F_NOADMA },
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9, pci_init_piix, ata66_piix,	ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8, pci_init_piix, ata66_piix,	ide_init_piix, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, pci_init_piix, ata66_piix, ide_init_piix,	NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
+#endif
+#ifdef CONFIG_BLK_DEV_VIA82CXXX
+	{PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1,	pci_init_via82cxxx, ata66_via82cxxx, ide_init_via82cxxx, ide_dmacapable_via82cxxx, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0, ATA_F_NOADMA },
+	{PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1,	pci_init_via82cxxx, ata66_via82cxxx, ide_init_via82cxxx, ide_dmacapable_via82cxxx, {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, ON_BOARD, 0, ATA_F_NOADMA },
 #endif
-	{DEVID_PDC20268,"PDC20268",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
+#ifdef CONFIG_BLK_DEV_PDC202XX
+# ifdef CONFIG_PDC202XX_FORCE
+        {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, pci_init_pdc202xx, NULL, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD,	16, ATA_F_IRQ | ATA_F_DMA },
+        {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48, ATA_F_IRQ | ATA_F_PHACK | ATA_F_DMA},
+        {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 48, ATA_F_IRQ | ATA_F_PHACK | ATA_F_DMA},
+        {PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 48, ATA_F_IRQ | ATA_F_DMA },
+# else
+	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, pci_init_pdc202xx, NULL, ide_init_pdc202xx, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 16, ATA_F_IRQ | ATA_F_DMA },
+	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48, ATA_F_IRQ | ATA_F_PHACK | ATA_F_DMA },
+	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48, ATA_F_IRQ | ATA_F_PHACK  | ATA_F_DMA },
+	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x50,0x02,0x02}, {0x50,0x04,0x04}}, OFF_BOARD, 48, ATA_F_IRQ  | ATA_F_DMA },
+# endif
+	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
 	/* Promise used a different PCI ident for the raid card apparently to try and
 	   prevent Linux detecting it and using our own raid code. We want to detect
 	   it for the ataraid drivers, so we have to list both here.. */
-	{DEVID_PDC20268R,"PDC20270",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20269,"PDC20269",	PCI_PDC202XX,	ATA66_PDC202XX,	 INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20275,"PDC20275",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_RZ1000,	"RZ1000",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_RZ1001,	"RZ1001",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_SAMURAI,	"SAMURAI",	NULL,		NULL,		INIT_SAMURAI,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD640,	"CMD640",	NULL,		NULL,		IDE_IGNORE,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87410,	"NS87410",	NULL,		NULL,		NULL,		NULL,		{{0x43,0x08,0x08}, {0x47,0x08,0x08}}, 	ON_BOARD,	0 },
-	{DEVID_SIS5513,	"SIS5513",	PCI_SIS5513,	ATA66_SIS5513,	INIT_SIS5513,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	ON_BOARD,	0 },
-	{DEVID_CMD643,	"CMD643",	PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD646,	"CMD646",	PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x51,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_CMD648,	"CMD648",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD649,	"CMD649",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD680,	"CMD680",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_HT6565,	"HT6565",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_OPTI621,	"OPTI621",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_OPTI621X,"OPTI621X",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_TRM290,	"TRM290",	NULL,		NULL,		INIT_TRM290,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87415,	"NS87415",	NULL,		NULL,		INIT_NS87415,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_AEC6210,	"AEC6210",	PCI_AEC62XX,	NULL,		INIT_AEC62XX,	DMA_AEC62XX,	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	OFF_BOARD,	0 },
-	{DEVID_AEC6260,	"AEC6260",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	0 },
-	{DEVID_AEC6260R,"AEC6260R",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},	OFF_BOARD,	0 },
-	{DEVID_W82C105,	"W82C105",	PCI_W82C105,	NULL,		INIT_W82C105,	DMA_W82C105,	{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0 },
-	{DEVID_UM8673F,	"UM8673F",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_UM8886A,	"UM8886A",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_UM8886BF,"UM8886BF",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_HPT34X,	"HPT34X",	PCI_HPT34X,	NULL,		INIT_HPT34X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	16 },
-	{DEVID_HPT366,	"HPT366",	PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	240 },
-	{DEVID_ALI15X3,	"ALI15X3",	PCI_ALI15X3,	ATA66_ALI15X3,	INIT_ALI15X3,	DMA_ALI15X3,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CY82C693,"CY82C693",	PCI_CY82C693,	NULL,		INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CS5530,	"CS5530",	PCI_CS5530,	NULL,		INIT_CS5530,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_AMD7401,	"AMD7401",	NULL,		NULL,		NULL,		DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7409,	"AMD7409",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7411,	"AMD7411",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7441,	"AMD7441",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_PDCADMA,	"PDCADMA",	PCI_PDCADMA,	ATA66_PDCADMA,	INIT_PDCADMA,	DMA_PDCADMA,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_SLC90E66,"SLC90E66",	PCI_SLC90E66,	ATA66_SLC90E66,	INIT_SLC90E66,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-        {DEVID_OSB4,    "ServerWorks OSB4",		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CSB5,	"ServerWorks CSB5",		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_ITE8172G,"IT8172G",	PCI_IT8172,	NULL,	INIT_IT8172,	NULL,		{{0x00,0x00,0x00}, {0x40,0x00,0x01}},	ON_BOARD,	0 },
-	{IDE_PCI_DEVID_NULL, "PCI_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 }};
+	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ  | ATA_F_DMA },
+	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
+	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, pci_init_pdc202xx, ata66_pdc202xx,	ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
+#endif
+#ifdef CONFIG_BLK_DEV_RZ1000
+	{PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, NULL, NULL,	ide_init_rz1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, NULL, NULL,	ide_init_rz1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
+#endif
+#ifdef CONFIG_BLK_DEV_SIS5513
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, pci_init_sis5513, ata66_sis5513, ide_init_sis5513, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, ON_BOARD, 0, ATA_F_NOADMA },
+#endif
+#ifdef CONFIG_BLK_DEV_CMD64X
+	{PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, pci_init_cmd64x, NULL, ide_init_cmd64x, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, pci_init_cmd64x, NULL, ide_init_cmd64x, NULL, {{0x00,0x00,0x00}, {0x51,0x80,0x80}}, ON_BOARD, 0, ATA_F_DMA },
+	{PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, pci_init_cmd64x, ata66_cmd64x, ide_init_cmd64x, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA },
+	{PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, pci_init_cmd64x, ata66_cmd64x, ide_init_cmd64x, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA },
+	{PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_680, pci_init_cmd64x, ata66_cmd64x, ide_init_cmd64x, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA },
+#endif
+#ifdef CONFIG_BLK_DEV_OPTI621
+	{PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, NULL, NULL, ide_init_opti621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, NULL, NULL, ide_init_opti621, NULL, {{0x45,0x80,0x00}, {0x40,0x08,0x00}}, ON_BOARD, 0, 0 },
+#endif
+#ifdef CONFIG_BLK_DEV_TRM290
+	{PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290, NULL, NULL, ide_init_trm290,	NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
+#endif
+#ifdef CONFIG_BLK_DEV_NS87415
+	{PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, NULL, NULL, ide_init_ns87415, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
+#endif
+#ifdef CONFIG_BLK_DEV_AEC62XX
+	{PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, pci_init_aec62xx, NULL, ide_init_aec62xx, ide_dmacapable_aec62xx, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0, ATA_F_SER | ATA_F_IRQ | ATA_F_DMA },
+	{PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860, pci_init_aec62xx, ata66_aec62xx, ide_init_aec62xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 0, ATA_F_IRQ | ATA_F_NOADMA | ATA_F_DMA },
+	{PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R, pci_init_aec62xx, ata66_aec62xx, ide_init_aec62xx, NULL, {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
+#endif
+#ifdef CONFIG_BLK_DEV_SL82C105
+	{PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, pci_init_sl82c105, NULL, ide_init_sl82c105, dma_init_sl82c105, {{0x40,0x01,0x01}, {0x40,0x10,0x10}}, ON_BOARD, 0, 0 },
+#endif
+#ifdef CONFIG_BLK_DEV_HPT34X
+	{PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343, pci_init_hpt34x, NULL, ide_init_hpt34x, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, NEVER_BOARD, 16, ATA_F_NOADMA | ATA_F_DMA },
+#endif
+#ifdef CONFIG_BLK_DEV_HPT366
+	{PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366, pci_init_hpt366, ata66_hpt366, ide_init_hpt366, ide_dmacapable_hpt366, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 240, ATA_F_IRQ | ATA_F_HPTHACK | ATA_F_DMA },
+#endif
+#ifdef CONFIG_BLK_DEV_ALI15X3
+	{PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, pci_init_ali15x3, ata66_ali15x3, ide_init_ali15x3, ide_dmacapable_ali15x3, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
+#endif
+#ifdef CONFIG_BLK_DEV_CY82C693
+	{PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, pci_init_cy82c693, NULL, ide_init_cy82c693,	NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA },
+#endif
+#ifdef CONFIG_BLK_DEV_CS5530
+	{PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE, pci_init_cs5530, NULL, ide_init_cs5530, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA },
+#endif
+#ifdef CONFIG_BLK_DEV_AMD74XX
+	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, NULL, NULL, NULL, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7441, pci_init_amd74xx, ata66_amd74xx, ide_init_amd74xx, ide_dmacapable_amd74xx, {{0x40,0x01,0x01}, {0x40,0x02,0x02}}, ON_BOARD, 0, 0 },
+#endif
+#ifdef CONFIG_BLK_DEV_PDC_ADMA
+	{PCI_VENDOR_ID_PDC, PCI_DEVICE_ID_PDC_1841, pci_init_pdcadma, ata66_pdcadma, ide_init_pdcadma, ide_dmacapable_pdcadma, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_NODMA },
+#endif
+#ifdef CONFIG_BLK_DEV_SLC90E66
+	{PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1, pci_init_slc90e66, ata66_slc90e66, ide_init_slc90e66, NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0, 0 },
+#endif
+#ifdef CONFIG_BLK_DEV_SVWKS
+        {PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, pci_init_svwks, ata66_svwks, ide_init_svwks, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_DMA },
+	{PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, pci_init_svwks, ata66_svwks, ide_init_svwks, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
+#endif
+#ifdef CONFIG_BLK_DEV_IT8172
+	{PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G, pci_init_it8172,	NULL, ide_init_it8172, NULL, {{0x00,0x00,0x00}, {0x40,0x00,0x01}}, ON_BOARD, 0, 0 },
+#endif
+	/* Those are id's of chips we don't deal currently with. */
+	{PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640, NULL, NULL, IDE_IGNORE, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, NULL, NULL, NULL, NULL, {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
+	{PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_FIXIRQ },
+	{PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_FIXIRQ },
+	{PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_FIXIRQ },
+	{PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, ATA_F_NOADMA },
+	{0, 0, NULL, NULL, NULL, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0 }};
 
 /*
  * This allows offboard ide-pci cards the enable a BIOS, verify interrupt
  * settings of split-mirror pci-config space, place chipset into init-mode,
  * and/or preserve an interrupt if the card is not native ide support.
  */
-static unsigned int __init ide_special_settings (struct pci_dev *dev, const char *name)
+static unsigned int __init trust_pci_irq(ide_pci_device_t *d, struct pci_dev *dev)
 {
-	switch(dev->device) {
-		case PCI_DEVICE_ID_TTI_HPT366:
-		case PCI_DEVICE_ID_PROMISE_20246:
-		case PCI_DEVICE_ID_PROMISE_20262:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20268R:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			return dev->irq;
-		default:
-			break;
-	}
+	if (d->flags & ATA_F_IRQ)
+		return dev->irq;
+
 	return 0;
 }
 
@@ -491,7 +332,7 @@
  * Match a PCI IDE port against an entry in ide_hwifs[],
  * based on io_base port if possible.
  */
-static ide_hwif_t __init *ide_match_hwif (unsigned long io_base, byte bootable, const char *name)
+static ide_hwif_t __init *lookup_hwif (unsigned long io_base, byte bootable, const char *name)
 {
 	int h;
 	ide_hwif_t *hwif;
@@ -553,7 +394,7 @@
 	return NULL;
 }
 
-static int __init ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
+static int __init setup_pci_baseregs (struct pci_dev *dev, const char *name)
 {
 	byte reg, progif = 0;
 
@@ -566,7 +407,7 @@
 			return 1;
 		}
 		printk("%s: placing both ports into native PCI mode\n", name);
-		(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
+		pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
 		if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) || (progif & 5) != 5) {
 			printk("%s: rewrite of PROGIF failed, wanted 0x%04x, got 0x%04x\n", name, progif|5, progif);
 			return 1;
@@ -588,23 +429,181 @@
 }
 
 /*
- * ide_setup_pci_device() looks at the primary/secondary interfaces
- * on a PCI IDE device and, if they are enabled, prepares the IDE driver
- * for use with them.  This generic code works for most PCI chipsets.
+ * Setup a particular port on an ATA host controller.
  *
- * One thing that is not standardized is the location of the
- * primary/secondary interface "enable/disable" bits.  For chipsets that
- * we "know" about, this information is in the ide_pci_device_t struct;
- * for all other chipsets, we just assume both interfaces are enabled.
+ * This get's called once for the master and for the slave interface.
  */
-static void __init ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d)
+static int __init setup_host_channel(struct pci_dev *dev,
+		ide_pci_device_t *d,
+		int port,
+		u8 class_rev,
+		int pciirq, ide_hwif_t **mate,
+		int autodma,
+		unsigned short *pcicmd)
 {
-	unsigned int port, at_least_one_hwif_enabled = 0, autodma = 0, pciirq = 0;
-	unsigned short pcicmd = 0, tried_config = 0;
-	byte tmp = 0;
-	ide_hwif_t *hwif, *mate = NULL;
+	unsigned long base = 0;
+	unsigned long ctl = 0;
+	ide_pci_enablebit_t *e = &(d->enablebits[port]);
+	ide_hwif_t *hwif;
+
+	u8 tmp;
+	if (port == 1) {
+
+		/* If this is a Promise FakeRaid controller, the 2nd controller
+		 * will be marked as disabled while it is actually there and
+		 * enabled by the bios for raid purposes.  Skip the normal "is
+		 * it enabled" test for those.
+		 */
+		if (d->flags & ATA_F_PHACK)
+			goto controller_ok;
+	}
+
+	/* Test whatever the port is enabled.
+	 */
+	if (e->reg) {
+		if (pci_read_config_byte(dev, e->reg, &tmp))
+			return 0; /* error! */
+		if ((tmp & e->mask) != e->val)
+			return 0;
+	}
+
+	/* Nothing to be done for the second port.
+	 */
+	if (port == 1) {
+		if ((d->flags & ATA_F_HPTHACK) && (class_rev < 0x03))
+			return 0;
+	}
+controller_ok:
+	if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) {
+		ctl  = dev->resource[(2 * port) + 1].start;
+		base = dev->resource[2 * port].start;
+		if (!(ctl & PCI_BASE_ADDRESS_IO_MASK) || !(base & PCI_BASE_ADDRESS_IO_MASK)) {
+			printk(KERN_WARNING "%s: error: IO reported as MEM by BIOS!\n", dev->name);
+			/* try it with the default values */
+			ctl = 0;
+			base = 0;
+		}
+	}
+	if (ctl && !base) {
+		printk(KERN_WARNING "%s: error: missing MEM base info from BIOS!\n", dev->name);
+		/* we will still try to get along with the default */
+	}
+	if (base && !ctl) {
+		printk(KERN_WARNING "%s: error: missing IO base info from BIOS!\n", dev->name);
+		/* we will still try to get along with the default */
+	}
+
+	/* Fill in the default values: */
+	if (!ctl)
+		ctl = port ? 0x374 : 0x3f4;
+	if (!base)
+		base = port ? 0x170 : 0x1f0;
+
+	if ((hwif = lookup_hwif(base, d->bootable, dev->name)) == NULL)
+		return -ENOMEM;	/* no room in ide_hwifs[] */
+
+	if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
+		ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
+		memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+		hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
+	}
+
+	hwif->chipset = ide_pci;
+	hwif->pci_dev = dev;
+	hwif->channel = port;
+	if (!hwif->irq)
+		hwif->irq = pciirq;
+
+	/* Setup the mate interface if we have two channels.
+	 */
+	if (*mate) {
+		hwif->mate = *mate;
+		(*mate)->mate = hwif;
+		if (d->flags & ATA_F_SER) {
+			hwif->serialized = 1;
+			(*mate)->serialized = 1;
+		}
+	}
+
+	/* Hard wired IRQ lines on UMC chips and no DMA transfers.*/
+	if (d->flags & ATA_F_FIXIRQ) {
+		hwif->irq = hwif->channel ? 15 : 14;
+		goto no_dma;
+	}
+	if (d->flags & ATA_F_NODMA)
+		goto no_dma;
+
+	/* Check whatever this interface is UDMA4 mode capable. */
+	if (hwif->udma_four) {
+		printk("%s: warning: ATA-66/100 forced bit set!\n", dev->name);
+	} else {
+		if (d->ata66_check)
+			hwif->udma_four = d->ata66_check(hwif);
+	}
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (d->flags & ATA_F_NOADMA)
+		autodma = 0;
+
+	if (autodma)
+		hwif->autodma = 1;
+
+	if ((d->flags & ATA_F_DMA) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
+		unsigned long dma_base;
+
+		dma_base = ide_get_or_set_dma_base(hwif, (!*mate && d->extra) ? d->extra : 0, dev->name);
+		if (dma_base && !(*pcicmd & PCI_COMMAND_MASTER)) {
+
+			/*
+			 * Set up BM-DMA capability (PnP BIOS should have done this already)
+			 */
+			if (!(d->vendor == PCI_VENDOR_ID_CYRIX && d->device == PCI_DEVICE_ID_CYRIX_5530_IDE))
+				hwif->autodma = 0;	/* default DMA off if we had to configure it here */
+			pci_write_config_word(dev, PCI_COMMAND, *pcicmd | PCI_COMMAND_MASTER);
+			if (pci_read_config_word(dev, PCI_COMMAND, pcicmd) || !(*pcicmd & PCI_COMMAND_MASTER)) {
+				printk("%s: %s error updating PCICMD\n", hwif->name, dev->name);
+				dma_base = 0;
+			}
+		}
+		if (dma_base) {
+			if (d->dma_init)
+				d->dma_init(hwif, dma_base);
+			else	/* FIXME: use a generic device descriptor instead */
+				ide_setup_dma(hwif, dma_base, 8);
+		} else {
+			printk("%s: %s Bus-Master DMA was disabled by BIOS\n", hwif->name, dev->name);
+		}
+	}
+#endif
+no_dma:
+	if (d->init_hwif)  /* Call chipset-specific routine for each enabled hwif */
+		d->init_hwif(hwif);
+
+	*mate = hwif;
+
+	/* we are done */
+
+	return 0;
+}
+
+/*
+ * Looks at the primary/secondary chanells on a PCI IDE device and, if they
+ * are enabled, prepares the IDE driver for use with them.  This generic code
+ * works for most PCI chipsets.
+ *
+ * One thing that is not standardized is the location of the primary/secondary
+ * interface "enable/disable" bits.  For chipsets that we "know" about, this
+ * information is in the ide_pci_device_t struct; for all other chipsets, we
+ * just assume both interfaces are enabled.
+ */
+
+static void __init setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d)
+{
+	int autodma = 0;
+	int pciirq = 0;
+	unsigned short pcicmd = 0;
+	unsigned short tried_config = 0;
+	ide_hwif_t *mate = NULL;
 	unsigned int class_rev;
-	static int secondpdc = 0;
 
 #ifdef CONFIG_IDEDMA_AUTO
 	if (!noautodma)
@@ -612,18 +611,18 @@
 #endif
 
 	if (d->init_hwif == IDE_NO_DRIVER) {
-		printk(KERN_WARNING "%s: detected chipset, but driver not compiled in!\n", d->name);
+		printk(KERN_WARNING "%s: detected chipset, but driver not compiled in!\n", dev->name);
 		d->init_hwif = NULL;
 	}
 
 	if (pci_enable_device(dev)) {
-		printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name);
+		printk(KERN_WARNING "%s: Could not enable PCI device.\n", dev->name);
 		return;
 	}
 
 check_if_enabled:
 	if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd)) {
-		printk("%s: error accessing PCI regs\n", d->name);
+		printk("%s: error accessing PCI regs\n", dev->name);
 		return;
 	}
 	if (!(pcicmd & PCI_COMMAND_IO)) {	/* is device disabled? */
@@ -635,42 +634,38 @@
 		 * but we'll eventually ignore it again if no drives respond.
 		 */
 		if (tried_config++
-		 || ide_setup_pci_baseregs(dev, d->name)
+		 || setup_pci_baseregs(dev, dev->name)
 		 || pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_IO)) {
-			printk("%s: device disabled (BIOS)\n", d->name);
+			printk("%s: device disabled (BIOS)\n", dev->name);
 			return;
 		}
 		autodma = 0;	/* default DMA off if we had to configure it here */
 		goto check_if_enabled;
 	}
 	if (tried_config)
-		printk("%s: device enabled (Linux)\n", d->name);
+		printk("%s: device enabled (Linux)\n", dev->name);
 
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;
 
-	if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) {
-		/* see comments in hpt34x.c on why..... */
-		char *chipset_names[] = {"HPT343", "HPT345"};
-		strcpy(d->name, chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0]);
+	if (d->vendor == PCI_VENDOR_ID_TTI && PCI_DEVICE_ID_TTI_HPT343) {
+		/* see comments in hpt34x.c to see why... */
 		d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
 	}
 
-	printk("%s: chipset revision %d\n", d->name, class_rev);
+	printk("%s: chipset revision %d\n", dev->name, class_rev);
 
 	/*
 	 * Can we trust the reported IRQ?
 	 */
 	pciirq = dev->irq;
-	
-	if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID)
-	{
+
+	if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID) {
 		/* By rights we want to ignore these, but the Promise Fastrak
 		   people have some strange ideas about proprietary so we have
 		   to act otherwise on those. The supertrak however we need
 		   to skip */
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265))
-		{
+		if (d->vendor == PCI_VENDOR_ID_PROMISE && d->device == PCI_DEVICE_ID_PROMISE_20265) {
 			printk(KERN_INFO "ide: Found promise 20265 in RAID mode.\n");
 			if(dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_INTEL &&
 				dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960)
@@ -679,180 +674,43 @@
 				return;
 			}
 		}
-		/* Its attached to something else, just a random bridge. 
+		/* Its attached to something else, just a random bridge.
 		   Suspect a fastrak and fall through */
 	}
 	if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) {
-		printk("%s: not 100%% native mode: will probe irqs later\n", d->name);
+		printk("%s: not 100%% native mode: will probe irqs later\n", dev->name);
 		/*
 		 * This allows offboard ide-pci cards the enable a BIOS,
 		 * verify interrupt settings of split-mirror pci-config
 		 * space, place chipset into init-mode, and/or preserve
 		 * an interrupt if the card is not native ide support.
 		 */
-		pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : ide_special_settings(dev, d->name);
+		if (d->init_chipset)
+			pciirq = d->init_chipset(dev);
+		else
+			pciirq = trust_pci_irq(d, dev);
 	} else if (tried_config) {
-		printk("%s: will probe irqs later\n", d->name);
+		printk("%s: will probe irqs later\n", dev->name);
 		pciirq = 0;
 	} else if (!pciirq) {
-		printk("%s: bad irq (%d): will probe later\n", d->name, pciirq);
+		printk("%s: bad irq (%d): will probe later\n", dev->name, pciirq);
 		pciirq = 0;
 	} else {
 		if (d->init_chipset)
-			(void) d->init_chipset(dev, d->name);
+			d->init_chipset(dev);
 #ifdef __sparc__
 		printk("%s: 100%% native mode on irq %s\n",
-		       d->name, __irq_itoa(pciirq));
+		       dev->name, __irq_itoa(pciirq));
 #else
-		printk("%s: 100%% native mode on irq %d\n", d->name, pciirq);
+		printk("%s: 100%% native mode on irq %d\n", dev->name, pciirq);
 #endif
 	}
 
 	/*
-	 * Set up the IDE ports
+	 * Set up IDE chanells. First the primary, then the secondary.
 	 */
-	for (port = 0; port <= 1; ++port) {
-		unsigned long base = 0, ctl = 0;
-		ide_pci_enablebit_t *e = &(d->enablebits[port]);
-	
-		/* 
-		 * If this is a Promise FakeRaid controller, the 2nd controller will be marked as 
-		 * disabled while it is actually there and enabled by the bios for raid purposes. 
-		 * Skip the normal "is it enabled" test for those.
-		 */
-		if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265)) && (secondpdc++==1) && (port==1)  ) 
-			goto controller_ok;
-		if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262)) && (secondpdc++==1) && (port==1)  ) 
-			goto controller_ok;
-			
-		if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) || (tmp & e->mask) != e->val))
-			continue;	/* port not enabled */
-controller_ok:			
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) && (port) && (class_rev < 0x03))
-			return;
-		if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE || (dev->class & (port ? 4 : 1)) != 0) {
-			ctl  = dev->resource[(2*port)+1].start;
-			base = dev->resource[2*port].start;
-			if (!(ctl & PCI_BASE_ADDRESS_IO_MASK) ||
-			    !(base & PCI_BASE_ADDRESS_IO_MASK)) {
-				printk("%s: IO baseregs (BIOS) are reported as MEM, report to <andre@linux-ide.org>.\n", d->name);
-#if 0
-				/* FIXME! This really should check that it really gets the IO/MEM part right! */
-				continue;
-#endif
-			}
-		}
-		if ((ctl && !base) || (base && !ctl)) {
-			printk("%s: inconsistent baseregs (BIOS) for port %d, skipping\n", d->name, port);
-			continue;
-		}
-		if (!ctl)
-			ctl = port ? 0x374 : 0x3f4;	/* use default value */
-		if (!base)
-			base = port ? 0x170 : 0x1f0;	/* use default value */
-		if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
-			continue;	/* no room in ide_hwifs[] */
-		if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
-			ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
-			memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-			hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
-		}
-		hwif->chipset = ide_pci;
-		hwif->pci_dev = dev;
-		hwif->pci_devid = d->devid;
-		hwif->channel = port;
-		if (!hwif->irq)
-			hwif->irq = pciirq;
-		if (mate) {
-			hwif->mate = mate;
-			mate->mate = hwif;
-			if (IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210)) {
-				hwif->serialized = 1;
-				mate->serialized = 1;
-			}
-		}
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886BF) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8673F)) {
-			hwif->irq = hwif->channel ? 15 : 14;
-			goto bypass_umc_dma;
-		}
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_MPIIX))
-			goto bypass_piix_dma;
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDCADMA))
-			goto bypass_legacy_dma;
-		if (hwif->udma_four) {
-			printk("%s: ATA-66/100 forced bit set (WARNING)!!\n", d->name);
-		} else {
-			hwif->udma_four = (d->ata66_check) ? d->ata66_check(hwif) : 0;
-		}
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_SIS5513) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PIIX4NX) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)  ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_VIA_IDE) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_MR_IDE)  ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_VP_IDE))
-			autodma = 0;
-		if (autodma)
-			hwif->autodma = 1;
-
-		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20262) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20267) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6210) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_AEC6260R) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD646) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD648) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD649) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_CMD680) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_OSB4) ||
-		    ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80))) {
-			unsigned long dma_base = ide_get_or_set_dma_base(hwif, (!mate && d->extra) ? d->extra : 0, d->name);
-			if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
-				/*
- 	 			 * Set up BM-DMA capability (PnP BIOS should have done this)
- 	 			 */
-		    		if (!IDE_PCI_DEVID_EQ(d->devid, DEVID_CS5530))
-					hwif->autodma = 0;	/* default DMA off if we had to configure it here */
-				(void) pci_write_config_word(dev, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER);
-				if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) {
-					printk("%s: %s error updating PCICMD\n", hwif->name, d->name);
-					dma_base = 0;
-				}
-			}
-			if (dma_base) {
-				if (d->dma_init) {
-					d->dma_init(hwif, dma_base);
-				} else {
-					ide_setup_dma(hwif, dma_base, 8);
-				}
-			} else {
-				printk("%s: %s Bus-Master DMA disabled (BIOS)\n", hwif->name, d->name);
-			}
-		}
-#endif	/* CONFIG_BLK_DEV_IDEDMA */
-bypass_legacy_dma:
-bypass_piix_dma:
-bypass_umc_dma:
-		if (d->init_hwif)  /* Call chipset-specific routine for each enabled hwif */
-			d->init_hwif(hwif);
-		mate = hwif;
-		at_least_one_hwif_enabled = 1;
-	}
-	if (!at_least_one_hwif_enabled)
-		printk("%s: neither IDE port enabled (BIOS)\n", d->name);
+	setup_host_channel(dev, d, 0, class_rev, pciirq, &mate, autodma, &pcicmd);
+	setup_host_channel(dev, d, 1, class_rev, pciirq, &mate, autodma, &pcicmd);
 }
 
 static void __init pdc20270_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
@@ -860,9 +718,9 @@
 	struct pci_dev *dev2 = NULL, *findev;
 	ide_pci_device_t *d2;
 
-	if ((dev->bus->self &&
-	     dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
-	    (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
+	if (dev->bus->self &&
+	    dev->bus->self->vendor == PCI_VENDOR_ID_DEC &&
+	    dev->bus->self->device == PCI_DEVICE_ID_DEC_21150) {
 		if (PCI_SLOT(dev->devfn) & 2) {
 			return;
 		}
@@ -884,13 +742,13 @@
 		}
 	}
 
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d->name, dev->bus->number, dev->devfn);
-	ide_setup_pci_device(dev, d);
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n", dev->name, dev->bus->number, dev->devfn);
+	setup_pci_device(dev, d);
 	if (!dev2)
 		return;
 	d2 = d;
-	printk("%s: IDE controller on PCI bus %02x dev %02x\n", d2->name, dev2->bus->number, dev2->devfn);
-	ide_setup_pci_device(dev2, d2);
+	printk("%s: IDE controller on PCI bus %02x dev %02x\n", dev2->name, dev2->bus->number, dev2->devfn);
+	setup_pci_device(dev2, d2);
 }
 
 static void __init hpt366_device_order_fixup (struct pci_dev *dev, ide_pci_device_t *d)
@@ -899,7 +757,6 @@
 	ide_pci_device_t *d2;
 	unsigned char pin1 = 0, pin2 = 0;
 	unsigned int class_rev;
-	char *chipset_names[] = {"HPT366", "HPT366", "HPT368", "HPT370", "HPT370A"};
 
 	if (PCI_FUNC(dev->devfn) & 1)
 		return;
@@ -907,20 +764,18 @@
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;
 
-	strcpy(d->name, chipset_names[class_rev]);
-
 	switch(class_rev) {
 		case 4:
-		case 3:	printk("%s: IDE controller on PCI slot %s\n", d->name, dev->slot_name);
-			ide_setup_pci_device(dev, d);
+		case 3:	printk("%s: IDE controller on PCI slot %s\n", dev->name, dev->slot_name);
+			setup_pci_device(dev, d);
 			return;
 		default:	break;
 	}
 
 	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
 	pci_for_each_dev(findev) {
-		if ((findev->vendor == dev->vendor) &&
-		    (findev->device == dev->device) &&
+		if (findev->vendor == dev->vendor &&
+		    findev->device == dev->device &&
 		    ((findev->devfn - dev->devfn) == 1) &&
 		    (PCI_FUNC(findev->devfn) & 1)) {
 			dev2 = findev;
@@ -929,7 +784,7 @@
 			hpt363_shared_irq = (dev->irq == dev2->irq) ? 1 : 0;
 			if (hpt363_shared_pin && hpt363_shared_irq) {
 				d->bootable = ON_BOARD;
-				printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", d->name, pin1, pin2);
+				printk("%s: onboard version of chipset, pin1=%d pin2=%d\n", dev->name, pin1, pin2);
 #if 0
 				/* I forgot why I did this once, but it fixed something. */
 				pci_write_config_byte(dev2, PCI_INTERRUPT_PIN, dev->irq);
@@ -940,48 +795,55 @@
 			break;
 		}
 	}
-	printk("%s: IDE controller on PCI slot %s\n", d->name, dev->slot_name);
-	ide_setup_pci_device(dev, d);
+	printk("%s: IDE controller on PCI slot %s\n", dev->name, dev->slot_name);
+	setup_pci_device(dev, d);
 	if (!dev2)
 		return;
 	d2 = d;
-	printk("%s: IDE controller on PCI slot %s\n", d2->name, dev2->slot_name);
-	ide_setup_pci_device(dev2, d2);
+	printk("%s: IDE controller on PCI slot %s\n", dev2->name, dev2->slot_name);
+	setup_pci_device(dev2, d2);
 }
 
 /*
- * ide_scan_pcibus() gets invoked at boot time from ide.c.
- * It finds all PCI IDE controllers and calls ide_setup_pci_device for them.
+ * This finds all PCI IDE controllers and calls appriopriate initialization
+ * functions for them.
  */
-void __init ide_scan_pcidev (struct pci_dev *dev)
+static void __init ide_scan_pcidev(struct pci_dev *dev)
 {
-	ide_pci_devid_t		devid;
+	unsigned short vendor;
+	unsigned short device;
 	ide_pci_device_t	*d;
 
-	devid.vid = dev->vendor;
-	devid.did = dev->device;
-	for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d);
+	vendor = dev->vendor;
+	device = dev->device;
+
+	/* Look up the chipset information.
+	 */
+	d = pci_chipsets;
+	while (d->vendor && !(d->vendor == vendor && d->device == device))
+		++d;
+
 	if (d->init_hwif == IDE_IGNORE)
-		printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name);
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(PCI_FUNC(dev->devfn) & 1))
+		printk("%s: has been ignored by PCI bus scan\n", dev->name);
+	else if ((d->vendor == PCI_VENDOR_ID_OPTI && d->device == PCI_DEVICE_ID_OPTI_82C558) && !(PCI_FUNC(dev->devfn) & 1))
 		return;
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
+	else if ((d->vendor == PCI_VENDOR_ID_CONTAQ && d->device == PCI_DEVICE_ID_CONTAQ_82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
 		return;	/* CY82C693 is more than only a IDE controller */
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_ITE8172G) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
+	else if ((d->vendor == PCI_VENDOR_ID_ITE && d->device == PCI_DEVICE_ID_ITE_IT8172G) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
 		return;	/* IT8172G is also more than only an IDE controller */
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && !(PCI_FUNC(dev->devfn) & 1))
+	else if ((d->vendor == PCI_VENDOR_ID_UMC && d->device == PCI_DEVICE_ID_UMC_UM8886A) && !(PCI_FUNC(dev->devfn) & 1))
 		return;	/* UM8886A/BF pair */
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366))
+	else if (d->flags & ATA_F_HPTHACK)
 		hpt366_device_order_fixup(dev, d);
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268R))
+	else if (d->vendor == PCI_VENDOR_ID_PROMISE && d->device == PCI_DEVICE_ID_PROMISE_20268R)
 		pdc20270_device_order_fixup(dev, d);
-	else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-		if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
-			printk("%s: unknown IDE controller on PCI slot %s, VID=%04x, DID=%04x\n",
-			       d->name, dev->slot_name, devid.vid, devid.did);
+	else if (!(d->vendor == 0 && d->device == 0) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+		if (d->vendor == 0 && d->device == 0)
+			printk("%s: unknown IDE controller on PCI slot %s, vendor=%04x, device=%04x\n",
+			       dev->name, dev->slot_name, vendor, device);
 		else
-			printk("%s: IDE controller on PCI slot %s\n", d->name, dev->slot_name);
-		ide_setup_pci_device(dev, d);
+			printk("%s: IDE controller on PCI slot %s\n", dev->name, dev->slot_name);
+		setup_pci_device(dev, d);
 	}
 }
 
diff -urN linux-2.5.6-pre1/drivers/ide/ide-pnp.c linux-2.5.6-pre2/drivers/ide/ide-pnp.c
--- linux-2.5.6-pre1/drivers/ide/ide-pnp.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/drivers/ide/ide-pnp.c	Thu Feb 28 13:34:21 2002
@@ -57,6 +57,7 @@
 static int __init pnpide_generic_init(struct pci_dev *dev, int enable)
 {
 	hw_regs_t hw;
+	ide_hwif_t *hwif;
 	int index;
 
 	if (!enable)
@@ -69,10 +70,11 @@
 			generic_ide_offsets, (ide_ioreg_t) DEV_IO(dev, 1),
 			0, NULL, DEV_IRQ(dev, 0));
 
-	index = ide_register_hw(&hw, NULL);
+	index = ide_register_hw(&hw, &hwif);
 
 	if (index != -1) {
-	    	printk("ide%d: %s IDE interface\n", index, DEV_NAME(dev));
+		hwif->pci_dev = dev;
+		printk("ide%d: %s IDE interface\n", index, DEV_NAME(dev));
 		return 0;
 	}
 
diff -urN linux-2.5.6-pre1/drivers/ide/ide-probe.c linux-2.5.6-pre2/drivers/ide/ide-probe.c
--- linux-2.5.6-pre1/drivers/ide/ide-probe.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/drivers/ide/ide-probe.c	Thu Feb 28 13:34:21 2002
@@ -46,6 +46,7 @@
 #include <linux/delay.h>
 #include <linux/ide.h>
 #include <linux/spinlock.h>
+#include <linux/pci.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -129,17 +130,17 @@
 		}
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 		switch (type) {
-			case ide_floppy:
+			case ATA_FLOPPY:
 				if (!strstr(id->model, "CD-ROM")) {
 					if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP"))
 						printk("cdrom or floppy?, assuming ");
-					if (drive->media != ide_cdrom) {
+					if (drive->type != ATA_ROM) {
 						printk ("FLOPPY");
 						break;
 					}
 				}
-				type = ide_cdrom;	/* Early cdrom models used zero */
-			case ide_cdrom:
+				type = ATA_ROM;	/* Early cdrom models used zero */
+			case ATA_ROM:
 				drive->removable = 1;
 #ifdef CONFIG_PPC
 				/* kludge for Apple PowerBook internal zip */
@@ -151,10 +152,10 @@
 #endif
 				printk ("CD/DVD-ROM");
 				break;
-			case ide_tape:
+			case ATA_TAPE:
 				printk ("TAPE");
 				break;
-			case ide_optical:
+			case ATA_MOD:
 				printk ("OPTICAL");
 				drive->removable = 1;
 				break;
@@ -163,7 +164,7 @@
 				break;
 		}
 		printk (" drive\n");
-		drive->media = type;
+		drive->type = type;
 		return;
 	}
 
@@ -183,7 +184,7 @@
 			mate->noprobe = 1;
 		}
 	}
-	drive->media = ide_disk;
+	drive->type = ATA_DISK;
 	printk("ATA DISK drive\n");
 	QUIRK_LIST(HWIF(drive),drive);
 	return;
@@ -326,12 +327,12 @@
 	int rc;
 	ide_hwif_t *hwif = HWIF(drive);
 	if (drive->present) {	/* avoid waiting for inappropriate probes */
-		if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY))
+		if ((drive->type != ATA_DISK) && (cmd == WIN_IDENTIFY))
 			return 4;
 	}
 #ifdef DEBUG
-	printk("probing for %s: present=%d, media=%d, probetype=%s\n",
-		drive->name, drive->present, drive->media,
+	printk("probing for %s: present=%d, type=%d, probetype=%s\n",
+		drive->name, drive->present, drive->type,
 		(cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI");
 #endif
 	ide_delay_50ms();	/* needed for some systems (e.g. crw9624 as drive0 with disk as slave) */
@@ -420,10 +421,10 @@
 	if (!drive->present)
 		return;			/* drive not found */
 	if (drive->id == NULL) {		/* identification failed? */
-		if (drive->media == ide_disk) {
+		if (drive->type == ATA_DISK) {
 			printk ("%s: non-IDE drive, CHS=%d/%d/%d\n",
 			 drive->name, drive->cyl, drive->head, drive->sect);
-		} else if (drive->media == ide_cdrom) {
+		} else if (drive->type == ATA_ROM) {
 			printk("%s: ATAPI cdrom (?)\n", drive->name);
 		} else {
 			drive->present = 0;	/* nuke it */
@@ -465,37 +466,46 @@
 
 static void hwif_register (ide_hwif_t *hwif)
 {
+	/* Register this hardware interface within the global device tree.
+	 */
+	sprintf(hwif->device.bus_id, "%04x", hwif->io_ports[IDE_DATA_OFFSET]);
+	sprintf(hwif->device.name, "ide");
+	hwif->device.driver_data = hwif;
+	if (hwif->pci_dev)
+		hwif->device.parent = &hwif->pci_dev->dev;
+	else
+		hwif->device.parent = NULL; /* Would like to do = &device_legacy */
+	device_register(&hwif->device);
+
 	if (((unsigned long)hwif->io_ports[IDE_DATA_OFFSET] | 7) ==
 	    ((unsigned long)hwif->io_ports[IDE_STATUS_OFFSET])) {
 		ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 8, hwif->name);
 		hwif->straight8 = 1;
-		goto jump_straight8;
-	}
-
-	if (hwif->io_ports[IDE_DATA_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_ERROR_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_ERROR_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_NSECTOR_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_SECTOR_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_LCYL_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_LCYL_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_HCYL_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_HCYL_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_SELECT_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_SELECT_OFFSET], 1, hwif->name);
-	if (hwif->io_ports[IDE_STATUS_OFFSET])
-		ide_request_region(hwif->io_ports[IDE_STATUS_OFFSET], 1, hwif->name);
+	} else {
+		if (hwif->io_ports[IDE_DATA_OFFSET])
+			ide_request_region(hwif->io_ports[IDE_DATA_OFFSET], 1, hwif->name);
+		if (hwif->io_ports[IDE_ERROR_OFFSET])
+			ide_request_region(hwif->io_ports[IDE_ERROR_OFFSET], 1, hwif->name);
+		if (hwif->io_ports[IDE_NSECTOR_OFFSET])
+			ide_request_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1, hwif->name);
+		if (hwif->io_ports[IDE_SECTOR_OFFSET])
+			ide_request_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1, hwif->name);
+		if (hwif->io_ports[IDE_LCYL_OFFSET])
+			ide_request_region(hwif->io_ports[IDE_LCYL_OFFSET], 1, hwif->name);
+		if (hwif->io_ports[IDE_HCYL_OFFSET])
+			ide_request_region(hwif->io_ports[IDE_HCYL_OFFSET], 1, hwif->name);
+		if (hwif->io_ports[IDE_SELECT_OFFSET])
+			ide_request_region(hwif->io_ports[IDE_SELECT_OFFSET], 1, hwif->name);
+		if (hwif->io_ports[IDE_STATUS_OFFSET])
+			ide_request_region(hwif->io_ports[IDE_STATUS_OFFSET], 1, hwif->name);
 
-jump_straight8:
+	}
 	if (hwif->io_ports[IDE_CONTROL_OFFSET])
 		ide_request_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1, hwif->name);
 #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
 	if (hwif->io_ports[IDE_IRQ_OFFSET])
 		ide_request_region(hwif->io_ports[IDE_IRQ_OFFSET], 1, hwif->name);
-#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
+#endif
 }
 
 /*
@@ -509,13 +519,6 @@
 
 	if (hwif->noprobe)
 		return;
-#ifdef CONFIG_BLK_DEV_IDE
-	if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA) {
-		extern void probe_cmos_for_drives(ide_hwif_t *);
-
-		probe_cmos_for_drives (hwif);
-	}
-#endif
 
 	if ((hwif->chipset != ide_4drives || !hwif->mate->present) &&
 #if CONFIG_BLK_DEV_PDC4030
@@ -533,7 +536,7 @@
 		}
 		if (!msgout)
 			printk("%s: ports already in use, skipping probe\n", hwif->name);
-		return;	
+		return;
 	}
 
 	__save_flags(flags);	/* local CPU only */
@@ -784,60 +787,51 @@
 static void init_gendisk (ide_hwif_t *hwif)
 {
 	struct gendisk *gd;
-	unsigned int unit, units, minors, i;
+	unsigned int unit, minors, i;
 	extern devfs_handle_t ide_devfs_handle;
 
-#if 1
-	units = MAX_DRIVES;
-#else
-	/* figure out maximum drive number on the interface */
-	for (units = MAX_DRIVES; units > 0; --units) {
-		if (hwif->drives[units-1].present)
-			break;
-	}
-#endif
-
-	minors = units * (1<<PARTN_BITS);
+	minors = MAX_DRIVES * (1 << PARTN_BITS);
 
 	gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL);
 	if (!gd)
 		goto err_kmalloc_gd;
+
 	gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
 	if (!gd->sizes)
 		goto err_kmalloc_gd_sizes;
+
 	gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
 	if (!gd->part)
 		goto err_kmalloc_gd_part;
+	memset(gd->part, 0, minors * sizeof(struct hd_struct));
+
 	blksize_size[hwif->major] = kmalloc (minors*sizeof(int), GFP_KERNEL);
 	if (!blksize_size[hwif->major])
 		goto err_kmalloc_bs;
-
-	memset(gd->part, 0, minors * sizeof(struct hd_struct));
-
 	for (i = 0; i < minors; ++i)
 	    blksize_size[hwif->major][i] = BLOCK_SIZE;
-	for (unit = 0; unit < units; ++unit)
+
+	for (unit = 0; unit < MAX_DRIVES; ++unit)
 		hwif->drives[unit].part = &gd->part[unit << PARTN_BITS];
 
 	gd->major	= hwif->major;		/* our major device number */
 	gd->major_name	= IDE_MAJOR_NAME;	/* treated special in genhd.c */
 	gd->minor_shift	= PARTN_BITS;		/* num bits for partitions */
-	gd->nr_real	= units;		/* current num real drives */
+	gd->nr_real	= MAX_DRIVES;		/* current num real drives */
 	gd->next	= NULL;			/* linked list of major devs */
 	gd->fops        = ide_fops;             /* file operations */
-	gd->de_arr	= kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL);
-	gd->flags	= kmalloc (sizeof *gd->flags * units, GFP_KERNEL);
+	gd->de_arr	= kmalloc(sizeof(*gd->de_arr) * MAX_DRIVES, GFP_KERNEL);
+	gd->flags	= kmalloc(sizeof(*gd->flags) * MAX_DRIVES, GFP_KERNEL);
 	if (gd->de_arr)
-		memset (gd->de_arr, 0, sizeof *gd->de_arr * units);
+		memset(gd->de_arr, 0, sizeof(*gd->de_arr) * MAX_DRIVES);
 	if (gd->flags)
-		memset (gd->flags, 0, sizeof *gd->flags * units);
+		memset(gd->flags, 0, sizeof(*gd->flags) * MAX_DRIVES);
 
 	hwif->gd = gd;
 	add_gendisk(gd);
 
-	for (unit = 0; unit < units; ++unit) {
-#if 1
-		char name[64];
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		char name[80];
 		ide_add_generic_settings(hwif->drives + unit);
 		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
 		sprintf (name, "host%d/bus%d/target%d/lun%d",
@@ -846,19 +840,6 @@
 			hwif->channel, unit, hwif->drives[unit].lun);
 		if (hwif->drives[unit].present)
 			hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
-#else
-		if (hwif->drives[unit].present) {
-			char name[64];
-
-			ide_add_generic_settings(hwif->drives + unit);
-			hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
-			sprintf (name, "host%d/bus%d/target%d/lun%d",
-				 (hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index,
-				 hwif->channel, unit, hwif->drives[unit].lun);
-			hwif->drives[unit].de =
-				devfs_mk_dir (ide_devfs_handle, name, NULL);
-		}
-#endif
 	}
 	return;
 
@@ -869,7 +850,7 @@
 err_kmalloc_gd_sizes:
 	kfree(gd);
 err_kmalloc_gd:
-	printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n");
+	printk(KERN_CRIT "(ide::init_gendisk) Out of memory\n");
 	return;
 }
 
diff -urN linux-2.5.6-pre1/drivers/ide/ide-proc.c linux-2.5.6-pre2/drivers/ide/ide-proc.c
--- linux-2.5.6-pre1/drivers/ide/ide-proc.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/drivers/ide/ide-proc.c	Thu Feb 28 13:34:21 2002
@@ -127,242 +127,8 @@
 int (*via_display_info)(char *, char **, off_t, int) = NULL;
 #endif /* CONFIG_BLK_DEV_VIA82CXXX */
 
-static int ide_getxdigit(char c)
-{
-	int digit;
-	if (isdigit(c))
-		digit = c - '0';
-	else if (isxdigit(c))
-		digit = tolower(c) - 'a' + 10;
-	else
-		digit = -1;
-	return digit;
-}
-
-static int xx_xx_parse_error (const char *data, unsigned long len, const char *msg)
-{
-	char errbuf[16];
-	int i;
-	if (len >= sizeof(errbuf))
-		len = sizeof(errbuf) - 1;
-	for (i = 0; i < len; ++i) {
-		char c = data[i];
-		if (!c || c == '\n')
-			c = '\0';
-		else if (iscntrl(c))
-			c = '?';
-		errbuf[i] = c;
-	}
-	errbuf[i] = '\0';
-	printk("proc_ide: error: %s: '%s'\n", msg, errbuf);
-	return -EINVAL;
-}
-
 static struct proc_dir_entry * proc_ide_root = NULL;
 
-static int proc_ide_write_config
-	(struct file *file, const char *buffer, unsigned long count, void *data)
-{
-	ide_hwif_t	*hwif = data;
-	int		for_real = 0;
-	unsigned long	startn = 0, n, flags;
-	const char	*start = NULL, *msg = NULL;
-
-	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
-		return -EACCES;
-	/*
-	 * Skip over leading whitespace
-	 */
-	while (count && isspace(*buffer)) {
-		--count;
-		++buffer;
-	}
-	/*
-	 * Do one full pass to verify all parameters,
-	 * then do another to actually write the regs.
-	 */
-	save_flags(flags);	/* all CPUs */
-	do {
-		const char *p;
-		if (for_real) {
-			unsigned long timeout = jiffies + (3 * HZ);
-			ide_hwgroup_t *mygroup = (ide_hwgroup_t *)(hwif->hwgroup);
-			ide_hwgroup_t *mategroup = NULL;
-			if (hwif->mate && hwif->mate->hwgroup)
-				mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup);
-			cli();	/* all CPUs; ensure all writes are done together */
-			while (test_bit(IDE_BUSY, &mygroup->flags) || (mategroup && test_bit(IDE_BUSY, &mategroup->flags))) {
-				sti();	/* all CPUs */
-				if (0 < (signed long)(jiffies - timeout)) {
-					printk("/proc/ide/%s/config: channel(s) busy, cannot write\n", hwif->name);
-					restore_flags(flags);	/* all CPUs */
-					return -EBUSY;
-				}
-				cli();	/* all CPUs */
-			}
-		}
-		p = buffer;
-		n = count;
-		while (n > 0) {
-			int d, digits;
-			unsigned int reg = 0, val = 0, is_pci;
-			start = p;
-			startn = n--;
-			switch (*p++) {
-				case 'R':	is_pci = 0;
-						break;
-				case 'P':	is_pci = 1;
-#ifdef CONFIG_BLK_DEV_IDEPCI
-						if (hwif->pci_dev && !IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))
-							break;
-#endif	/* CONFIG_BLK_DEV_IDEPCI */
-						msg = "not a PCI device";
-						goto parse_error;
-				default:	msg = "expected 'R' or 'P'";
-						goto parse_error;
-			}
-			digits = 0;
-			while (n > 0 && (d = ide_getxdigit(*p)) >= 0) {
-				reg = (reg << 4) | d;
-				--n;
-				++p;
-				++digits;
-			}
-			if (!digits || (digits > 4) || (is_pci && reg > 0xff)) {
-				msg = "bad/missing register number";
-				goto parse_error;
-			}
-			if (n-- == 0 || *p++ != ':') {
-				msg = "missing ':'";
-				goto parse_error;
-			}
-			digits = 0;
-			while (n > 0 && (d = ide_getxdigit(*p)) >= 0) {
-				val = (val << 4) | d;
-				--n;
-				++p;
-				++digits;
-			}
-			if (digits != 2 && digits != 4 && digits != 8) {
-				msg = "bad data, 2/4/8 digits required";
-				goto parse_error;
-			}
-			if (n > 0 && !isspace(*p)) {
-				msg = "expected whitespace after data";
-				goto parse_error;
-			}
-			while (n > 0 && isspace(*p)) {
-				--n;
-				++p;
-			}
-#ifdef CONFIG_BLK_DEV_IDEPCI
-			if (is_pci && (reg & ((digits >> 1) - 1))) {
-				msg = "misaligned access";
-				goto parse_error;
-			}
-#endif	/* CONFIG_BLK_DEV_IDEPCI */
-			if (for_real) {
-#if 0
-				printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? "PCI" : "non-PCI", reg, val, digits);
-#endif
-				if (is_pci) {
-#ifdef CONFIG_BLK_DEV_IDEPCI
-					int rc = 0;
-					struct pci_dev *dev = hwif->pci_dev;
-					switch (digits) {
-						case 2:	msg = "byte";
-							rc = pci_write_config_byte(dev, reg, val);
-							break;
-						case 4:	msg = "word";
-							rc = pci_write_config_word(dev, reg, val);
-							break;
-						case 8:	msg = "dword";
-							rc = pci_write_config_dword(dev, reg, val);
-							break;
-					}
-					if (rc) {
-						restore_flags(flags);	/* all CPUs */
-						printk("proc_ide_write_config: error writing %s at bus %02x dev %02x reg 0x%x value 0x%x\n",
-							msg, dev->bus->number, dev->devfn, reg, val);
-						printk("proc_ide_write_config: error %d\n", rc);
-						return -EIO;
-					}
-#endif	/* CONFIG_BLK_DEV_IDEPCI */
-				} else {	/* not pci */
-#if !defined(__mc68000__) && !defined(CONFIG_APUS)
-
-/*
- * Geert Uytterhoeven
- *
- * unless you can explain me what it really does.
- * On m68k, we don't have outw() and outl() yet,
- * and I need a good reason to implement it.
- * 
- * BTW, IMHO the main remaining portability problem with the IDE driver 
- * is that it mixes IO (ioport) and MMIO (iomem) access on different platforms.
- * 
- * I think all accesses should be done using
- * 
- *     ide_in[bwl](ide_device_instance, offset)
- *     ide_out[bwl](ide_device_instance, value, offset)
- * 
- * so the architecture specific code can #define ide_{in,out}[bwl] to the
- * appropriate function.
- * 
- */
-					switch (digits) {
-						case 2:	outb(val, reg);
-							break;
-						case 4:	outw(val, reg);
-							break;
-						case 8:	outl(val, reg);
-							break;
-					}
-#endif /* !__mc68000__ && !CONFIG_APUS */
-				}
-			}
-		}
-	} while (!for_real++);
-	restore_flags(flags);	/* all CPUs */
-	return count;
-parse_error:
-	restore_flags(flags);	/* all CPUs */
-	printk("parse error\n");
-	return xx_xx_parse_error(start, startn, msg);
-}
-
-static int proc_ide_read_config
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	char		*out = page;
-	int		len;
-
-#ifdef CONFIG_BLK_DEV_IDEPCI
-	ide_hwif_t	*hwif = data;
-	struct pci_dev	*dev = hwif->pci_dev;
-	if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL) && dev && dev->bus) {
-		int reg = 0;
-
-		out += sprintf(out, "pci bus %02x device %02x vid %04x did %04x channel %d\n",
-			dev->bus->number, dev->devfn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel);
-		do {
-			byte val;
-			int rc = pci_read_config_byte(dev, reg, &val);
-			if (rc) {
-				printk("proc_ide_read_config: error %d reading bus %02x dev %02x reg 0x%02x\n",
-					rc, dev->bus->number, dev->devfn, reg);
-				out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n');
-			} else
-				out += sprintf(out, "%02x%c", val, (++reg & 0xf) ? ' ' : '\n');
-		} while (reg < 0x100);
-	} else
-#endif	/* CONFIG_BLK_DEV_IDEPCI */
-		out += sprintf(out, "(none)\n");
-	len = out - page;
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
-
 static int ide_getdigit(char c)
 {
 	int digit;
@@ -373,20 +139,6 @@
 	return digit;
 }
 
-static int proc_ide_read_drivers
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	char		*out = page;
-	int		len;
-	struct ide_driver_s * driver;
-
-	for (driver = ide_drivers; driver; driver = driver->next) {
-		out += sprintf(out, "%s\n",driver->name);
-	}
-	len = out - page;
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
 static int proc_ide_read_imodel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -450,7 +202,7 @@
 	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
 
 	taskfile.sector_count = 0x01;
-	taskfile.command = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY ;
+	taskfile.command = (drive->type == ATA_DISK) ? WIN_IDENTIFY : WIN_PIDENTIFY ;
 
 	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
 }
@@ -594,9 +346,9 @@
 int proc_ide_read_capacity
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-	ide_drive_t	*drive = data;
-	ide_driver_t    *driver = drive->driver;
-	int		len;
+	ide_drive_t *drive = data;
+	struct ata_operations *driver = drive->driver;
+	int len;
 
 	if (!driver)
 		len = sprintf(page, "(none)\n");
@@ -629,58 +381,31 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_driver
-	(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-	ide_drive_t	*drive = (ide_drive_t *) data;
-	ide_driver_t	*driver = drive->driver;
-	int		len;
-
-	if (!driver)
-		len = sprintf(page, "(none)\n");
-	else
-		len = sprintf(page, "%s\n", driver->name);
-	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
-}
-
-static int proc_ide_write_driver
-	(struct file *file, const char *buffer, unsigned long count, void *data)
-{
-	ide_drive_t	*drive = data;
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-	if (ide_replace_subdriver(drive, buffer))
-		return -EINVAL;
-	return count;
-}
-
 static int proc_ide_read_media
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = data;
-	const char	*media;
+	const char	*type;
 	int		len;
 
-	switch (drive->media) {
-		case ide_disk:	media = "disk\n";
+	switch (drive->type) {
+		case ATA_DISK:	type = "disk\n";
 				break;
-		case ide_cdrom:	media = "cdrom\n";
+		case ATA_ROM:	type = "cdrom\n";
 				break;
-		case ide_tape:	media = "tape\n";
+		case ATA_TAPE:	type = "tape\n";
 				break;
-		case ide_floppy:media = "floppy\n";
+		case ATA_FLOPPY:type = "floppy\n";
 				break;
-		default:	media = "UNKNOWN\n";
+		default:	type = "UNKNOWN\n";
 				break;
 	}
-	strcpy(page,media);
-	len = strlen(media);
+	strcpy(page,type);
+	len = strlen(type);
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
 static ide_proc_entry_t generic_drive_entries[] = {
-	{ "driver",	S_IFREG|S_IRUGO,	proc_ide_read_driver,	proc_ide_write_driver },
 	{ "identify",	S_IFREG|S_IRUSR,	proc_ide_read_identify,	NULL },
 	{ "media",	S_IFREG|S_IRUGO,	proc_ide_read_media,	NULL },
 	{ "model",	S_IFREG|S_IRUGO,	proc_ide_read_dmodel,	NULL },
@@ -724,7 +449,7 @@
 
 	for (d = 0; d < MAX_DRIVES; d++) {
 		ide_drive_t *drive = &hwif->drives[d];
-		ide_driver_t *driver = drive->driver;
+		struct ata_operations *driver = drive->driver;
 
 		if (!drive->present)
 			continue;
@@ -745,35 +470,9 @@
 	}
 }
 
-void recreate_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-	struct proc_dir_entry *ent;
-	struct proc_dir_entry *parent = hwif->proc;
-	char name[64];
-
-	if (drive->present && !drive->proc) {
-		drive->proc = proc_mkdir(drive->name, parent);
-		if (drive->proc)
-			ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
-
-/*
- * assume that we have these already, however, should test FIXME!
- * if (driver) {
- *      ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
- *      ide_add_proc_entries(drive->proc, driver->proc, drive);
- * }
- *
- */
-		sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name);
-		ent = proc_symlink(drive->name, proc_ide_root, name);
-		if (!ent)
-			return;
-	}
-}
-
-void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
+static void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
 {
-	ide_driver_t *driver = drive->driver;
+	struct ata_operations *driver = drive->driver;
 
 	if (drive->proc) {
 		if (driver)
@@ -799,7 +498,6 @@
 
 static ide_proc_entry_t hwif_entries[] = {
 	{ "channel",	S_IFREG|S_IRUGO,	proc_ide_read_channel,	NULL },
-	{ "config",	S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config,	proc_ide_write_config },
 	{ "mate",	S_IFREG|S_IRUGO,	proc_ide_read_mate,	NULL },
 	{ "model",	S_IFREG|S_IRUGO,	proc_ide_read_imodel,	NULL },
 	{ NULL,	0, NULL, NULL }
@@ -852,9 +550,6 @@
 
 	create_proc_ide_interfaces();
 
-	create_proc_read_entry("drivers", 0, proc_ide_root,
-				proc_ide_read_drivers, NULL);
-
 #ifdef CONFIG_BLK_DEV_AEC62XX
 	if ((aec62xx_display_info) && (aec62xx_proc))
 		create_proc_info_entry("aec62xx", 0, proc_ide_root, aec62xx_display_info);
diff -urN linux-2.5.6-pre1/drivers/ide/ide-tape.c linux-2.5.6-pre2/drivers/ide/ide-tape.c
--- linux-2.5.6-pre1/drivers/ide/ide-tape.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/drivers/ide/ide-tape.c	Thu Feb 28 13:34:21 2002
@@ -6098,8 +6098,11 @@
 	}
 	idetape_chrdevs[minor].drive = NULL;
 	restore_flags (flags);	/* all CPUs (overkill?) */
-	DRIVER(drive)->busy = 0;
-	(void) ide_unregister_subdriver (drive);
+
+	/* FIXME: this appears to be totally wrong! */
+	ata_ops(drive)->busy = 0;
+
+	ide_unregister_subdriver (drive);
 	drive->driver_data = NULL;
 	devfs_unregister (tape->de_r);
 	devfs_unregister (tape->de_n);
@@ -6137,18 +6140,13 @@
 
 #endif
 
-int idetape_init (void);
-int idetape_reinit(ide_drive_t *drive);
+static int idetape_reinit(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
  */
-static ide_driver_t idetape_driver = {
-	name:			"ide-tape",
-	media:			ide_tape,
-	busy:			1,
-	supports_dma:		1,
-	supports_dsc_overlap: 	1,
+static struct ata_operations idetape_driver = {
+	owner:			THIS_MODULE,
 	cleanup:		idetape_cleanup,
 	standby:		NULL,
 	flushcache:		NULL,
@@ -6162,7 +6160,6 @@
 	pre_reset:		idetape_pre_reset,
 	capacity:		NULL,
 	proc:			idetape_proc,
-	driver_init:		idetape_init,
 	driver_reinit:		idetape_reinit,
 };
 
@@ -6178,90 +6175,10 @@
 	release:	idetape_chrdev_release,
 };
 
-int idetape_reinit (ide_drive_t *drive)
+/* This will propably just go entierly away... */
+static int idetape_reinit (ide_drive_t *drive)
 {
-#if 0
-	idetape_tape_t *tape;
-	int minor, failed = 0, supported = 0;
-/* DRIVER(drive)->busy++; */
-	MOD_INC_USE_COUNT;
-#if ONSTREAM_DEBUG
-        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
-#endif
-	if (!idetape_chrdev_present)
-		for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
-			idetape_chrdevs[minor].drive = NULL;
-
-	if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
-		ide_register_module (&idetape_module);
-		MOD_DEC_USE_COUNT;
-#if ONSTREAM_DEBUG
-		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
-#endif
-		return 0;
-	}
-	if (!idetape_chrdev_present &&
-	    devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
-		printk (KERN_ERR "ide-tape: Failed to register character device interface\n");
-		MOD_DEC_USE_COUNT;
-#if ONSTREAM_DEBUG
-		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
-#endif
-		return -EBUSY;
-	}
-	do {
-		if (!idetape_identify_device (drive, drive->id)) {
-			printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
-			continue;
-		}
-		if (drive->scsi) {
-			if (strstr(drive->id->model, "OnStream DI-30")) {
-				printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
-			} else {
-				printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
-				continue;
-			}
-		}
-		tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
-		if (tape == NULL) {
-			printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
-			continue;
-		}
-		if (ide_register_subdriver (drive, &idetape_driver)) {
-			printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (tape);
-			continue;
-		}
-		for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
-		idetape_setup (drive, tape, minor);
-		idetape_chrdevs[minor].drive = drive;
-		tape->de_r =
-		    devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
-				    HWIF(drive)->major, minor,
-				    S_IFCHR | S_IRUGO | S_IWUGO,
-				    &idetape_fops, NULL);
-		tape->de_n =
-		    devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
-				    HWIF(drive)->major, minor + 128,
-				    S_IFCHR | S_IRUGO | S_IWUGO,
-				    &idetape_fops, NULL);
-		devfs_register_tape (tape->de_r);
-		supported++; failed--;
-	} while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
-	if (!idetape_chrdev_present && !supported) {
-		devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
-	} else
-		idetape_chrdev_present = 1;
-	ide_register_module (&idetape_module);
-	MOD_DEC_USE_COUNT;
-#if ONSTREAM_DEBUG
-	printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
-#endif
-
-	return 0;
-#else
 	return 1;
-#endif
 }
 
 MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
@@ -6277,7 +6194,6 @@
 		if (drive != NULL && idetape_cleanup (drive))
 		printk (KERN_ERR "ide-tape: %s: cleanup_module() called while still busy\n", drive->name);
 	}
-	ide_unregister_module(&idetape_driver);
 }
 
 /*
@@ -6297,8 +6213,8 @@
 		for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
 			idetape_chrdevs[minor].drive = NULL;
 
-	if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
-		ide_register_module (&idetape_driver);
+	if ((drive = ide_scan_devices(ATA_TAPE, "ide-tape", NULL, failed++)) == NULL) {
+		revalidate_drives();
 		MOD_DEC_USE_COUNT;
 #if ONSTREAM_DEBUG
 		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
@@ -6352,12 +6268,12 @@
 				    &idetape_fops, NULL);
 		devfs_register_tape (tape->de_r);
 		supported++; failed--;
-	} while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
+	} while ((drive = ide_scan_devices(ATA_TAPE, "ide-tape", NULL, failed++)) != NULL);
 	if (!idetape_chrdev_present && !supported) {
 		devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
 	} else
 		idetape_chrdev_present = 1;
-	ide_register_module (&idetape_driver);
+	revalidate_drives();
 	MOD_DEC_USE_COUNT;
 #if ONSTREAM_DEBUG
 	printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
diff -urN linux-2.5.6-pre1/drivers/ide/ide-taskfile.c linux-2.5.6-pre2/drivers/ide/ide-taskfile.c
--- linux-2.5.6-pre1/drivers/ide/ide-taskfile.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/drivers/ide/ide-taskfile.c	Thu Feb 28 13:34:21 2002
@@ -42,6 +42,24 @@
 #define DTF(x...)
 #endif
 
+/*
+ * for now, taskfile requests are special :/
+ */
+static inline char *ide_map_rq(struct request *rq, unsigned long *flags)
+{
+	if (rq->bio)
+		return  bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
+	else
+		return rq->buffer + task_rq_offset(rq);
+}
+
+static inline void ide_unmap_rq(struct request *rq, char *to,
+				unsigned long *flags)
+{
+	if (rq->bio)
+	    bio_kunmap_irq(to, flags);
+}
+
 inline u32 task_read_24 (ide_drive_t *drive)
 {
 	return	(IN_BYTE(IDE_HCYL_REG)<<16) |
@@ -630,7 +648,7 @@
 
 	if (rq->errors >= ERROR_MAX) {
 		if (drive->driver != NULL)
-			DRIVER(drive)->end_request(0, HWGROUP(drive));
+			ata_ops(drive)->end_request(0, HWGROUP(drive));
 		else
 			ide_end_request(drive, 0);
 	} else {
@@ -1137,7 +1155,7 @@
 			nsect = mcount;
 		mcount -= nsect;
 
-		buffer = ide_map_buffer(rq, &flags);
+		buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
 		rq->sector += nsect;
 		rq->nr_sectors -= nsect;
 		rq->current_nr_sectors -= nsect;
@@ -1161,7 +1179,7 @@
 		 * re-entering us on the last transfer.
 		 */
 		taskfile_output_data(drive, buffer, nsect * SECTOR_WORDS);
-		ide_unmap_buffer(buffer, &flags);
+		bio_kunmap_irq(buffer, &flags);
 	} while (mcount);
 
 	drive->io_32bit = io_32bit;
diff -urN linux-2.5.6-pre1/drivers/ide/ide.c linux-2.5.6-pre2/drivers/ide/ide.c
--- linux-2.5.6-pre1/drivers/ide/ide.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/drivers/ide/ide.c	Thu Feb 28 13:34:21 2002
@@ -1,6 +1,4 @@
 /*
- *  linux/drivers/ide/ide.c		Version 6.31	June 9, 2000
- *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
 
@@ -114,22 +112,15 @@
  *			Native ATA-100 support
  *			Prep for Cascades Project
  * Version 6.32		4GB highmem support for DMA, and mapping of those for
- * 			PIO transfer (Jens Axboe)
+ *			PIO transfer (Jens Axboe)
  *
  *  Some additional driver compile-time options are in ./include/linux/ide.h
- *
- *  To do, in likely order of completion:
- *	- modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
- *
  */
 
-#define	REVISION	"Revision: 6.32"
-#define	VERSION		"Id: ide.c 6.32 2001/05/24"
+#define	VERSION	"7.0.0"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
-#define _IDE_C			/* Tell ide.h it's really us */
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -153,6 +144,8 @@
 #include <linux/completion.h>
 #include <linux/reboot.h>
 #include <linux/cdrom.h>
+#include <linux/device.h>
+#include <linux/kmod.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -162,17 +155,100 @@
 
 #include "ide_modes.h"
 
-#ifdef CONFIG_KMOD
-#include <linux/kmod.h>
-#endif /* CONFIG_KMOD */
+/* Constant tables for PIO mode programming:
+ */
 
-/* default maximum number of failures */
-#define IDE_DEFAULT_MAX_FAILURES 	1
+const ide_pio_timings_t ide_pio_timings[6] = {
+	{ 70,	165,	600 },	/* PIO Mode 0 */
+	{ 50,	125,	383 },	/* PIO Mode 1 */
+	{ 30,	100,	240 },	/* PIO Mode 2 */
+	{ 30,	80,	180 },	/* PIO Mode 3 with IORDY */
+	{ 25,	70,	120 },	/* PIO Mode 4 with IORDY */
+	{ 20,	50,	100 }	/* PIO Mode 5 with IORDY (nonstandard) */
+};
 
-static const byte ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR, IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR };
+/*
+ * Black list. Some drives incorrectly report their maximal PIO mode,
+ * at least in respect to CMD640. Here we keep info on some known drives.
+ */
+static struct ide_pio_info {
+	const char	*name;
+	int		pio;
+} ide_pio_blacklist [] = {
+/*	{ "Conner Peripherals 1275MB - CFS1275A", 4 }, */
+	{ "Conner Peripherals 540MB - CFS540A", 3 },
+
+	{ "WDC AC2700",  3 },
+	{ "WDC AC2540",  3 },
+	{ "WDC AC2420",  3 },
+	{ "WDC AC2340",  3 },
+	{ "WDC AC2250",  0 },
+	{ "WDC AC2200",  0 },
+	{ "WDC AC21200", 4 },
+	{ "WDC AC2120",  0 },
+	{ "WDC AC2850",  3 },
+	{ "WDC AC1270",  3 },
+	{ "WDC AC1170",  1 },
+	{ "WDC AC1210",  1 },
+	{ "WDC AC280",   0 },
+/*	{ "WDC AC21000", 4 }, */
+	{ "WDC AC31000", 3 },
+	{ "WDC AC31200", 3 },
+/*	{ "WDC AC31600", 4 }, */
+
+	{ "Maxtor 7131 AT", 1 },
+	{ "Maxtor 7171 AT", 1 },
+	{ "Maxtor 7213 AT", 1 },
+	{ "Maxtor 7245 AT", 1 },
+	{ "Maxtor 7345 AT", 1 },
+	{ "Maxtor 7546 AT", 3 },
+	{ "Maxtor 7540 AV", 3 },
+
+	{ "SAMSUNG SHD-3121A", 1 },
+	{ "SAMSUNG SHD-3122A", 1 },
+	{ "SAMSUNG SHD-3172A", 1 },
+
+/*	{ "ST51080A", 4 },
+ *	{ "ST51270A", 4 },
+ *	{ "ST31220A", 4 },
+ *	{ "ST31640A", 4 },
+ *	{ "ST32140A", 4 },
+ *	{ "ST3780A",  4 },
+ */
+	{ "ST5660A",  3 },
+	{ "ST3660A",  3 },
+	{ "ST3630A",  3 },
+	{ "ST3655A",  3 },
+	{ "ST3391A",  3 },
+	{ "ST3390A",  1 },
+	{ "ST3600A",  1 },
+	{ "ST3290A",  0 },
+	{ "ST3144A",  0 },
+	{ "ST3491A",  1 },	/* reports 3, should be 1 or 2 (depending on */	
+				/* drive) according to Seagates FIND-ATA program */
+
+	{ "QUANTUM ELS127A", 0 },
+	{ "QUANTUM ELS170A", 0 },
+	{ "QUANTUM LPS240A", 0 },
+	{ "QUANTUM LPS210A", 3 },
+	{ "QUANTUM LPS270A", 3 },
+	{ "QUANTUM LPS365A", 3 },
+	{ "QUANTUM LPS540A", 3 },
+	{ "QUANTUM LIGHTNING 540A", 3 },
+	{ "QUANTUM LIGHTNING 730A", 3 },
+
+        { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
+        { "QUANTUM FIREBALL_640", 3 }, 
+        { "QUANTUM FIREBALL_1080", 3 },
+        { "QUANTUM FIREBALL_1280", 3 },
+	{ NULL,	0 }
+};
+
+/* default maximum number of failures */
+#define IDE_DEFAULT_MAX_FAILURES	1
 
 static int	idebus_parameter; /* holds the "idebus=" parameter */
-static int	system_bus_speed; /* holds what we think is VESA/PCI bus speed */
+int system_bus_speed; /* holds what we think is VESA/PCI bus speed */
 static int	initializing;     /* set while initializing built-in drivers */
 
 /*
@@ -196,14 +272,109 @@
 int noautodma = 0;
 
 /*
- * This is the anchor of the single linked list of ide device type drivers.
+ * This is declared extern in ide.h, for access by other IDE modules:
  */
-struct ide_driver_s *ide_drivers;
+ide_hwif_t	ide_hwifs[MAX_HWIFS];	/* master data repository */
+
 
 /*
- * This is declared extern in ide.h, for access by other IDE modules:
+ * This routine searches the ide_pio_blacklist for an entry
+ * matching the start/whole of the supplied model name.
+ *
+ * Returns -1 if no match found.
+ * Otherwise returns the recommended PIO mode from ide_pio_blacklist[].
  */
-ide_hwif_t	ide_hwifs[MAX_HWIFS];	/* master data repository */
+int ide_scan_pio_blacklist (char *model)
+{
+	struct ide_pio_info *p;
+
+	for (p = ide_pio_blacklist; p->name != NULL; p++) {
+		if (strncmp(p->name, model, strlen(p->name)) == 0)
+			return p->pio;
+	}
+	return -1;
+}
+
+/*
+ * This routine returns the recommended PIO settings for a given drive,
+ * based on the drive->id information and the ide_pio_blacklist[].
+ * This is used by most chipset support modules when "auto-tuning".
+ */
+
+/*
+ * Drive PIO mode auto selection
+ */
+byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d)
+{
+	int pio_mode;
+	int cycle_time = 0;
+	int use_iordy = 0;
+	struct hd_driveid* id = drive->id;
+	int overridden  = 0;
+	int blacklisted = 0;
+
+	if (mode_wanted != 255) {
+		pio_mode = mode_wanted;
+	} else if (!drive->id) {
+		pio_mode = 0;
+	} else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
+		overridden = 1;
+		blacklisted = 1;
+		use_iordy = (pio_mode > 2);
+	} else {
+		pio_mode = id->tPIO;
+		if (pio_mode > 2) {	/* 2 is maximum allowed tPIO value */
+			pio_mode = 2;
+			overridden = 1;
+		}
+		if (id->field_valid & 2) {	  /* drive implements ATA2? */
+			if (id->capability & 8) { /* drive supports use_iordy? */
+				use_iordy = 1;
+				cycle_time = id->eide_pio_iordy;
+				if (id->eide_pio_modes & 7) {
+					overridden = 0;
+					if (id->eide_pio_modes & 4)
+						pio_mode = 5;
+					else if (id->eide_pio_modes & 2)
+						pio_mode = 4;
+					else
+						pio_mode = 3;
+				}
+			} else {
+				cycle_time = id->eide_pio;
+			}
+		}
+
+#if 0
+		if (drive->id->major_rev_num & 0x0004) printk("ATA-2 ");
+#endif
+
+		/*
+		 * Conservative "downgrade" for all pre-ATA2 drives
+		 */
+		if (pio_mode && pio_mode < 4) {
+			pio_mode--;
+			overridden = 1;
+#if 0
+			use_iordy = (pio_mode > 2);
+#endif
+			if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
+				cycle_time = 0; /* use standard timing */
+		}
+	}
+	if (pio_mode > max_mode) {
+		pio_mode = max_mode;
+		cycle_time = 0;
+	}
+	if (d) {
+		d->pio_mode = pio_mode;
+		d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
+		d->use_iordy = use_iordy;
+		d->overridden = overridden;
+		d->blacklisted = blacklisted;
+	}
+	return pio_mode;
+}
 
 #if (DISK_RECOVERY_TIME > 0)
 /*
@@ -238,6 +409,11 @@
  */
 static void init_hwif_data (unsigned int index)
 {
+	static const byte ide_major[] = {
+		IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR,
+		IDE5_MAJOR, IDE6_MAJOR, IDE7_MAJOR, IDE8_MAJOR, IDE9_MAJOR
+	};
+
 	unsigned int unit;
 	hw_regs_t hw;
 	ide_hwif_t *hwif = &ide_hwifs[index];
@@ -256,16 +432,13 @@
 	if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA)
 		hwif->noprobe = 1; /* may be overridden by ide_setup() */
 #endif /* CONFIG_BLK_DEV_HD */
-	hwif->major	= ide_hwif_to_major[index];
-	hwif->name[0]	= 'i';
-	hwif->name[1]	= 'd';
-	hwif->name[2]	= 'e';
-	hwif->name[3]	= '0' + index;
+	hwif->major = ide_major[index];
+	sprintf(hwif->name, "ide%d", index);
 	hwif->bus_state = BUSSTATE_ON;
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
 
-		drive->media			= ide_disk;
+		drive->type			= ATA_DISK;
 		drive->select.all		= (unit<<4)|0xa0;
 		drive->hwif			= hwif;
 		drive->ctl			= 0x08;
@@ -273,9 +446,7 @@
 		drive->bad_wstat		= BAD_W_STAT;
 		drive->special.b.recalibrate	= 1;
 		drive->special.b.set_geometry	= 1;
-		drive->name[0]			= 'h';
-		drive->name[1]			= 'd';
-		drive->name[2]			= 'a' + (index * MAX_DRIVES) + unit;
+		sprintf(drive->name, "hd%c", 'a' + (index * MAX_DRIVES) + unit);
 		drive->max_failures		= IDE_DEFAULT_MAX_FAILURES;
 		init_waitqueue_head(&drive->wqueue);
 	}
@@ -313,7 +484,6 @@
 	ide_init_default_hwifs();
 
 	idebus_parameter = 0;
-	system_bus_speed = 0;
 }
 
 /*
@@ -347,30 +517,6 @@
 	return 0;	/* no, it is not a flash memory card */
 }
 
-/*
- * ide_system_bus_speed() returns what we think is the system VESA/PCI
- * bus speed (in MHz).  This is used for calculating interface PIO timings.
- * The default is 40 for known PCI systems, 50 otherwise.
- * The "idebus=xx" parameter can be used to override this value.
- * The actual value to be used is computed/displayed the first time through.
- */
-int ide_system_bus_speed (void)
-{
-	if (!system_bus_speed) {
-		if (idebus_parameter)
-			system_bus_speed = idebus_parameter;	/* user supplied value */
-#ifdef CONFIG_PCI
-		else if (pci_present())
-			system_bus_speed = 33;	/* safe default value for PCI */
-#endif /* CONFIG_PCI */
-		else
-			system_bus_speed = 50;	/* safe default value for VESA and PCI */
-		printk("ide: Assuming %dMHz system bus speed for PIO modes%s\n", system_bus_speed,
-			idebus_parameter ? "" : "; override with idebus=xx");
-	}
-	return system_bus_speed;
-}
-
 int __ide_end_request(ide_drive_t *drive, int uptodate, int nr_secs)
 {
 	struct request *rq;
@@ -436,19 +582,18 @@
 }
 
 /*
- * current_capacity() returns the capacity (in sectors) of a drive
- * according to its current geometry/LBA settings.
+ * The capacity of a drive according to its current geometry/LBA settings in
+ * sectors.
  */
 unsigned long current_capacity (ide_drive_t *drive)
 {
-	if (!drive->present)
+	if (!drive->present || !drive->driver)
 		return 0;
-	if (drive->driver != NULL)
-		return DRIVER(drive)->capacity(drive);
-	return 0;
+	return ata_ops(drive)->capacity(drive);
 }
 
 extern struct block_device_operations ide_fops[];
+
 /*
  * ide_geninit() is called exactly *once* for each interface.
  */
@@ -462,7 +607,7 @@
 
 		if (!drive->present)
 			continue;
-		if (drive->media!=ide_disk && drive->media!=ide_floppy)
+		if (drive->type != ATA_DISK && drive->type != ATA_FLOPPY)
 			continue;
 		register_disk(gd,mk_kdev(hwif->major,unit<<PARTN_BITS),
 #ifdef CONFIG_BLK_DEV_ISAPNP
@@ -573,7 +718,7 @@
 static void pre_reset (ide_drive_t *drive)
 {
 	if (drive->driver != NULL)
-		DRIVER(drive)->pre_reset(drive);
+		ata_ops(drive)->pre_reset(drive);
 
 	if (!drive->keep_settings) {
 		if (drive->using_dma) {
@@ -614,7 +759,7 @@
 	__cli();		/* local CPU only */
 
 	/* For an ATAPI device, first try an ATAPI SRST. */
-	if (drive->media != ide_disk && !do_not_try_atapi) {
+	if (drive->type != ATA_DISK && !do_not_try_atapi) {
 		pre_reset(drive);
 		SELECT_DRIVE(hwif,drive);
 		udelay (20);
@@ -783,7 +928,7 @@
 		err = GET_ERR();
 		printk("%s: %s: error=0x%02x", drive->name, msg, err);
 #if FANCY_STATUS_DUMPS
-		if (drive->media == ide_disk) {
+		if (drive->type == ATA_DISK) {
 			printk(" { ");
 			if (err & ABRT_ERR)	printk("DriveStatusError ");
 			if (err & ICRC_ERR)	printk("%s", (err & ABRT_ERR) ? "BadCRC " : "BadSector ");
@@ -842,7 +987,7 @@
 {
 	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;
 
-	if (drive->media != ide_disk)
+	if (drive->type != ATA_DISK)
 		return;
 	while (i > 0) {
 		u32 buffer[16];
@@ -878,7 +1023,7 @@
 	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
 	} else {
-		if (drive->media == ide_disk && (stat & ERR_STAT)) {
+		if (drive->type == ATA_DISK && (stat & ERR_STAT)) {
 			/* err has different meaning on cdrom and tape */
 			if (err == ABRT_ERR) {
 				if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY)
@@ -898,8 +1043,9 @@
 		OUT_BYTE(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	/* force an abort */
 
 	if (rq->errors >= ERROR_MAX) {
+		/* ATA-PATTERN */
 		if (drive->driver != NULL)
-			DRIVER(drive)->end_request(drive, 0);
+			ata_ops(drive)->end_request(drive, 0);
 		else
 			ide_end_request(drive, 0);
 	} else {
@@ -971,7 +1117,7 @@
 		if (tuneproc != NULL)
 			tuneproc(drive, drive->tune_req);
 	} else if (drive->driver != NULL) {
-		return DRIVER(drive)->special(drive);
+		return ata_ops(drive)->special(drive);
 	} else if (s->all) {
 		printk("%s: bad special flag: 0x%02x\n", drive->name, s->all);
 		s->all = 0;
@@ -1169,8 +1315,8 @@
 	block    = rq->sector;
 
 	/* Strange disk manager remap */
-	if ((rq->flags & REQ_CMD) && 
-	    (drive->media == ide_disk || drive->media == ide_floppy)) {
+	if ((rq->flags & REQ_CMD) &&
+	    (drive->type == ATA_DISK || drive->type == ATA_FLOPPY)) {
 		block += drive->sect0;
 	}
 	/* Yecch - this will shift the entire interval,
@@ -1185,7 +1331,7 @@
 	SELECT_DRIVE(hwif, drive);
 	if (ide_wait_stat(&startstop, drive, drive->ready_stat,
 			  BUSY_STAT|DRQ_STAT, WAIT_READY)) {
-		printk("%s: drive not ready for command\n", drive->name);
+		printk(KERN_WARNING "%s: drive not ready for command\n", drive->name);
 		return startstop;
 	}
 	if (!drive->special.all) {
@@ -1193,16 +1339,16 @@
 			return execute_drive_cmd(drive, rq);
 
 		if (drive->driver != NULL) {
-			return (DRIVER(drive)->do_request(drive, rq, block));
+			return ata_ops(drive)->do_request(drive, rq, block);
 		}
-		printk("%s: media type %d not supported\n",
-		       drive->name, drive->media);
+		printk(KERN_WARNING "%s: device type %d not supported\n",
+		       drive->name, drive->type);
 		goto kill_rq;
 	}
 	return do_special(drive);
 kill_rq:
 	if (drive->driver != NULL)
-		DRIVER(drive)->end_request(drive, 0);
+		ata_ops(drive)->end_request(drive, 0);
 	else
 		ide_end_request(drive, 0);
 	return ide_stopped;
@@ -1626,8 +1772,8 @@
 		 * so in that case we just ignore it and hope it goes away.
 		 */
 #ifdef CONFIG_BLK_DEV_IDEPCI
-		if (IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))
-#endif	/* CONFIG_BLK_DEV_IDEPCI */
+		if (hwif->pci_dev && !hwif->pci_dev->vendor)
+#endif
 		{
 			/*
 			 * Probably not a shared PCI interrupt,
@@ -1639,7 +1785,7 @@
 			/*
 			 * Whack the status register, just in case we have a leftover pending IRQ.
 			 */
-			(void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
+			IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 		}
 		goto out_lock;
@@ -1832,8 +1978,8 @@
 	if (res)
 		goto leave;
 
-	if (DRIVER(drive)->revalidate)
-		DRIVER(drive)->revalidate(drive);
+	if (ata_ops(drive)->revalidate)
+		ata_ops(drive)->revalidate(drive);
 
  leave:
 	drive->busy = 0;
@@ -1842,7 +1988,11 @@
 	return res;
 }
 
-static void revalidate_drives (void)
+/*
+ * Look again for all drives in the system on all interfaces.  This is used
+ * after a new driver cathegory has been loaded as module.
+ */
+void revalidate_drives (void)
 {
 	ide_hwif_t *hwif;
 	ide_drive_t *drive;
@@ -1855,7 +2005,7 @@
 			if (drive->revalidate) {
 				drive->revalidate = 0;
 				if (!initializing)
-					(void) ide_revalidate_disk(mk_kdev(hwif->major, unit<<PARTN_BITS));
+					ide_revalidate_disk(mk_kdev(hwif->major, unit<<PARTN_BITS));
 			}
 		}
 	}
@@ -1870,15 +2020,12 @@
 static void ide_driver_module (void)
 {
 	int index;
-	struct ide_driver_s *d;
 
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (ide_hwifs[index].present)
 			goto search;
 	ide_probe_module();
 search:
-	for (d = ide_drivers; d != NULL; d = d->next)
-		d->driver_init();
 
 	revalidate_drives();
 }
@@ -1891,27 +2038,44 @@
 		return -ENXIO;
 	if (drive->driver == NULL)
 		ide_driver_module();
+
+	/* Request a particular device type module.
+	 *
+	 * FIXME: The function which should rather requests the drivers is
+	 * ide_driver_module(), since it seems illogical and even a bit
+	 * dangerous to delay this until open time!
+	 */
+
 #ifdef CONFIG_KMOD
 	if (drive->driver == NULL) {
-		if (drive->media == ide_disk)
-			(void) request_module("ide-disk");
-		if (drive->media == ide_cdrom)
-			(void) request_module("ide-cd");
-		if (drive->media == ide_tape)
-			(void) request_module("ide-tape");
-		if (drive->media == ide_floppy)
-			(void) request_module("ide-floppy");
+		switch (drive->type) {
+			case ATA_DISK:
+				request_module("ide-disk");
+				break;
+			case ATA_ROM:
+				request_module("ide-cd");
+				break;
+			case ATA_TAPE:
+				request_module("ide-tape");
+				break;
+			case ATA_FLOPPY:
+				request_module("ide-floppy");
+				break;
 #if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI)
-		if (drive->media == ide_scsi)
-			(void) request_module("ide-scsi");
-#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
+			case ATA_SCSI:
+				request_module("ide-scsi");
+				break;
+#endif
+			default:
+				/* nothing to be done about it */ ;
+		}
 	}
 #endif /* CONFIG_KMOD */
 	while (drive->busy)
 		sleep_on(&drive->wqueue);
 	drive->usage++;
 	if (drive->driver != NULL)
-		return DRIVER(drive)->open(inode, filp, drive);
+		return ata_ops(drive)->open(inode, filp, drive);
 	printk ("%s: driver not present\n", drive->name);
 	drive->usage--;
 	return -ENXIO;
@@ -1928,27 +2092,11 @@
 	if ((drive = get_info_ptr(inode->i_rdev)) != NULL) {
 		drive->usage--;
 		if (drive->driver != NULL)
-			DRIVER(drive)->release(inode, file, drive);
+			ata_ops(drive)->release(inode, file, drive);
 	}
 	return 0;
 }
 
-int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
-{
-	if (!drive->present || drive->busy || drive->usage)
-		goto abort;
-	if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
-		goto abort;
-	strncpy(drive->driver_req, driver, 9);
-	ide_driver_module();
-	drive->driver_req[0] = 0;
-	ide_driver_module();
-	if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))
-		return 0;
-abort:
-	return 1;
-}
-
 #ifdef CONFIG_PROC_FS
 ide_proc_entry_t generic_subdriver_entries[] = {
 	{ "capacity",	S_IFREG|S_IRUGO,	proc_ide_read_capacity,	NULL },
@@ -2009,13 +2157,14 @@
 	hwif = &ide_hwifs[index];
 	if (!hwif->present)
 		goto abort;
+	put_device(&hwif->device);
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		drive = &hwif->drives[unit];
 		if (!drive->present)
 			continue;
 		if (drive->busy || drive->usage)
 			goto abort;
-		if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+		if (drive->driver != NULL && ata_ops(drive)->cleanup(drive))
 			goto abort;
 	}
 	hwif->present = 0;
@@ -2147,10 +2296,8 @@
 	hwif->udma_four		= old_hwif.udma_four;
 #ifdef CONFIG_BLK_DEV_IDEPCI
 	hwif->pci_dev		= old_hwif.pci_dev;
-	hwif->pci_devid		= old_hwif.pci_devid;
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 	hwif->straight8		= old_hwif.straight8;
-	hwif->hwif_data		= old_hwif.hwif_data;
 abort:
 	restore_flags(flags);	/* all CPUs */
 }
@@ -2406,7 +2553,7 @@
 
 static int set_using_dma (ide_drive_t *drive, int arg)
 {
-	if (!drive->driver || !DRIVER(drive)->supports_dma)
+	if (!drive->driver)
 		return -EPERM;
 	if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
 		return -EPERM;
@@ -2493,66 +2640,6 @@
 #endif /* CONFIG_BLK_DEV_IDECS */
 }
 
-int system_bus_clock (void)
-{
-	return((int) ((!system_bus_speed) ? ide_system_bus_speed() : system_bus_speed ));
-}
-
-int ide_reinit_drive (ide_drive_t *drive)
-{
-	switch (drive->media) {
-#ifdef CONFIG_BLK_DEV_IDECD
-		case ide_cdrom:
-		{
-			extern int ide_cdrom_reinit(ide_drive_t *drive);
-			if (ide_cdrom_reinit(drive))
-				return 1;
-			break;
-		}
-#endif /* CONFIG_BLK_DEV_IDECD */
-#ifdef CONFIG_BLK_DEV_IDEDISK
-		case ide_disk:
-		{
-			extern int idedisk_reinit(ide_drive_t *drive);
-			if (idedisk_reinit(drive))
-				return 1;
-			break;
-		}
-#endif /* CONFIG_BLK_DEV_IDEDISK */
-#ifdef CONFIG_BLK_DEV_IDEFLOPPY
-		case ide_floppy:
-		{
-			extern int idefloppy_reinit(ide_drive_t *drive);
-			if (idefloppy_reinit(drive))
-				return 1;
-			break;
-		}
-#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
-#ifdef CONFIG_BLK_DEV_IDETAPE
-		case ide_tape:
-		{
-			extern int idetape_reinit(ide_drive_t *drive);
-			if (idetape_reinit(drive))
-				return 1;
-			break;
-		}
-#endif /* CONFIG_BLK_DEV_IDETAPE */
-#ifdef CONFIG_BLK_DEV_IDESCSI
-/*
- *              {
- *                      extern int idescsi_reinit(ide_drive_t *drive);
- *                      if (idescsi_reinit(drive))
- *                              return 1;
- *                      break;
- * }
- */
-#endif /* CONFIG_BLK_DEV_IDESCSI */
-		default:
-			return 1;
-	}
-	return 0;
-}
-
 static int ide_ioctl (struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
@@ -2594,7 +2681,9 @@
 		{
 			struct hd_geometry *loc = (struct hd_geometry *) arg;
 			unsigned short bios_cyl = drive->bios_cyl; /* truncate */
-			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
+
+			if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
+				return -EINVAL;
 			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
 			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
 			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
@@ -2606,7 +2695,9 @@
 		case HDIO_GETGEO_BIG:
 		{
 			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
-			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
+
+			if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
+				return -EINVAL;
 
 			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
 			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
@@ -2619,7 +2710,8 @@
 		case HDIO_GETGEO_BIG_RAW:
 		{
 			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
-			if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
+			if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
+				return -EINVAL;
 			if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT;
 			if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT;
 			if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
@@ -2654,15 +2746,15 @@
 		case HDIO_DRIVE_TASKFILE:
 		        if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
 				return -EACCES;
-			switch(drive->media) {
-				case ide_disk:
+			switch(drive->type) {
+				case ATA_DISK:
 					return ide_taskfile_ioctl(drive, inode, file, cmd, arg);
 #ifdef CONFIG_PKT_TASK_IOCTL
-				case ide_cdrom:
-				case ide_tape:
-				case ide_floppy:
+				case ATA_CDROM:
+				case ATA_TAPE:
+				case ATA_FLOPPY:
 					return pkt_taskfile_ioctl(drive, inode, file, cmd, arg);
-#endif /* CONFIG_PKT_TASK_IOCTL */
+#endif
 				default:
 					return -ENOMSG;
 			}
@@ -2695,12 +2787,11 @@
 			return 0;
 		case HDIO_SET_NICE:
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-			if (drive->driver == NULL)
-				return -EPERM;
 			if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
 				return -EPERM;
 			drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
-			if (drive->dsc_overlap && !DRIVER(drive)->supports_dsc_overlap) {
+			/* Only CD-ROM's and tapes support DSC overlap. */
+			if (drive->dsc_overlap && !(drive->type == ATA_ROM || drive->type == ATA_TAPE)) {
 				drive->dsc_overlap = 0;
 				return -EPERM;
 			}
@@ -2776,7 +2867,7 @@
 
 		default:
 			if (drive->driver != NULL)
-				return DRIVER(drive)->ioctl(drive, inode, file, cmd, arg);
+				return ata_ops(drive)->ioctl(drive, inode, file, cmd, arg);
 			return -EPERM;
 	}
 }
@@ -2788,7 +2879,7 @@
 	if ((drive = get_info_ptr(i_rdev)) == NULL)
 		return -ENODEV;
 	if (drive->driver != NULL)
-		return DRIVER(drive)->media_change(drive);
+		return ata_ops(drive)->media_change(drive);
 	return 0;
 }
 
@@ -2972,7 +3063,6 @@
 	const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1);
 	const char max_hwif  = '0' + (MAX_HWIFS - 1);
 
-	
 	if (strncmp(s,"hd",2) == 0 && s[2] == '=')	/* hd= is for hd.c   */
 		return 0;				/* driver and not us */
 
@@ -3050,7 +3140,7 @@
 				goto done;
 			case -4: /* "cdrom" */
 				drive->present = 1;
-				drive->media = ide_cdrom;
+				drive->type = ATA_ROM;
 				hwif->noprobe = 0;
 				goto done;
 			case -5: /* "serialize" */
@@ -3087,7 +3177,7 @@
 				goto bad_option;
 #endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
 			case 3: /* cyl,head,sect */
-				drive->media	= ide_disk;
+				drive->type	= ATA_DISK;
 				drive->cyl	= drive->bios_cyl  = vals[0];
 				drive->head	= drive->bios_head = vals[1];
 				drive->sect	= drive->bios_sect = vals[2];
@@ -3389,7 +3479,7 @@
 	}
 #endif /* __mc68000__ || CONFIG_APUS */
 
-	(void) ideprobe_init();
+	ideprobe_init();
 
 #if defined(__mc68000__) || defined(CONFIG_APUS)
 	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) {
@@ -3404,27 +3494,27 @@
 #endif
 
 	/*
-	 * Attempt to match drivers for the available drives
+	 * Initialize all device type driver modules.
 	 */
 #ifdef CONFIG_BLK_DEV_IDEDISK
-	(void) idedisk_init();
-#endif /* CONFIG_BLK_DEV_IDEDISK */
+	idedisk_init();
+#endif
 #ifdef CONFIG_BLK_DEV_IDECD
-	(void) ide_cdrom_init();
-#endif /* CONFIG_BLK_DEV_IDECD */
+	ide_cdrom_init();
+#endif
 #ifdef CONFIG_BLK_DEV_IDETAPE
-	(void) idetape_init();
-#endif /* CONFIG_BLK_DEV_IDETAPE */
+	idetape_init();
+#endif
 #ifdef CONFIG_BLK_DEV_IDEFLOPPY
-	(void) idefloppy_init();
-#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
+	idefloppy_init();
+#endif
 #ifdef CONFIG_BLK_DEV_IDESCSI
  #ifdef CONFIG_SCSI
-	(void) idescsi_init();
+	idescsi_init();
  #else
     #warning ide scsi-emulation selected but no SCSI-subsystem in kernel
  #endif
-#endif /* CONFIG_BLK_DEV_IDESCSI */
+#endif
 }
 
 static int default_cleanup (ide_drive_t *drive)
@@ -3500,7 +3590,10 @@
 	return 0;
 }
 
-ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n)
+/*
+ * Lookup IDE devices, which requested a particular deriver
+ */
+ide_drive_t *ide_scan_devices(byte type, const char *name, struct ata_operations *driver, int n)
 {
 	unsigned int unit, index, i;
 
@@ -3513,14 +3606,17 @@
 			char *req = drive->driver_req;
 			if (*req && !strstr(name, req))
 				continue;
-			if (drive->present && drive->media == media && drive->driver == driver && ++i > n)
+			if (drive->present && drive->type == type && drive->driver == driver && ++i > n)
 				return drive;
 		}
 	}
 	return NULL;
 }
 
-int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver)
+/*
+ * This is in fact registering a drive not a driver.
+ */
+int ide_register_subdriver(ide_drive_t *drive, struct ata_operations *driver)
 {
 	unsigned long flags;
 
@@ -3564,18 +3660,24 @@
 	    driver->driver_reinit = default_driver_reinit;
 
 	restore_flags(flags);		/* all CPUs */
+	/* FIXME: Check what this magic number is supposed to be about? */
 	if (drive->autotune != 2) {
-		if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) {
+		if (HWIF(drive)->dmaproc != NULL) {
+
 			/*
-			 * Force DMAing for the beginning of the check.
-			 * Some chipsets appear to do interesting things,
-			 * if not checked and cleared.
+			 * Force DMAing for the beginning of the check.  Some
+			 * chipsets appear to do interesting things, if not
+			 * checked and cleared.
+			 *
 			 *   PARANOIA!!!
 			 */
-			(void) (HWIF(drive)->dmaproc(ide_dma_off_quietly, drive));
-			(void) (HWIF(drive)->dmaproc(ide_dma_check, drive));
+
+			HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);
+			HWIF(drive)->dmaproc(ide_dma_check, drive);
 		}
-		drive->dsc_overlap = (drive->next != drive && driver->supports_dsc_overlap);
+		/* Only CD-ROMs and tape drives support DSC overlap. */
+		drive->dsc_overlap = (drive->next != drive
+				&& (drive->type == ATA_ROM || drive->type == ATA_TAPE));
 		drive->nice1 = 1;
 	}
 	drive->revalidate = 1;
@@ -3587,13 +3689,13 @@
 	return 0;
 }
 
-int ide_unregister_subdriver (ide_drive_t *drive)
+int ide_unregister_subdriver(ide_drive_t *drive)
 {
 	unsigned long flags;
 
 	save_flags(flags);		/* all CPUs */
 	cli();				/* all CPUs */
-	if (drive->usage || drive->busy || drive->driver == NULL || DRIVER(drive)->busy) {
+	if (drive->usage || drive->busy || drive->driver == NULL || ata_ops(drive)->busy) {
 		restore_flags(flags);	/* all CPUs */
 		return 1;
 	}
@@ -3601,7 +3703,7 @@
 	pnpide_init(0);
 #endif /* CONFIG_BLK_DEV_ISAPNP */
 #ifdef CONFIG_PROC_FS
-	ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc);
+	ide_remove_proc_entries(drive->proc, ata_ops(drive)->proc);
 	ide_remove_proc_entries(drive->proc, generic_subdriver_entries);
 #endif
 	auto_remove_settings(drive);
@@ -3610,30 +3712,29 @@
 	return 0;
 }
 
-int ide_register_module (struct ide_driver_s *d)
-{
-	struct ide_driver_s *p = ide_drivers;
 
-	while (p) {
-		if (p == d)
-			return 1;
-		p = p->next;
-	}
-	d->next = ide_drivers;
-	ide_drivers = d;
-	revalidate_drives();
+/*
+ * Register an ATA driver for a particular device type.
+ */
+
+int register_ata_driver(unsigned int type, struct ata_operations *driver)
+{
 	return 0;
 }
 
-void ide_unregister_module (struct ide_driver_s *d)
-{
-	struct ide_driver_s **p;
+EXPORT_SYMBOL(register_ata_driver);
 
-	for (p = &ide_drivers; (*p) && (*p) != d; p = &((*p)->next));
-	if (*p)
-		*p = (*p)->next;
+/*
+ * Unregister an ATA driver for a particular device type.
+ */
+
+int unregister_ata_driver(unsigned int type, struct ata_operations *driver)
+{
+	return 0;
 }
 
+EXPORT_SYMBOL(unregister_ata_driver);
+
 struct block_device_operations ide_fops[] = {{
 	owner:			THIS_MODULE,
 	open:			ide_open,
@@ -3644,9 +3745,8 @@
 }};
 
 EXPORT_SYMBOL(ide_hwifs);
-EXPORT_SYMBOL(ide_register_module);
-EXPORT_SYMBOL(ide_unregister_module);
 EXPORT_SYMBOL(ide_spin_wait_hwgroup);
+EXPORT_SYMBOL(revalidate_drives);
 
 /*
  * Probe module
@@ -3657,10 +3757,8 @@
 EXPORT_SYMBOL(drive_is_flashcard);
 EXPORT_SYMBOL(ide_timer_expiry);
 EXPORT_SYMBOL(ide_intr);
-EXPORT_SYMBOL(ide_fops);
 EXPORT_SYMBOL(ide_get_queue);
 EXPORT_SYMBOL(ide_add_generic_settings);
-EXPORT_SYMBOL(ide_devfs_handle);
 EXPORT_SYMBOL(do_ide_request);
 /*
  * Driver module
@@ -3668,7 +3766,6 @@
 EXPORT_SYMBOL(ide_scan_devices);
 EXPORT_SYMBOL(ide_register_subdriver);
 EXPORT_SYMBOL(ide_unregister_subdriver);
-EXPORT_SYMBOL(ide_replace_subdriver);
 EXPORT_SYMBOL(ide_set_handler);
 EXPORT_SYMBOL(ide_dump_status);
 EXPORT_SYMBOL(ide_error);
@@ -3692,9 +3789,6 @@
 EXPORT_SYMBOL(ide_add_proc_entries);
 EXPORT_SYMBOL(ide_remove_proc_entries);
 EXPORT_SYMBOL(proc_ide_read_geometry);
-EXPORT_SYMBOL(create_proc_ide_interfaces);
-EXPORT_SYMBOL(recreate_proc_ide_device);
-EXPORT_SYMBOL(destroy_proc_ide_device);
 #endif
 EXPORT_SYMBOL(ide_add_setting);
 EXPORT_SYMBOL(ide_remove_setting);
@@ -3706,10 +3800,6 @@
 EXPORT_SYMBOL(get_info_ptr);
 EXPORT_SYMBOL(current_capacity);
 
-EXPORT_SYMBOL(system_bus_clock);
-
-EXPORT_SYMBOL(ide_reinit_drive);
-
 static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
 {
 	ide_hwif_t *hwif;
@@ -3739,10 +3829,10 @@
 			/* set the drive to standby */
 			printk("%s ", drive->name);
 			if (event != SYS_RESTART)
-				if (drive->driver != NULL && DRIVER(drive)->standby(drive))
-				continue;
+				if (drive->driver != NULL && ata_ops(drive)->standby(drive))
+					continue;
 
-			if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+			if (drive->driver != NULL && ata_ops(drive)->cleanup(drive))
 				continue;
 		}
 	}
@@ -3757,24 +3847,42 @@
 };
 
 /*
- * This is gets invoked once during initialization, to set *everything* up
+ * This is the global initialization entry point.
  */
-int __init ide_init (void)
+static int __init ata_module_init(void)
 {
-	static char banner_printed;
 	int i;
 
-	if (!banner_printed) {
-		printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
-		ide_devfs_handle = devfs_mk_dir (NULL, "ide", NULL);
-		system_bus_speed = ide_system_bus_speed();
-		banner_printed = 1;
-	}
+	printk(KERN_INFO "Uniform Multi-Platform E-IDE driver ver.:" VERSION "\n");
+
+	ide_devfs_handle = devfs_mk_dir (NULL, "ide", NULL);
+
+	/* Initialize system bus speed.
+	 *
+	 * This can be changed by a particular chipse initialization module.
+	 * Otherwise we assume 33MHz as a safe value for PCI bus based systems.
+	 * 50MHz will be assumed for abolitions like VESA, since higher values
+	 * result in more conservative timing setups.
+	 *
+	 * The kernel parameter idebus=XX overrides the default settings.
+	 */
+
+	system_bus_speed = 50;
+	if (idebus_parameter)
+	    system_bus_speed = idebus_parameter;
+#ifdef CONFIG_PCI
+	else if (pci_present())
+	    system_bus_speed = 33;
+#endif
+
+	printk("ide: system bus speed %dMHz\n", system_bus_speed);
 
 	init_ide_data ();
 
 	initializing = 1;
+
 	ide_init_builtin_drivers();
+
 	initializing = 0;
 
 	for (i = 0; i < MAX_HWIFS; ++i) {
@@ -3787,8 +3895,7 @@
 	return 0;
 }
 
-#ifdef MODULE
-char *options = NULL;
+static char *options = NULL;
 MODULE_PARM(options,"s");
 MODULE_LICENSE("GPL");
 
@@ -3799,40 +3906,44 @@
 	if (line == NULL || !*line)
 		return;
 	while ((line = next) != NULL) {
- 		if ((next = strchr(line,' ')) != NULL)
+		if ((next = strchr(line,' ')) != NULL)
 			*next++ = 0;
 		if (!ide_setup(line))
 			printk ("Unknown option '%s'\n", line);
 	}
 }
 
-int init_module (void)
+static int __init init_ata (void)
 {
 	parse_options(options);
-	return ide_init();
+	return ata_module_init();
 }
 
-void cleanup_module (void)
+static void __exit cleanup_ata (void)
 {
 	int index;
 
 	unregister_reboot_notifier(&ide_notifier);
 	for (index = 0; index < MAX_HWIFS; ++index) {
 		ide_unregister(index);
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+# if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
 		if (ide_hwifs[index].dma_base)
 			(void) ide_release_dma(&ide_hwifs[index]);
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+# endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
 	}
 
-#ifdef CONFIG_PROC_FS
+# ifdef CONFIG_PROC_FS
 	proc_ide_destroy();
-#endif
+# endif
 	devfs_unregister (ide_devfs_handle);
 }
 
-#else /* !MODULE */
+module_init(init_ata);
+module_exit(cleanup_ata);
+
+#ifndef MODULE
 
+/* command line option parser */
 __setup("", ide_setup);
 
-#endif /* MODULE */
+#endif
diff -urN linux-2.5.6-pre1/drivers/ide/ide_modes.h linux-2.5.6-pre2/drivers/ide/ide_modes.h
--- linux-2.5.6-pre1/drivers/ide/ide_modes.h	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/drivers/ide/ide_modes.h	Thu Feb 28 13:34:21 2002
@@ -11,9 +11,6 @@
 
 /*
  * Shared data/functions for determining best PIO mode for an IDE drive.
- * Most of this stuff originally lived in cmd640.c, and changes to the
- * ide_pio_blacklist[] table should be made with EXTREME CAUTION to avoid
- * breaking the fragile cmd640.c support.
  */
 
 #ifdef CONFIG_BLK_DEV_IDE_MODES
@@ -37,200 +34,9 @@
 	byte blacklisted;
 	unsigned int cycle_time;
 } ide_pio_data_t;
-	
-#ifndef _IDE_C
 
-int ide_scan_pio_blacklist (char *model);
-byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d);
+extern int ide_scan_pio_blacklist (char *model);
+extern byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d);
 extern const ide_pio_timings_t ide_pio_timings[6];
-
-#else /* _IDE_C */
-
-const ide_pio_timings_t ide_pio_timings[6] = {
-	{ 70,	165,	600 },	/* PIO Mode 0 */
-	{ 50,	125,	383 },	/* PIO Mode 1 */
-	{ 30,	100,	240 },	/* PIO Mode 2 */
-	{ 30,	80,	180 },	/* PIO Mode 3 with IORDY */
-	{ 25,	70,	120 },	/* PIO Mode 4 with IORDY */
-	{ 20,	50,	100 }	/* PIO Mode 5 with IORDY (nonstandard) */
-};
-
-/*
- * Black list. Some drives incorrectly report their maximal PIO mode,
- * at least in respect to CMD640. Here we keep info on some known drives.
- */
-static struct ide_pio_info {
-	const char	*name;
-	int		pio;
-} ide_pio_blacklist [] = {
-/*	{ "Conner Peripherals 1275MB - CFS1275A", 4 }, */
-	{ "Conner Peripherals 540MB - CFS540A", 3 },
-
-	{ "WDC AC2700",  3 },
-	{ "WDC AC2540",  3 },
-	{ "WDC AC2420",  3 },
-	{ "WDC AC2340",  3 },
-	{ "WDC AC2250",  0 },
-	{ "WDC AC2200",  0 },
-	{ "WDC AC21200", 4 },
-	{ "WDC AC2120",  0 },
-	{ "WDC AC2850",  3 },
-	{ "WDC AC1270",  3 },
-	{ "WDC AC1170",  1 },
-	{ "WDC AC1210",  1 },
-	{ "WDC AC280",   0 },
-/*	{ "WDC AC21000", 4 }, */
-	{ "WDC AC31000", 3 },
-	{ "WDC AC31200", 3 },
-/*	{ "WDC AC31600", 4 }, */
-
-	{ "Maxtor 7131 AT", 1 },
-	{ "Maxtor 7171 AT", 1 },
-	{ "Maxtor 7213 AT", 1 },
-	{ "Maxtor 7245 AT", 1 },
-	{ "Maxtor 7345 AT", 1 },
-	{ "Maxtor 7546 AT", 3 },
-	{ "Maxtor 7540 AV", 3 },
-
-	{ "SAMSUNG SHD-3121A", 1 },
-	{ "SAMSUNG SHD-3122A", 1 },
-	{ "SAMSUNG SHD-3172A", 1 },
-
-/*	{ "ST51080A", 4 },
- *	{ "ST51270A", 4 },
- *	{ "ST31220A", 4 },
- *	{ "ST31640A", 4 },
- *	{ "ST32140A", 4 },
- *	{ "ST3780A",  4 },
- */
-	{ "ST5660A",  3 },
-	{ "ST3660A",  3 },
-	{ "ST3630A",  3 },
-	{ "ST3655A",  3 },
-	{ "ST3391A",  3 },
-	{ "ST3390A",  1 },
-	{ "ST3600A",  1 },
-	{ "ST3290A",  0 },
-	{ "ST3144A",  0 },
-	{ "ST3491A",  1 },	/* reports 3, should be 1 or 2 (depending on */	
-				/* drive) according to Seagates FIND-ATA program */
-
-	{ "QUANTUM ELS127A", 0 },
-	{ "QUANTUM ELS170A", 0 },
-	{ "QUANTUM LPS240A", 0 },
-	{ "QUANTUM LPS210A", 3 },
-	{ "QUANTUM LPS270A", 3 },
-	{ "QUANTUM LPS365A", 3 },
-	{ "QUANTUM LPS540A", 3 },
-	{ "QUANTUM LIGHTNING 540A", 3 },
-	{ "QUANTUM LIGHTNING 730A", 3 },
-
-        { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
-        { "QUANTUM FIREBALL_640", 3 }, 
-        { "QUANTUM FIREBALL_1080", 3 },
-        { "QUANTUM FIREBALL_1280", 3 },
-	{ NULL,	0 }
-};
-
-/*
- * This routine searches the ide_pio_blacklist for an entry
- * matching the start/whole of the supplied model name.
- *
- * Returns -1 if no match found.
- * Otherwise returns the recommended PIO mode from ide_pio_blacklist[].
- */
-int ide_scan_pio_blacklist (char *model)
-{
-	struct ide_pio_info *p;
-
-	for (p = ide_pio_blacklist; p->name != NULL; p++) {
-		if (strncmp(p->name, model, strlen(p->name)) == 0)
-			return p->pio;
-	}
-	return -1;
-}
-
-/*
- * This routine returns the recommended PIO settings for a given drive,
- * based on the drive->id information and the ide_pio_blacklist[].
- * This is used by most chipset support modules when "auto-tuning".
- */
-
-/*
- * Drive PIO mode auto selection
- */
-byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d)
-{
-	int pio_mode;
-	int cycle_time = 0;
-	int use_iordy = 0;
-	struct hd_driveid* id = drive->id;
-	int overridden  = 0;
-	int blacklisted = 0;
-
-	if (mode_wanted != 255) {
-		pio_mode = mode_wanted;
-	} else if (!drive->id) {
-		pio_mode = 0;
-	} else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
-		overridden = 1;
-		blacklisted = 1;
-		use_iordy = (pio_mode > 2);
-	} else {
-		pio_mode = id->tPIO;
-		if (pio_mode > 2) {	/* 2 is maximum allowed tPIO value */
-			pio_mode = 2;
-			overridden = 1;
-		}
-		if (id->field_valid & 2) {	  /* drive implements ATA2? */
-			if (id->capability & 8) { /* drive supports use_iordy? */
-				use_iordy = 1;
-				cycle_time = id->eide_pio_iordy;
-				if (id->eide_pio_modes & 7) {
-					overridden = 0;
-					if (id->eide_pio_modes & 4)
-						pio_mode = 5;
-					else if (id->eide_pio_modes & 2)
-						pio_mode = 4;
-					else
-						pio_mode = 3;
-				}
-			} else {
-				cycle_time = id->eide_pio;
-			}
-		}
-
-#if 0
-		if (drive->id->major_rev_num & 0x0004) printk("ATA-2 ");
 #endif
-
-		/*
-		 * Conservative "downgrade" for all pre-ATA2 drives
-		 */
-		if (pio_mode && pio_mode < 4) {
-			pio_mode--;
-			overridden = 1;
-#if 0
-			use_iordy = (pio_mode > 2);
 #endif
-			if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
-				cycle_time = 0; /* use standard timing */
-		}
-	}
-	if (pio_mode > max_mode) {
-		pio_mode = max_mode;
-		cycle_time = 0;
-	}
-	if (d) {
-		d->pio_mode = pio_mode;
-		d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
-		d->use_iordy = use_iordy;
-		d->overridden = overridden;
-		d->blacklisted = blacklisted;
-	}
-	return pio_mode;
-}
-
-#endif /* _IDE_C */
-#endif /* CONFIG_BLK_DEV_IDE_MODES */
-#endif /* _IDE_MODES_H */
diff -urN linux-2.5.6-pre1/drivers/ide/it8172.c linux-2.5.6-pre2/drivers/ide/it8172.c
--- linux-2.5.6-pre1/drivers/ide/it8172.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/drivers/ide/it8172.c	Thu Feb 28 13:34:21 2002
@@ -53,7 +53,6 @@
 static int it8172_config_drive_for_dma (ide_drive_t *drive);
 static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
 #endif
-unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name);
 void __init ide_init_it8172 (ide_hwif_t *hwif);
 
 
@@ -232,7 +231,7 @@
 #endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_IT8172_TUNING) */
 
 
-unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_it8172 (struct pci_dev *dev)
 {
     unsigned char progif;
     
diff -urN linux-2.5.6-pre1/drivers/ide/ns87415.c linux-2.5.6-pre2/drivers/ide/ns87415.c
--- linux-2.5.6-pre1/drivers/ide/ns87415.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/ide/ns87415.c	Thu Feb 28 13:34:21 2002
@@ -103,7 +103,7 @@
 			ns87415_prepare_drive(drive, 0);	/* DMA failed: select PIO xfer */
 			return 1;
 		case ide_dma_check:
-			if (drive->media != ide_disk)
+			if (drive->type != ATA_DISK)
 				return ide_dmaproc(ide_dma_off_quietly, drive);
 			/* Fallthrough... */
 		default:
diff -urN linux-2.5.6-pre1/drivers/ide/opti621.c linux-2.5.6-pre2/drivers/ide/opti621.c
--- linux-2.5.6-pre1/drivers/ide/opti621.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/drivers/ide/opti621.c	Thu Feb 28 13:34:21 2002
@@ -164,7 +164,7 @@
 	}
 }
 
-int cmpt_clk(int time, int bus_speed)
+static int cmpt_clk(int time, int bus_speed)
 /* Returns (rounded up) time in clocks for time in ns,
  * with bus_speed in MHz.
  * Example: bus_speed = 40 MHz, time = 80 ns
@@ -216,14 +216,13 @@
 {
         if (pio != PIO_NOT_EXIST) {
         	int adr_setup, data_pls;
-		int bus_speed = system_bus_clock();
 
  	       	adr_setup = ide_pio_timings[pio].setup_time;
   	      	data_pls = ide_pio_timings[pio].active_time;
-	  	clks->address_time = cmpt_clk(adr_setup, bus_speed);
-	     	clks->data_time = cmpt_clk(data_pls, bus_speed);
+	  	clks->address_time = cmpt_clk(adr_setup, system_bus_speed);
+	     	clks->data_time = cmpt_clk(data_pls, system_bus_speed);
      		clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time
-     			- adr_setup-data_pls, bus_speed);
+     			- adr_setup-data_pls, system_bus_speed);
      		if (clks->address_time<1) clks->address_time = 1;
      		if (clks->address_time>4) clks->address_time = 4;
      		if (clks->data_time<1) clks->data_time = 1;
diff -urN linux-2.5.6-pre1/drivers/ide/pdc202xx.c linux-2.5.6-pre2/drivers/ide/pdc202xx.c
--- linux-2.5.6-pre1/drivers/ide/pdc202xx.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre2/drivers/ide/pdc202xx.c	Thu Feb 28 13:34:21 2002
@@ -63,7 +63,6 @@
 
 static int pdc202xx_get_info(char *, char **, off_t, int);
 extern int (*pdc202xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
 static struct pci_dev *bmide_dev;
 
 char *pdc202xx_pio_verbose (u32 drive_pci)
@@ -412,7 +411,8 @@
 		default: return -1;
 	}
 
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))	return -1;
+	if ((drive->type != ATA_DISK) && (speed < XFER_SW_DMA_0))
+		return -1;
 
 	pci_read_config_dword(dev, drive_pci, &drive_conf);
 	pci_read_config_byte(dev, (drive_pci), &AP);
@@ -820,7 +820,8 @@
 	}
 
 	if (jumpbit) {
-		if (drive->media != ide_disk)	return ide_dma_off_quietly;
+		if (drive->type != ATA_DISK)
+			return ide_dma_off_quietly;
 		if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
 			OUT_BYTE((iordy + adj), indexreg);
 			OUT_BYTE((IN_BYTE(datareg)|0x03), datareg);
@@ -869,13 +870,14 @@
 
 chipset_is_set:
 
-	if (drive->media != ide_disk)	return ide_dma_off_quietly;
+	if (drive->type != ATA_DISK)
+		return ide_dma_off_quietly;
 
 	pci_read_config_byte(dev, (drive_pci), &AP);
 	if (id->capability & 4)	/* IORDY_EN */
 		pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
 	pci_read_config_byte(dev, (drive_pci), &AP);
-	if (drive->media == ide_disk)	/* PREFETCH_EN */
+	if (drive->type == ATA_DISK)	/* PREFETCH_EN */
 		pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
 
 jumpbit_is_set:
@@ -1102,7 +1104,7 @@
 	return 0;
 }
 
-unsigned int __init pci_init_pdc202xx (struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_pdc202xx(struct pci_dev *dev)
 {
 	unsigned long high_16	= pci_resource_start(dev, 4);
 	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
@@ -1112,7 +1114,7 @@
 
 	if (dev->resource[PCI_ROM_RESOURCE].start) {
 		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk("%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+		printk("%s: ROM enabled at 0x%08lx\n", dev->name, dev->resource[PCI_ROM_RESOURCE].start);
 	}
 
 	switch (dev->device) {
@@ -1151,7 +1153,7 @@
 				pci_read_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, &irq2);	/* 0xbc */
 				if (irq != irq2) {
 					pci_write_config_byte(dev, (PCI_INTERRUPT_LINE)|0x80, irq);	/* 0xbc */
-					printk("%s: pci-config space interrupt mirror fixed.\n", name);
+					printk("%s: pci-config space interrupt mirror fixed.\n", dev->name);
 				}
 			}
 			break;
@@ -1163,14 +1165,14 @@
 	printk("%s: (U)DMA Burst Bit %sABLED " \
 		"Primary %s Mode " \
 		"Secondary %s Mode.\n",
-		name,
+		dev->name,
 		(udma_speed_flag & 1) ? "EN" : "DIS",
 		(primary_mode & 1) ? "MASTER" : "PCI",
 		(secondary_mode & 1) ? "MASTER" : "PCI" );
 
 #ifdef CONFIG_PDC202XX_BURST
 	if (!(udma_speed_flag & 1)) {
-		printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", name, udma_speed_flag, (udma_speed_flag|1));
+		printk("%s: FORCING BURST BIT 0x%02x -> 0x%02x ", dev->name, udma_speed_flag, (udma_speed_flag|1));
 		OUT_BYTE(udma_speed_flag|1, high_16 + 0x001f);
 		printk("%sCTIVE\n", (IN_BYTE(high_16 + 0x001f) & 1) ? "A" : "INA");
 	}
@@ -1179,14 +1181,14 @@
 #ifdef CONFIG_PDC202XX_MASTER
 	if (!(primary_mode & 1)) {
 		printk("%s: FORCING PRIMARY MODE BIT 0x%02x -> 0x%02x ",
-			name, primary_mode, (primary_mode|1));
+			dev->name, primary_mode, (primary_mode|1));
 		OUT_BYTE(primary_mode|1, high_16 + 0x001a);
 		printk("%s\n", (IN_BYTE(high_16 + 0x001a) & 1) ? "MASTER" : "PCI");
 	}
 
 	if (!(secondary_mode & 1)) {
 		printk("%s: FORCING SECONDARY MODE BIT 0x%02x -> 0x%02x ",
-			name, secondary_mode, (secondary_mode|1));
+			dev->name, secondary_mode, (secondary_mode|1));
 		OUT_BYTE(secondary_mode|1, high_16 + 0x001b);
 		printk("%s\n", (IN_BYTE(high_16 + 0x001b) & 1) ? "MASTER" : "PCI");
 	}
diff -urN linux-2.5.6-pre1/drivers/ide/pdc4030.c linux-2.5.6-pre2/drivers/ide/pdc4030.c
--- linux-2.5.6-pre1/drivers/ide/pdc4030.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/drivers/ide/pdc4030.c	Thu Feb 28 13:34:21 2002
@@ -332,14 +332,14 @@
 	if (nsect > sectors_avail)
 		nsect = sectors_avail;
 	sectors_avail -= nsect;
-	to = ide_map_buffer(rq, &flags);
+	to = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
 	ata_input_data(drive, to, nsect * SECTOR_WORDS);
 #ifdef DEBUG_READ
 	printk(KERN_DEBUG "%s:  promise_read: sectors(%ld-%ld), "
 	       "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector,
 	       rq->sector+nsect-1, (unsigned long) to, rq->nr_sectors-nsect);
 #endif
-	ide_unmap_buffer(to, &flags);
+	bio_kunmap_irq(to, &flags);
 	rq->sector += nsect;
 	rq->errors = 0;
 	rq->nr_sectors -= nsect;
@@ -437,7 +437,7 @@
 			nsect = mcount;
 		mcount -= nsect;
 
-		buffer = ide_map_buffer(rq, &flags);
+		buffer = bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
 		rq->sector += nsect;
 		rq->nr_sectors -= nsect;
 		rq->current_nr_sectors -= nsect;
@@ -461,7 +461,7 @@
 		 * re-entering us on the last transfer.
 		 */
 		taskfile_output_data(drive, buffer, nsect<<7);
-		ide_unmap_buffer(buffer, &flags);
+		bio_kunmap_irq(buffer, &flags);
 	} while (mcount);
 
 	return 0;
diff -urN linux-2.5.6-pre1/drivers/ide/pdcadma.c linux-2.5.6-pre2/drivers/ide/pdcadma.c
--- linux-2.5.6-pre1/drivers/ide/pdcadma.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/drivers/ide/pdcadma.c	Thu Feb 28 13:34:21 2002
@@ -34,7 +34,6 @@
 
 static int pdcadma_get_info(char *, char **, off_t, int);
 extern int (*pdcadma_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
 static struct pci_dev *bmide_dev;
 
 static int pdcadma_get_info (char *buffer, char **addr, off_t offset, int count)
@@ -71,7 +70,7 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-unsigned int __init pci_init_pdcadma (struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_pdcadma(struct pci_dev *dev)
 {
 #if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!pdcadma_proc) {
diff -urN linux-2.5.6-pre1/drivers/ide/piix.c linux-2.5.6-pre2/drivers/ide/piix.c
--- linux-2.5.6-pre1/drivers/ide/piix.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/ide/piix.c	Thu Feb 28 13:34:21 2002
@@ -77,7 +77,6 @@
 
 static int piix_get_info(char *, char **, off_t, int);
 extern int (*piix_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
 static struct pci_dev *bmide_dev;
 
 static int piix_get_info (char *buffer, char **addr, off_t offset, int count)
@@ -235,8 +234,8 @@
 			master_data = master_data | 0x0070;
 		pci_read_config_byte(HWIF(drive)->pci_dev, slave_port, &slave_data);
 		slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0);
-		slave_data = slave_data | ((timings[pio][0] << 2) | (timings[pio][1]
-					   << (HWIF(drive)->index ? 4 : 0)));
+		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1])
+					   << (HWIF(drive)->index ? 4 : 0));
 	} else {
 		master_data = master_data & 0xccf8;
 		if (pio > 1)
@@ -451,7 +450,7 @@
 }
 #endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */
 
-unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_piix(struct pci_dev *dev)
 {
 #if defined(DISPLAY_PIIX_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!piix_proc) {
diff -urN linux-2.5.6-pre1/drivers/ide/qd65xx.c linux-2.5.6-pre2/drivers/ide/qd65xx.c
--- linux-2.5.6-pre1/drivers/ide/qd65xx.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/drivers/ide/qd65xx.c	Thu Feb 28 13:34:21 2002
@@ -139,12 +139,12 @@
 {
 	byte active_cycle,recovery_cycle;
 
-	if (ide_system_bus_speed()<=33) {
-		active_cycle =   9  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 9);
-		recovery_cycle = 15 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 0, 15);
+	if (system_bus_speed <= 33) {
+		active_cycle =   9  - IDE_IN(active_time   * system_bus_speed / 1000 + 1, 2, 9);
+		recovery_cycle = 15 - IDE_IN(recovery_time * system_bus_speed / 1000 + 1, 0, 15);
 	} else {
-		active_cycle =   8  - IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 1, 8);
-		recovery_cycle = 18 - IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 3, 18);
+		active_cycle =   8  - IDE_IN(active_time   * system_bus_speed / 1000 + 1, 1, 8);
+		recovery_cycle = 18 - IDE_IN(recovery_time * system_bus_speed / 1000 + 1, 3, 18);
 	}
 
 	return((recovery_cycle<<4) | 0x08 | active_cycle);
@@ -158,8 +158,8 @@
 
 static byte qd6580_compute_timing (int active_time, int recovery_time)
 {
-	byte active_cycle   = 17-IDE_IN(active_time   * ide_system_bus_speed() / 1000 + 1, 2, 17);
-	byte recovery_cycle = 15-IDE_IN(recovery_time * ide_system_bus_speed() / 1000 + 1, 2, 15);
+	byte active_cycle   = 17-IDE_IN(active_time   * system_bus_speed / 1000 + 1, 2, 17);
+	byte recovery_cycle = 15-IDE_IN(recovery_time * system_bus_speed / 1000 + 1, 2, 15);
 
 	return((recovery_cycle<<4) | active_cycle);
 }
@@ -293,7 +293,7 @@
 		printk(KERN_INFO "%s: PIO mode%d\n",drive->name,pio);
 	}
 
-	if (!HWIF(drive)->channel && drive->media != ide_disk) {
+	if (!HWIF(drive)->channel && drive->type != ATA_DISK) {
 		qd_write_reg(0x5f,QD_CONTROL_PORT);
 		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n",drive->name,HWIF(drive)->name);
 	}
diff -urN linux-2.5.6-pre1/drivers/ide/serverworks.c linux-2.5.6-pre2/drivers/ide/serverworks.c
--- linux-2.5.6-pre1/drivers/ide/serverworks.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/drivers/ide/serverworks.c	Thu Feb 28 13:34:21 2002
@@ -105,7 +105,6 @@
 
 static int svwks_get_info(char *, char **, off_t, int);
 extern int (*svwks_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
 
 static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
 {
@@ -547,7 +546,7 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-unsigned int __init pci_init_svwks (struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_svwks(struct pci_dev *dev)
 {
 	unsigned int reg;
 	byte btr;
diff -urN linux-2.5.6-pre1/drivers/ide/sis5513.c linux-2.5.6-pre2/drivers/ide/sis5513.c
--- linux-2.5.6-pre1/drivers/ide/sis5513.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/ide/sis5513.c	Thu Feb 28 13:34:21 2002
@@ -238,7 +238,7 @@
 	byte rw_prefetch	= (0x11 << drive->dn);
 
 	pci_read_config_byte(dev, 0x4b, &reg4bh);
-	if (drive->media != ide_disk)
+	if (drive->type != ATA_DISK)
 		return;
 	
 	if ((reg4bh & rw_prefetch) != rw_prefetch)
@@ -567,7 +567,7 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-unsigned int __init pci_init_sis5513 (struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_sis5513(struct pci_dev *dev)
 {
 	struct pci_dev *host;
 	int i = 0;
diff -urN linux-2.5.6-pre1/drivers/ide/sl82c105.c linux-2.5.6-pre2/drivers/ide/sl82c105.c
--- linux-2.5.6-pre1/drivers/ide/sl82c105.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/drivers/ide/sl82c105.c	Thu Feb 28 13:34:21 2002
@@ -223,7 +223,7 @@
 /*
  * Enable the PCI device
  */
-unsigned int __init pci_init_sl82c105(struct pci_dev *dev, const char *msg)
+unsigned int __init pci_init_sl82c105(struct pci_dev *dev)
 {
 	unsigned char ctrl_stat;
 
diff -urN linux-2.5.6-pre1/drivers/ide/slc90e66.c linux-2.5.6-pre2/drivers/ide/slc90e66.c
--- linux-2.5.6-pre1/drivers/ide/slc90e66.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/drivers/ide/slc90e66.c	Thu Feb 28 13:34:21 2002
@@ -60,7 +60,6 @@
 
 static int slc90e66_get_info(char *, char **, off_t, int);
 extern int (*slc90e66_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
 static struct pci_dev *bmide_dev;
 
 static int slc90e66_get_info (char *buffer, char **addr, off_t offset, int count)
@@ -347,7 +346,7 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-unsigned int __init pci_init_slc90e66 (struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_slc90e66(struct pci_dev *dev)
 {
 #if defined(DISPLAY_SLC90E66_TIMINGS) && defined(CONFIG_PROC_FS)
 	if (!slc90e66_proc) {
diff -urN linux-2.5.6-pre1/drivers/ide/trm290.c linux-2.5.6-pre2/drivers/ide/trm290.c
--- linux-2.5.6-pre1/drivers/ide/trm290.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/drivers/ide/trm290.c	Thu Feb 28 13:34:21 2002
@@ -192,7 +192,7 @@
 			outl(hwif->dmatable_dma|reading|writing, hwif->dma_base);
 			drive->waiting_for_dma = 1;
 			outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
-			if (drive->media != ide_disk)
+			if (drive->type != ATA_DISK)
 				return 0;
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
 			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
diff -urN linux-2.5.6-pre1/drivers/ide/via82cxxx.c linux-2.5.6-pre2/drivers/ide/via82cxxx.c
--- linux-2.5.6-pre1/drivers/ide/via82cxxx.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/drivers/ide/via82cxxx.c	Thu Feb 28 13:34:21 2002
@@ -393,7 +393,7 @@
  * and initialize its drive independent registers.
  */
 
-unsigned int __init pci_init_via82cxxx(struct pci_dev *dev, const char *name)
+unsigned int __init pci_init_via82cxxx(struct pci_dev *dev)
 {
 	struct pci_dev *isa = NULL;
 	unsigned char t, v;
@@ -484,7 +484,7 @@
  * Determine system bus clock.
  */
 
-	via_clock = system_bus_clock() * 1000;
+	via_clock = system_bus_speed * 1000;
 
 	switch (via_clock) {
 		case 33000: via_clock = 33333; break;
diff -urN linux-2.5.6-pre1/drivers/input/gameport/cs461x.c linux-2.5.6-pre2/drivers/input/gameport/cs461x.c
--- linux-2.5.6-pre1/drivers/input/gameport/cs461x.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/drivers/input/gameport/cs461x.c	Thu Feb 28 13:34:21 2002
@@ -25,8 +25,6 @@
 #define CS461X_FULL_MAP
 */
 
-#define COOKED_MODE
-
 
 #ifndef PCI_VENDOR_ID_CIRRUS
 #define PCI_VENDOR_ID_CIRRUS            0x1013
@@ -122,6 +120,9 @@
 static unsigned long ba0_addr;
 static unsigned int *ba0;
 
+static char phys[32];
+static char name[] = "CS416x Gameport";
+
 #ifdef CS461X_FULL_MAP
 static unsigned long ba1_addr;
 static union ba1_t {
@@ -206,14 +207,11 @@
 static int cs461x_gameport_open(struct gameport *gameport, int mode)
 {
 	switch (mode) {
-#ifdef COOKED_MODE
-	case GAMEPORT_MODE_COOKED:
-		return 0;
-#endif
-	case GAMEPORT_MODE_RAW:
-		return 0;
-	default:
-		return -1;
+		case GAMEPORT_MODE_COOKED:
+		case GAMEPORT_MODE_RAW:
+			return 0;
+		default:
+			return -1;
 	}
 	return 0;
 }
@@ -274,9 +272,7 @@
 		return -ENOMEM;
 	}
 #endif
-	printk(KERN_INFO "CS461x PCI: %lx[%d]\n",
-	    ba0_addr, CS461X_BA0_SIZE);
-        
+
 	if (!(port = kmalloc(sizeof(struct gameport), GFP_KERNEL))) {
 		printk(KERN_ERR "Memory allocation failed.\n");
 		cs461x_free(pdev);
@@ -287,19 +283,25 @@
 	pci_set_drvdata(pdev, port);
 	
 	port->open = cs461x_gameport_open;
-	port->read = cs461x_gameport_read;
 	port->trigger = cs461x_gameport_trigger;
-#ifdef COOKED_MODE
+	port->read = cs461x_gameport_read;
 	port->cooked_read = cs461x_gameport_cooked_read;
-#endif
+
+	sprintf(phys, "pci%s/gameport0", pdev->slot_name);
+
+	port->name = name;
+	port->phys = phys;
+	port->idbus = BUS_PCI;
+	port->idvendor = pdev->vendor;
+	port->idproduct = pdev->device;
 
 	cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
 	cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
 
 	gameport_register_port(port);
 
-	printk(KERN_INFO "gameport%d: CS461x Gameport speed %d kHz\n",
-		port->number, port->speed);
+	printk(KERN_INFO "gameport: %s on pci%s speed %d kHz\n",
+		name, pdev->slot_name, port->speed);
 
 	return 0;
 }
@@ -310,22 +312,22 @@
 }
 	
 static struct pci_driver cs461x_pci_driver = {
-        name:           "PCI Gameport",
+        name:           "CS461x Gameport",
         id_table:       cs461x_pci_tbl,
         probe:          cs461x_pci_probe,
         remove:         __devexit_p(cs461x_pci_remove),
 };
 
-int __init js_cs461x_init(void)
+int __init cs461x_init(void)
 {
         return pci_module_init(&cs461x_pci_driver);
 }
 
-void __exit js_cs461x_exit(void)
+void __exit cs461x_exit(void)
 {
         pci_unregister_driver(&cs461x_pci_driver);
 }
 
-module_init(js_cs461x_init);
-module_exit(js_cs461x_exit);
+module_init(cs461x_init);
+module_exit(cs461x_exit);
 
diff -urN linux-2.5.6-pre1/drivers/input/gameport/emu10k1-gp.c linux-2.5.6-pre2/drivers/input/gameport/emu10k1-gp.c
--- linux-2.5.6-pre1/drivers/input/gameport/emu10k1-gp.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/drivers/input/gameport/emu10k1-gp.c	Thu Feb 28 13:34:21 2002
@@ -1,13 +1,11 @@
 /*
- * $Id: emu10k1-gp.c,v 1.2 2001/04/24 07:48:56 vojtech Exp $
+ * $Id: emu10k1-gp.c,v 1.8 2002/01/22 20:40:46 vojtech Exp $
  *
  *  Copyright (c) 2001 Vojtech Pavlik
- *
- *  Sponsored by SuSE
  */
 
 /*
- * EMU10k1 - SB Live! - gameport driver for Linux
+ * EMU10k1 - SB Live / Audigy - gameport driver for Linux
  */
 
 /*
@@ -27,7 +25,7 @@
  * 
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <asm/io.h>
@@ -41,6 +39,7 @@
 #include <linux/pci.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("EMU10k1 gameport driver");
 MODULE_LICENSE("GPL");
 
 struct emu {
@@ -48,10 +47,12 @@
 	struct emu *next;
 	struct gameport gameport;
 	int size;
+	char phys[32];
 };
 	
 static struct pci_device_id emu_tbl[] __devinitdata = {
-	{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live! gameport */
+	{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */
+	{ 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */
 	{ 0, }
 };
 
@@ -60,15 +61,10 @@
 static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	int ioport, iolen;
-	int rc;
-	struct emu *port;
+	struct emu *emu;
         
-	rc = pci_enable_device(pdev);
-	if (rc) {
-		printk(KERN_ERR "emu10k1-gp: Cannot enable emu10k1 gameport (bus %d, devfn %d) error=%d\n",
-			pdev->bus->number, pdev->devfn, rc);
-		return rc;
-	}
+	if (pci_enable_device(pdev))
+		return -EBUSY;
 
 	ioport = pci_resource_start(pdev, 0);
 	iolen = pci_resource_len(pdev, 0);
@@ -76,32 +72,41 @@
 	if (!request_region(ioport, iolen, "emu10k1-gp"))
 		return -EBUSY;
 
-	if (!(port = kmalloc(sizeof(struct emu), GFP_KERNEL))) {
+	if (!(emu = kmalloc(sizeof(struct emu), GFP_KERNEL))) {
 		printk(KERN_ERR "emu10k1-gp: Memory allocation failed.\n");
 		release_region(ioport, iolen);
 		return -ENOMEM;
 	}
-	memset(port, 0, sizeof(struct emu));
+	memset(emu, 0, sizeof(struct emu));
+
+	sprintf(emu->phys, "pci%s/gameport0", pdev->slot_name);
+
+	emu->size = iolen;
+	emu->dev = pdev;
+
+	emu->gameport.io = ioport;
+	emu->gameport.name = pdev->name;
+	emu->gameport.phys = emu->phys;
+	emu->gameport.idbus = BUS_PCI;
+	emu->gameport.idvendor = pdev->vendor;
+	emu->gameport.idproduct = pdev->device;
 
-	port->gameport.io = ioport;
-	port->size = iolen;
-	port->dev = pdev;
-	pci_set_drvdata(pdev, port);
+	pci_set_drvdata(pdev, emu);
 
-	gameport_register_port(&port->gameport);
+	gameport_register_port(&emu->gameport);
 
-	printk(KERN_INFO "gameport%d: Emu10k1 Gameport at %#x size %d speed %d kHz\n",
-		port->gameport.number, port->gameport.io, iolen, port->gameport.speed);
+	printk(KERN_INFO "gameport: %s at pci%s speed %d kHz\n",
+		pdev->name, pdev->slot_name, emu->gameport.speed);
 
 	return 0;
 }
 
 static void __devexit emu_remove(struct pci_dev *pdev)
 {
-	struct emu *port = pci_get_drvdata(pdev);
-	gameport_unregister_port(&port->gameport);
-	release_region(port->gameport.io, port->size);
-	kfree(port);
+	struct emu *emu = pci_get_drvdata(pdev);
+	gameport_unregister_port(&emu->gameport);
+	release_region(emu->gameport.io, emu->size);
+	kfree(emu);
 }
 
 static struct pci_driver emu_driver = {
diff -urN linux-2.5.6-pre1/drivers/input/gameport/gameport.c linux-2.5.6-pre2/drivers/input/gameport/gameport.c
--- linux-2.5.6-pre1/drivers/input/gameport/gameport.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/drivers/input/gameport/gameport.c	Thu Feb 28 13:34:21 2002
@@ -1,9 +1,7 @@
 /*
- * $Id: gameport.c,v 1.5 2000/05/29 10:54:53 vojtech Exp $
+ * $Id: gameport.c,v 1.18 2002/01/22 20:41:14 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  */
 
 /*
@@ -26,8 +24,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <asm/io.h>
@@ -40,7 +38,8 @@
 #include <linux/stddef.h>
 #include <linux/delay.h>
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Generic gameport layer");
 MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(gameport_register_port);
@@ -54,7 +53,6 @@
 
 static struct gameport *gameport_list;
 static struct gameport_dev *gameport_dev;
-static int gameport_number;
 
 /*
  * gameport_measure_speed() measures the gameport i/o speed.
@@ -122,7 +120,6 @@
 
 void gameport_register_port(struct gameport *gameport)
 {
-	gameport->number = gameport_number++;
 	gameport->next = gameport_list;	
 	gameport_list = gameport;
 
@@ -140,8 +137,6 @@
 
 	if (gameport->dev && gameport->dev->disconnect)
 		gameport->dev->disconnect(gameport);
-
-	gameport_number--;
 }
 
 void gameport_register_device(struct gameport_dev *dev)
diff -urN linux-2.5.6-pre1/drivers/input/gameport/lightning.c linux-2.5.6-pre2/drivers/input/gameport/lightning.c
--- linux-2.5.6-pre1/drivers/input/gameport/lightning.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/input/gameport/lightning.c	Thu Feb 28 13:34:21 2002
@@ -1,9 +1,7 @@
 /*
- * $Id: lightning.c,v 1.13 2001/04/26 10:24:46 vojtech Exp $
+ * $Id: lightning.c,v 1.20 2002/01/22 20:41:31 vojtech Exp $
  *
  *  Copyright (c) 1998-2001 Vojtech Pavlik
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -26,8 +24,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <asm/io.h>
@@ -51,14 +49,18 @@
 #define L4_BUSY			0x01
 #define L4_TIMEOUT		80	/* 80 us */
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("PDPI Lightning 4 gamecard driver");
 MODULE_LICENSE("GPL");
 
 struct l4 {
 	struct gameport gameport;
 	unsigned char port;
+	char phys[32];
 } *l4_port[8];
 
+char l4_name[] = "PDPI Lightning 4";
+
 /*
  * l4_wait_ready() waits for the L4 to become ready.
  */
@@ -77,7 +79,7 @@
 
 static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	struct l4 *l4 = gameport->private;
+	struct l4 *l4 = gameport->driver;
 	unsigned char status;
 	int i, result = -1;
 
@@ -110,7 +112,7 @@
 
 static int l4_open(struct gameport *gameport, int mode)
 {
-	struct l4 *l4 = gameport->private;
+	struct l4 *l4 = gameport->driver;
         if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED)
 		return -1;
 	outb(L4_SELECT_ANALOG, L4_PORT);
@@ -188,7 +190,7 @@
 {
 	int i, t;
 	int cal[4];
-	struct l4 *l4 = gameport->private;
+	struct l4 *l4 = gameport->driver;
 
 	if (l4_getcal(l4->port, cal))
 		return -1;
@@ -247,12 +249,18 @@
 			l4 = l4_port[i * 4 + j] = l4_port[i * 4] + j;
 			l4->port = i * 4 + j;
 
+			sprintf(l4->phys, "isa%04x/gameport%d", L4_PORT, 4 * i + j);
+
 			gameport = &l4->gameport;
-			gameport->private = l4;
+			gameport->driver = l4;
 			gameport->open = l4_open;
 			gameport->cooked_read = l4_cooked_read;
 			gameport->calibrate = l4_calibrate;
 
+			gameport->name = l4_name;
+			gameport->phys = l4->phys;
+			gameport->idbus = BUS_ISA;
+
 			if (!i && !j)
 				gameport->io = L4_PORT;
 
@@ -262,9 +270,7 @@
 			gameport_register_port(gameport);
 		}
 
-		printk(KERN_INFO "gameport%d,%d,%d,%d: PDPI Lightning 4 %s card v%d.%d at %#x\n",
-			l4_port[i * 4 + 0]->gameport.number, l4_port[i * 4 + 1]->gameport.number, 
-			l4_port[i * 4 + 2]->gameport.number, l4_port[i * 4 + 3]->gameport.number, 
+		printk(KERN_INFO "gameport: PDPI Lightning 4 %s card v%d.%d at %#x\n",
 			i ? "secondary" : "primary", rev >> 4, rev, L4_PORT);
 
 		cards++;
diff -urN linux-2.5.6-pre1/drivers/input/gameport/ns558.c linux-2.5.6-pre2/drivers/input/gameport/ns558.c
--- linux-2.5.6-pre1/drivers/input/gameport/ns558.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/drivers/input/gameport/ns558.c	Thu Feb 28 13:34:21 2002
@@ -1,10 +1,8 @@
 /*
- * $Id: ns558.c,v 1.29 2001/04/24 07:48:56 vojtech Exp $
+ * $Id: ns558.c,v 1.43 2002/01/24 19:23:21 vojtech Exp $
  *
  *  Copyright (c) 1999-2001 Vojtech Pavlik
  *  Copyright (c) 1999 Brian Gerst
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -28,7 +26,7 @@
  * 
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <asm/io.h>
@@ -42,6 +40,7 @@
 #include <linux/isapnp.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Classic gameport (ISA/PnP) driver");
 MODULE_LICENSE("GPL");
 
 #define NS558_ISA	1
@@ -56,6 +55,8 @@
 	struct pci_dev *dev;
 	struct ns558 *next;
 	struct gameport gameport;
+	char phys[32];
+	char name[32];
 };
 	
 static struct ns558 *ns558;
@@ -141,12 +142,18 @@
 	port->type = NS558_ISA;
 	port->size = (1 << i);
 	port->gameport.io = io & (-1 << i);
+	port->gameport.phys = port->phys;
+	port->gameport.name = port->name;
+	port->gameport.idbus = BUS_ISA;
+
+	sprintf(port->phys, "isa%04x/gameport0", io & (-1 << i));
+	sprintf(port->name, "NS558 ISA");
 
 	request_region(port->gameport.io, (1 << i), "ns558-isa");
 
 	gameport_register_port(&port->gameport);
 
-	printk(KERN_INFO "gameport%d: NS558 ISA at %#x", port->gameport.number, port->gameport.io);
+	printk(KERN_INFO "gameport: NS558 ISA at %#x", port->gameport.io);
 	if (port->size > 1) printk(" size %d", port->size);
 	printk(" speed %d kHz\n", port->gameport.speed);
 
@@ -155,17 +162,33 @@
 
 #ifdef __ISAPNP__
 
+#define NS558_DEVICE(a,b,c,d)\
+	card_vendor: ISAPNP_ANY_ID, card_device: ISAPNP_ANY_ID,\
+	vendor: ISAPNP_VENDOR(a,b,c), function: ISAPNP_DEVICE(d)
+
 static struct isapnp_device_id pnp_devids[] = {
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x0001), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x2001), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7001), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 },
-	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f), 0 },
+	{ NS558_DEVICE('@','P','@',0x0001) }, /* ALS 100 */
+	{ NS558_DEVICE('@','P','@',0x0020) }, /* ALS 200 */
+	{ NS558_DEVICE('@','P','@',0x1001) }, /* ALS 100+ */
+	{ NS558_DEVICE('@','P','@',0x2001) }, /* ALS 120 */
+	{ NS558_DEVICE('A','S','B',0x16fd) }, /* AdLib NSC16 */
+	{ NS558_DEVICE('A','Z','T',0x3001) }, /* AZT1008 */
+	{ NS558_DEVICE('C','D','C',0x0001) }, /* Opl3-SAx */
+	{ NS558_DEVICE('C','S','C',0x0001) }, /* CS4232 */
+	{ NS558_DEVICE('C','S','C',0x000f) }, /* CS4236 */
+	{ NS558_DEVICE('C','S','C',0x0101) }, /* CS4327 */
+	{ NS558_DEVICE('C','T','L',0x7001) }, /* SB16 */
+	{ NS558_DEVICE('C','T','L',0x7002) }, /* AWE64 */
+	{ NS558_DEVICE('C','T','L',0x7005) }, /* Vibra16 */
+	{ NS558_DEVICE('E','N','S',0x2020) }, /* SoundscapeVIVO */
+	{ NS558_DEVICE('E','S','S',0x0001) }, /* ES1869 */
+	{ NS558_DEVICE('E','S','S',0x0005) }, /* ES1878 */
+	{ NS558_DEVICE('E','S','S',0x6880) }, /* ES688 */
+	{ NS558_DEVICE('I','B','M',0x0012) }, /* CS4232 */
+	{ NS558_DEVICE('O','P','T',0x0001) }, /* OPTi Audio16 */
+	{ NS558_DEVICE('Y','M','H',0x0006) }, /* Opl3-SA */
+	{ NS558_DEVICE('Y','M','H',0x0022) }, /* Opl3-SAx */
+	{ NS558_DEVICE('P','N','P',0xb02f) }, /* Generic */
 	{ 0, },
 };
 
@@ -203,13 +226,24 @@
 
 	port->next = next;
 	port->type = NS558_PNP;
-	port->gameport.io = ioport;
 	port->size = iolen;
 	port->dev = dev;
 
+	port->gameport.io = ioport;
+	port->gameport.phys = port->phys;
+	port->gameport.name = port->name;
+	port->gameport.idbus = BUS_ISAPNP;
+	port->gameport.idvendor = dev->vendor;
+	port->gameport.idproduct = dev->device;
+	port->gameport.idversion = 0x100;
+
+	sprintf(port->phys, "isapnp%d.%d/gameport0", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	sprintf(port->name, "%s", dev->name[0] ? dev->name : "NS558 PnP Gameport");
+
 	gameport_register_port(&port->gameport);
 
-	printk(KERN_INFO "gameport%d: NS558 PnP at %#x", port->gameport.number, port->gameport.io);
+	printk(KERN_INFO "gameport: NS558 PnP at isapnp%d.%d io %#x",
+		PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), port->gameport.io);
 	if (iolen > 1) printk(" size %d", iolen);
 	printk(" speed %d kHz\n", port->gameport.speed);
 
diff -urN linux-2.5.6-pre1/drivers/input/joystick/a3d.c linux-2.5.6-pre2/drivers/input/joystick/a3d.c
--- linux-2.5.6-pre1/drivers/input/joystick/a3d.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/a3d.c	Thu Feb 28 13:34:21 2002
@@ -1,9 +1,7 @@
 /*
- * $Id: a3d.c,v 1.14 2001/04/26 10:24:46 vojtech Exp $
+ * $Id: a3d.c,v 1.21 2002/01/22 20:11:50 vojtech Exp $
  *
  *  Copyright (c) 1998-2001 Vojtech Pavlik
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -26,8 +24,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -37,6 +35,10 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("FP-Gaming Assasin 3D joystick driver");
+MODULE_LICENSE("GPL");
+
 #define A3D_MAX_START		400	/* 400 us */ 
 #define A3D_MAX_STROBE		60	/* 40 us */ 
 #define A3D_DELAY_READ		3	/* 3 ms */
@@ -63,6 +65,8 @@
 	int used;
 	int reads;
 	int bads;
+	char phys[32];
+	char adcphys[32];
 };
 
 /*
@@ -190,7 +194,7 @@
 
 int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	struct a3d *a3d = gameport->private;
+	struct a3d *a3d = gameport->driver;
 	int i;
 	for (i = 0; i < 4; i++)
 		axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1;
@@ -205,7 +209,7 @@
 
 int a3d_adc_open(struct gameport *gameport, int mode)
 {
-	struct a3d *a3d = gameport->private;
+	struct a3d *a3d = gameport->driver;
 	if (mode != GAMEPORT_MODE_COOKED)
 		return -1;
 	if (!a3d->used++)
@@ -219,7 +223,7 @@
 
 static void a3d_adc_close(struct gameport *gameport)
 {
-	struct a3d *a3d = gameport->private;
+	struct a3d *a3d = gameport->driver;
 	if (!--a3d->used)
 		del_timer(&a3d->timer);
 }
@@ -280,10 +284,12 @@
 
 	if (!a3d->mode || a3d->mode > 5) {
 		printk(KERN_WARNING "a3d.c: Unknown A3D device detected "
-			"(gameport%d, id=%d), contact <vojtech@suse.cz>\n", gameport->number, a3d->mode);
+			"(%s, id=%d), contact <vojtech@ucw.cz>\n", gameport->phys, a3d->mode);
 		goto fail2;
 	}
 
+	sprintf(a3d->phys, "%s/input0", gameport->phys);
+	sprintf(a3d->adcphys, "%s/gameport0", gameport->phys);
 
 	if (a3d->mode == A3D_MODE_PXL) {
 
@@ -323,17 +329,23 @@
 		a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
 		a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE);
 
-		a3d->adc.private = a3d;
+		a3d->adc.driver = a3d;
 		a3d->adc.open = a3d_adc_open;
 		a3d->adc.close = a3d_adc_close;
 		a3d->adc.cooked_read = a3d_adc_cooked_read;
 		a3d->adc.fuzz = 1; 
 
+		a3d->adc.name = a3d_names[a3d->mode];
+		a3d->adc.phys = a3d->adcphys;
+		a3d->adc.idbus = BUS_GAMEPORT;
+		a3d->adc.idvendor = GAMEPORT_ID_VENDOR_MADCATZ;
+		a3d->adc.idproduct = a3d->mode;
+		a3d->adc.idversion = 0x0100;
+
 		a3d_read(a3d, data);
 
 		gameport_register_port(&a3d->adc);
-		printk(KERN_INFO "gameport%d: %s on gameport%d.0\n",
-			a3d->adc.number, a3d_names[a3d->mode], gameport->number);
+		printk(KERN_INFO "gameport: %s on %s\n", a3d_names[a3d->mode], gameport->phys);
 	}
 
 	a3d->dev.private = a3d;
@@ -341,14 +353,14 @@
 	a3d->dev.close = a3d_close;
 
 	a3d->dev.name = a3d_names[a3d->mode];
+	a3d->dev.phys = a3d->phys;
 	a3d->dev.idbus = BUS_GAMEPORT;
 	a3d->dev.idvendor = GAMEPORT_ID_VENDOR_MADCATZ;
 	a3d->dev.idproduct = a3d->mode;
 	a3d->dev.idversion = 0x0100;
 
 	input_register_device(&a3d->dev);
-	printk(KERN_INFO "input%d: %s on gameport%d.0\n",
-		a3d->dev.number, a3d_names[a3d->mode], gameport->number);
+	printk(KERN_INFO "input: %s on %s\n", a3d_names[a3d->mode], a3d->phys);
 
 	return;
 fail2:	gameport_close(gameport);
@@ -384,5 +396,3 @@
 
 module_init(a3d_init);
 module_exit(a3d_exit);
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.6-pre1/drivers/input/joystick/adi.c linux-2.5.6-pre2/drivers/input/joystick/adi.c
--- linux-2.5.6-pre1/drivers/input/joystick/adi.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/adi.c	Thu Feb 28 13:34:21 2002
@@ -1,9 +1,7 @@
 /*
- * $Id: adi.c,v 1.15 2001/01/09 13:32:39 vojtech Exp $
+ * $Id: adi.c,v 1.23 2002/01/22 20:26:17 vojtech Exp $
  *
- *  Copyright (c) 1998-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
+ *  Copyright (c) 1998-2001 Vojtech Pavlik
  */
 
 /*
@@ -26,8 +24,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/delay.h>
@@ -39,6 +37,10 @@
 #include <linux/gameport.h>
 #include <linux/init.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Logitech ADI joystick family driver");
+MODULE_LICENSE("GPL");
+
 /*
  * Times, array sizes, flags, ids.
  */
@@ -55,6 +57,7 @@
 #define ADI_MIN_ID_LENGTH	66
 #define ADI_MAX_NAME_LENGTH	48
 #define ADI_MAX_CNAME_LENGTH	16
+#define ADI_MAX_PHYS_LENGTH	32
 
 #define ADI_FLAG_HAT		0x04
 #define ADI_FLAG_10BIT		0x08
@@ -118,6 +121,7 @@
 	short *key;
 	char name[ADI_MAX_NAME_LENGTH];
 	char cname[ADI_MAX_CNAME_LENGTH];
+	char phys[ADI_MAX_PHYS_LENGTH];
 	unsigned char data[ADI_MAX_LENGTH];
 };
 
@@ -392,7 +396,7 @@
 	}
 }
 
-static void adi_init_input(struct adi *adi, struct adi_port *port)
+static void adi_init_input(struct adi *adi, struct adi_port *port, int half)
 {
 	int i, t;
 	char buf[ADI_MAX_NAME_LENGTH];
@@ -403,6 +407,7 @@
 
 	sprintf(buf, adi_names[t], adi->id);
 	sprintf(adi->name, "Logitech %s", buf);
+	sprintf(adi->phys, "%s/input%d", port->gameport->phys, half);
 
 	adi->abs = adi_abs[t];
 	adi->key = adi_key[t];
@@ -411,6 +416,7 @@
 	adi->dev.close = adi_close;
 
 	adi->dev.name = adi->name;
+	adi->dev.phys = adi->phys;
 	adi->dev.idbus = BUS_GAMEPORT;
 	adi->dev.idvendor = GAMEPORT_ID_VENDOR_LOGITECH;
 	adi->dev.idproduct = adi->id;
@@ -419,7 +425,7 @@
 	adi->dev.private = port;
 	adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
-	for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; i++)
+	for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++)
 		set_bit(adi->abs[i], &adi->dev.absbit);
 
 	for (i = 0; i < adi->buttons; i++)
@@ -432,7 +438,7 @@
 
 	if (!adi->length) return;
 
-	for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; i++) {
+	for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) {
 
 		t = adi->abs[i];
 		x = adi->dev.abs[t];
@@ -495,7 +501,7 @@
 
 	for (i = 0; i < 2; i++) {
 		adi_id_decode(port->adi + i, port);
-		adi_init_input(port->adi + i, port);
+		adi_init_input(port->adi + i, port, i);
 	}
 
 	if (!port->adi[0].length && !port->adi[1].length) {
@@ -514,8 +520,8 @@
 		if (port->adi[i].length > 0) {
 			adi_init_center(port->adi + i);
 			input_register_device(&port->adi[i].dev);
-			printk(KERN_INFO "input%d: %s [%s] on gameport%d.%d\n",
-				port->adi[i].dev.number, port->adi[i].name, port->adi[i].cname, gameport->number, i);
+			printk(KERN_INFO "input: %s [%s] on %s\n",
+				port->adi[i].name, port->adi[i].cname, gameport->phys);
 		}
 }
 
@@ -553,5 +559,3 @@
 
 module_init(adi_init);
 module_exit(adi_exit);
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.6-pre1/drivers/input/joystick/amijoy.c linux-2.5.6-pre2/drivers/input/joystick/amijoy.c
--- linux-2.5.6-pre1/drivers/input/joystick/amijoy.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/amijoy.c	Thu Feb 28 13:34:21 2002
@@ -1,9 +1,7 @@
 /*
- * $Id: amijoy.c,v 1.5 2000/07/21 22:52:24 vojtech Exp $
+ * $Id: amijoy.c,v 1.13 2002/01/22 20:26:32 vojtech Exp $
  *
- *  Copyright (c) 1998-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
+ *  Copyright (c) 1998-2001 Vojtech Pavlik
  */
 
 /*
@@ -26,8 +24,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/types.h>
@@ -40,13 +38,15 @@
 #include <asm/system.h>
 #include <asm/amigahw.h>
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Driver for Amiga joysticks");
 MODULE_PARM(amijoy, "1-2i");
 MODULE_LICENSE("GPL");
 
 static int amijoy[2] = { 0, 1 };
 static int amijoy_used[2] = { 0, 0 };
 static struct input_dev amijoy_dev[2];
+static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
 
 static char *amijoy_name = "Amiga joystick";
 
@@ -64,9 +64,9 @@
 
 			input_report_key(amijoy_dev + i, BTN_TRIGGER, button);
 
-			input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1);
+			input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1));
 			data = ~(data ^ (data << 1));
-			input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1);
+			input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1));
 		}
 }
 
@@ -133,6 +133,7 @@
 			}
 
 			amijoy->dev[i].name = amijoy_name;
+			amijoy->dev[i].phys = amijoy_phys[i];
 			amijoy->dev[i].idbus = BUS_AMIGA;
 			amijoy->dev[i].idvendor = 0x0001;
 			amijoy->dev[i].idproduct = 0x0003;
@@ -141,7 +142,7 @@
 			amijoy_dev[i].private = amijoy_used + i;
 
 			input_register_device(amijoy_dev + i);
-			printk(KERN_INFO "input%d: %s at joy%ddat\n", amijoy_dev[i].number, amijoy_name, i);
+			printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
 		}
 	return 0;
 }
diff -urN linux-2.5.6-pre1/drivers/input/joystick/analog.c linux-2.5.6-pre2/drivers/input/joystick/analog.c
--- linux-2.5.6-pre1/drivers/input/joystick/analog.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/analog.c	Thu Feb 28 13:34:21 2002
@@ -1,9 +1,7 @@
 /*
- * $Id: analog.c,v 1.52 2000/06/07 13:07:06 vojtech Exp $
+ * $Id: analog.c,v 1.68 2002/01/22 20:18:32 vojtech Exp $
  *
- *  Copyright (c) 1996-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
+ *  Copyright (c) 1996-2001 Vojtech Pavlik
  */
 
 /*
@@ -26,8 +24,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/config.h>
@@ -41,8 +39,8 @@
 #include <linux/gameport.h>
 #include <asm/timex.h>
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_DESCRIPTION("Analog joystick and gamepad driver for Linux");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Analog joystick and gamepad driver");
 MODULE_LICENSE("GPL");
 
 /*
@@ -95,6 +93,7 @@
 #define ANALOG_FUZZ_MAGIC	36	/* 36 u*ms/loop */
 
 #define ANALOG_MAX_NAME_LENGTH  128
+#define ANALOG_MAX_PHYS_LENGTH	32
 
 static short analog_axes[] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE };
 static short analog_hats[] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
@@ -111,6 +110,7 @@
 	int mask;
 	short *buttons;
 	char name[ANALOG_MAX_NAME_LENGTH];
+	char phys[ANALOG_MAX_PHYS_LENGTH];
 };
 
 struct analog_port {
@@ -138,15 +138,29 @@
 
 #ifdef __i386__
 #define TSC_PRESENT	(test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability))
-#define GET_TIME(x)	do { if (TSC_PRESENT) rdtscl(x); else { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } } while (0)
+#define GET_TIME(x)	do { if (TSC_PRESENT) rdtscl(x); else x = get_time_pit(); } while (0)
 #define DELTA(x,y)	(TSC_PRESENT?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0)))
 #define TIME_NAME	(TSC_PRESENT?"TSC":"PIT")
+static unsigned int get_time_pit(void)
+{
+        extern spinlock_t i8253_lock;
+        unsigned long flags;
+        unsigned int count;
+
+        spin_lock_irqsave(&i8253_lock, flags);
+        outb_p(0x00, 0x43);
+        count = inb_p(0x40);
+        count |= inb_p(0x40) << 8;
+        spin_unlock_irqrestore(&i8253_lock, flags);
+
+        return count;
+}
 #elif __x86_64__
 #define GET_TIME(x)	rdtscl(x)
 #define DELTA(x,y)	((y)-(x))
 #define TIME_NAME	"TSC"
 #elif __alpha__
-#define GET_TIME(x)	((x) = get_cycles())
+#define GET_TIME(x)	do { x = get_cycles(x); } while (0)
 #define DELTA(x,y)	((y)-(x))
 #define TIME_NAME	"PCC"
 #else
@@ -418,10 +432,12 @@
 	int i, j, t, v, w, x, y, z;
 
 	analog_name(analog);
+	sprintf(analog->phys, "%s/input%d", port->gameport->phys, index);
 
 	analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn;
 
 	analog->dev.name = analog->name;
+	analog->dev.phys = analog->phys;
 	analog->dev.idbus = BUS_GAMEPORT;
 	analog->dev.idvendor = GAMEPORT_ID_VENDOR_ANALOG;
 	analog->dev.idproduct = analog->mask >> 4;
@@ -491,15 +507,14 @@
 
 	input_register_device(&analog->dev);
 
-	printk(KERN_INFO "input%d: %s at gameport%d.%d",
-		analog->dev.number, analog->name, port->gameport->number, index);
+	printk(KERN_INFO "input: %s at %s", analog->name, port->gameport->phys);
 
 	if (port->cooked)
 		printk(" [ADC port]\n");
 	else
 		printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME,
 		port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed,
-		port->speed > 10000 ? "M" : "k",
+		port->speed > 10000 ? "M" : "k", 
 		port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000)
 				    : (port->loop * 1000000) / port->speed);
 }
@@ -519,12 +534,13 @@
 
 	if ((port->mask & 3) != 3 && port->mask != 0xc) {
 		printk(KERN_WARNING "analog.c: Unknown joystick device found  "
-			"(data=%#x, gameport%d), probably not analog joystick.\n",
-			port->mask, port->gameport->number);
+			"(data=%#x, %s), probably not analog joystick.\n",
+			port->mask, port->gameport->phys);
 		return -1;
 	}
 
-	i = port->gameport->number < ANALOG_PORTS ? analog_options[port->gameport->number] : 0xff;
+
+	i = analog_options[0]; /* FIXME !!! - need to specify options for different ports */
 
 	analog[0].mask = i & 0xfffff;
 
@@ -604,8 +620,8 @@
 		gameport_trigger(gameport);
 		while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++; 
 
-		if (v < (u >> 1) && port->gameport->number < ANALOG_PORTS) {
-			analog_options[port->gameport->number] |=
+		if (v < (u >> 1)) { /* FIXME - more than one port */
+			analog_options[0] |= /* FIXME - more than one port */
 				ANALOG_SAITEK | ANALOG_BTNS_CHF | ANALOG_HBTN_CHF | ANALOG_HAT1_CHF;
 			return 0;
 		}
@@ -666,9 +682,9 @@
 		if (port->analog[i].mask)
 			input_unregister_device(&port->analog[i].dev);
 	gameport_close(gameport);
-	printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on gameport%d failed\n",
+	printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on %s failed\n",
 		port->bads, port->reads, port->reads ? (port->bads * 100 / port->reads) : 0,
-		port->gameport->number);
+		port->gameport->phys);
 	kfree(port);
 }
 
diff -urN linux-2.5.6-pre1/drivers/input/joystick/cobra.c linux-2.5.6-pre2/drivers/input/joystick/cobra.c
--- linux-2.5.6-pre1/drivers/input/joystick/cobra.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/cobra.c	Thu Feb 28 13:34:21 2002
@@ -1,13 +1,11 @@
 /*
- * $Id: cobra.c,v 1.10 2000/06/08 10:23:45 vojtech Exp $
+ * $Id: cobra.c,v 1.19 2002/01/22 20:26:52 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  */
 
 /*
- * Creative Labd Blaster GamePad Cobra driver for Linux
+ * Creative Labs Blaster GamePad Cobra driver for Linux
  */
 
 /*
@@ -26,8 +24,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -37,6 +35,10 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Creative Labs Blaster GamePad Cobra driver");
+MODULE_LICENSE("GPL");
+
 #define COBRA_MAX_STROBE	45	/* 45 us max wait for first strobe */
 #define COBRA_REFRESH_TIME	HZ/50	/* 20 ms between reads */
 #define COBRA_LENGTH		36
@@ -53,6 +55,7 @@
 	int reads;
 	int bads;
 	unsigned char exists;
+	char phys[2][32];
 };
 
 static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data)
@@ -121,6 +124,7 @@
 
 	if ((r = cobra_read_packet(cobra->gameport, data)) != cobra->exists)
 		cobra->bads++;
+	else
 
 	for (i = 0; i < 2; i++)
 		if (cobra->exists & r & (1 << i)) {
@@ -177,8 +181,8 @@
 
 	for (i = 0; i < 2; i++) 
 		if ((cobra->exists >> i) & data[i] & 1) {
-			printk(KERN_WARNING "cobra.c: Device on gameport%d.%d has the Ext bit set. ID is: %d"
-				" Contact vojtech@suse.cz\n", gameport->number, i, (data[i] >> 2) & 7);
+			printk(KERN_WARNING "cobra.c: Device %d on %s has the Ext bit set. ID is: %d"
+				" Contact vojtech@ucw.cz\n", i, gameport->phys, (data[i] >> 2) & 7);
 			cobra->exists &= ~(1 << i);
 		}
 
@@ -188,11 +192,14 @@
 	for (i = 0; i < 2; i++)
 		if ((cobra->exists >> i) & 1) {
 
+			sprintf(cobra->phys[i], "%s/input%d", gameport->phys, i);
+
 			cobra->dev[i].private = cobra;
 			cobra->dev[i].open = cobra_open;
 			cobra->dev[i].close = cobra_close;
 
 			cobra->dev[i].name = cobra_name;
+			cobra->dev[i].phys = cobra->phys[i];
 			cobra->dev[i].idbus = BUS_GAMEPORT;
 			cobra->dev[i].idvendor = GAMEPORT_ID_VENDOR_CREATIVE;
 			cobra->dev[i].idproduct = 0x0008;
@@ -208,11 +215,9 @@
 			cobra->dev[i].absmin[ABS_Y] = -1; cobra->dev[i].absmax[ABS_Y] = 1;
 
 			input_register_device(cobra->dev + i);
-			printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
-				cobra->dev[i].number, cobra_name, gameport->number, i);
+			printk(KERN_INFO "input: %s on %s\n", cobra_name, gameport->phys);
 		}
 
-
 	return;
 fail2:	gameport_close(gameport);
 fail1:	kfree(cobra);
@@ -248,5 +253,3 @@
 
 module_init(cobra_init);
 module_exit(cobra_exit);
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.6-pre1/drivers/input/joystick/db9.c linux-2.5.6-pre2/drivers/input/joystick/db9.c
--- linux-2.5.6-pre1/drivers/input/joystick/db9.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/db9.c	Thu Feb 28 13:34:21 2002
@@ -1,12 +1,10 @@
 /*
- * $Id: db9.c,v 1.6 2000/06/25 10:57:50 vojtech Exp $
+ * $Id: db9.c,v 1.12 2002/01/22 20:27:05 vojtech Exp $
  *
- *  Copyright (c) 1999 Vojtech Pavlik
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  Based on the work of:
  *	Andree Borrmann		Mats Sjövall
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -29,8 +27,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -40,8 +38,10 @@
 #include <linux/parport.h>
 #include <linux/input.h>
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver");
 MODULE_LICENSE("GPL");
+
 MODULE_PARM(db9, "2i");
 MODULE_PARM(db9_2, "2i");
 MODULE_PARM(db9_3, "2i");
@@ -87,6 +87,7 @@
 	struct pardevice *pd;	
 	int mode;
 	int used;
+	char phys[2][32];
 };
 
 static struct db9 *db9_base[3];
@@ -342,11 +343,14 @@
 
 	for (i = 0; i < 1 + (db9->mode == DB9_MULTI_0802_2); i++) {
 
+		sprintf(db9->phys[i], "%s/input%d", db9->pd->port->name, i);
+
 		db9->dev[i].private = db9;
 		db9->dev[i].open = db9_open;
 		db9->dev[i].close = db9_close;
 
 		db9->dev[i].name = db9_name[db9->mode];
+		db9->dev[i].phys = db9->phys[i];
 		db9->dev[i].idbus = BUS_PARPORT;
 		db9->dev[i].idvendor = 0x0002;
 		db9->dev[i].idproduct = config[1];
@@ -362,8 +366,7 @@
 		db9->dev[i].absmin[ABS_Y] = -1; db9->dev[i].absmax[ABS_Y] = 1;
 
 		input_register_device(db9->dev + i);
-		printk(KERN_INFO "input%d: %s on %s\n",
-			db9->dev[i].number, db9_name[db9->mode], db9->pd->port->name);
+		printk(KERN_INFO "input: %s on %s\n", db9->dev[i].name, db9->pd->port->name);
 	}
 
 	return db9;
diff -urN linux-2.5.6-pre1/drivers/input/joystick/gamecon.c linux-2.5.6-pre2/drivers/input/joystick/gamecon.c
--- linux-2.5.6-pre1/drivers/input/joystick/gamecon.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/gamecon.c	Thu Feb 28 13:34:21 2002
@@ -1,17 +1,15 @@
 /*
- * $Id: gamecon.c,v 1.14 2001/04/29 22:42:14 vojtech Exp $
+ * $Id: gamecon.c,v 1.21 2002/01/22 20:27:27 vojtech Exp $
  *
  *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  Based on the work of:
  *  	Andree Borrmann		John Dahlstrom
  *  	David Kuder		Nathan Hand
- *
- *  Sponsored by SuSE
  */
 
 /*
- * NES, SNES, N64, Multi1, Multi2, PSX gamepad driver for Linux
+ * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
  */
 
 /*
@@ -30,8 +28,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -41,8 +39,10 @@
 #include <linux/parport.h>
 #include <linux/input.h>
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver");
 MODULE_LICENSE("GPL");
+
 MODULE_PARM(gc, "2-6i");
 MODULE_PARM(gc_2,"2-6i");
 MODULE_PARM(gc_3,"2-6i");
@@ -65,6 +65,7 @@
 	struct timer_list timer;
 	unsigned char pads[GC_MAX + 1];
 	int used;
+	char phys[5][32];
 };
 
 static struct gc *gc_base[3];
@@ -585,12 +586,15 @@
 					default:
 						gc->pads[GC_PSX] &= ~gc_status_bit[i];
 						printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x,"
-							" please report to <vojtech@suse.cz>.\n", psx);
+							" please report to <vojtech@ucw.cz>.\n", psx);
 				}
 				break;
 		}
 
+		sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i);
+		
                 gc->dev[i].name = gc_names[config[i + 1]];
+		gc->dev[i].phys = gc->phys[i];
                 gc->dev[i].idbus = BUS_PARPORT;
                 gc->dev[i].idvendor = 0x0001;
                 gc->dev[i].idproduct = config[i + 1];
@@ -608,7 +612,7 @@
 	for (i = 0; i < 5; i++) 
 		if (gc->pads[0] & gc_status_bit[i]) {
 			input_register_device(gc->dev + i);
-			printk(KERN_INFO "input%d: %s on %s\n", gc->dev[i].number, gc->dev[i].name, gc->pd->port->name);
+			printk(KERN_INFO "input: %s on %s\n", gc->dev[i].name, gc->pd->port->name);
 		}
 
 	return gc;
diff -urN linux-2.5.6-pre1/drivers/input/joystick/gf2k.c linux-2.5.6-pre2/drivers/input/joystick/gf2k.c
--- linux-2.5.6-pre1/drivers/input/joystick/gf2k.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/gf2k.c	Thu Feb 28 13:34:21 2002
@@ -1,9 +1,7 @@
 /*
- * $Id: gf2k.c,v 1.12 2000/06/04 14:53:44 vojtech Exp $
+ * $Id: gf2k.c,v 1.19 2002/01/22 20:27:43 vojtech Exp $
  *
- *  Copyright (c) 1998-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
+ *  Copyright (c) 1998-2001 Vojtech Pavlik
  */
 
 /*
@@ -26,8 +24,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/delay.h>
@@ -38,6 +36,10 @@
 #include <linux/input.h>
 #include <linux/gameport.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Genius Flight 2000 joystick driver");
+MODULE_LICENSE("GPL");
+
 #define GF2K_START		400	/* The time we wait for the first bit [400 us] */
 #define GF2K_STROBE		40	/* The time we wait for the first bit [40 us] */
 #define GF2K_TIMEOUT		4	/* Wait for everything to settle [4 ms] */
@@ -85,6 +87,7 @@
 	int used;
 	unsigned char id;
 	unsigned char length;
+	char phys[32];
 };
 
 /*
@@ -278,11 +281,13 @@
 #endif
 
 	if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) {
-		printk(KERN_WARNING "gf2k.c: Not yet supported joystick on gameport%d. [id: %d type:%s]\n",
-			gameport->number, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]);
+		printk(KERN_WARNING "gf2k.c: Not yet supported joystick on %s. [id: %d type:%s]\n",
+			gameport->phys, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]);
 		goto fail2;
 	}
 
+	sprintf(gf2k->phys, "%s/input0", gameport->phys);
+
 	gf2k->length = gf2k_lens[gf2k->id];
 
 	gf2k->dev.private = gf2k;
@@ -291,6 +296,7 @@
 	gf2k->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
 
 	gf2k->dev.name = gf2k_names[gf2k->id];
+	gf2k->dev.phys = gf2k->phys;
 	gf2k->dev.idbus = BUS_GAMEPORT;
 	gf2k->dev.idvendor = GAMEPORT_ID_VENDOR_GENIUS;
 	gf2k->dev.idproduct = gf2k->id;
@@ -323,8 +329,7 @@
 	}
 
 	input_register_device(&gf2k->dev);
-	printk(KERN_INFO "input%d: %s on gameport%d.0\n",
-		gf2k->dev.number, gf2k_names[gf2k->id], gameport->number);
+	printk(KERN_INFO "input: %s on %s\n", gf2k_names[gf2k->id], gameport->phys);
 
 	return;
 fail2:	gameport_close(gameport);
@@ -357,5 +362,3 @@
 
 module_init(gf2k_init);
 module_exit(gf2k_exit);
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.6-pre1/drivers/input/joystick/grip.c linux-2.5.6-pre2/drivers/input/joystick/grip.c
--- linux-2.5.6-pre1/drivers/input/joystick/grip.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/grip.c	Thu Feb 28 13:34:21 2002
@@ -1,9 +1,7 @@
 /*
- * $Id: grip.c,v 1.14 2000/06/06 21:13:36 vojtech Exp $
+ * $Id: grip.c,v 1.21 2002/01/22 20:27:57 vojtech Exp $
  *
- *  Copyright (c) 1998-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
+ *  Copyright (c) 1998-2001 Vojtech Pavlik
  */
 
 /*
@@ -26,8 +24,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -37,6 +35,10 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Gravis GrIP protocol joystick driver");
+MODULE_LICENSE("GPL");
+
 #define GRIP_MODE_GPP		1
 #define GRIP_MODE_BD		2
 #define GRIP_MODE_XT		3
@@ -59,6 +61,7 @@
 	int used;
 	int reads;
 	int bads;
+	char phys[2][32];
 };
 
 static int grip_btn_gpp[] = { BTN_START, BTN_SELECT, BTN_TR2, BTN_Y, 0, BTN_TL2, BTN_A, BTN_B, BTN_X, 0, BTN_TL, BTN_TR, -1 };
@@ -340,12 +343,15 @@
 	for (i = 0; i < 2; i++)
 		if (grip->mode[i]) {
 
+			sprintf(grip->phys[i], "%s/input%d", gameport->phys, i);
+
 			grip->dev[i].private = grip;
 
 			grip->dev[i].open = grip_open;
 			grip->dev[i].close = grip_close;
 
 			grip->dev[i].name = grip_name[grip->mode[i]];
+			grip->dev[i].phys = grip->phys[i];
 			grip->dev[i].idbus = BUS_GAMEPORT;
 			grip->dev[i].idvendor = GAMEPORT_ID_VENDOR_GRAVIS;
 			grip->dev[i].idproduct = grip->mode[i];
@@ -382,8 +388,8 @@
 
 			input_register_device(grip->dev + i);
 
-			printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
-				grip->dev[i].number, grip_name[grip->mode[i]], gameport->number, i);
+			printk(KERN_INFO "input: %s on %s\n",
+				grip_name[grip->mode[i]], gameport->phys);
 		}
 
 	return;
@@ -421,5 +427,3 @@
 
 module_init(grip_init);
 module_exit(grip_exit);
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.6-pre1/drivers/input/joystick/interact.c linux-2.5.6-pre2/drivers/input/joystick/interact.c
--- linux-2.5.6-pre1/drivers/input/joystick/interact.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/interact.c	Thu Feb 28 13:34:21 2002
@@ -1,12 +1,10 @@
 /*
- * $Id: interact.c,v 1.8 2000/05/29 11:19:51 vojtech Exp $
+ * $Id: interact.c,v 1.16 2002/01/22 20:28:25 vojtech Exp $
  *
- *  Copyright (c) 2000 Vojtech Pavlik
+ *  Copyright (c) 2001 Vojtech Pavlik
  *
  *  Based on the work of:
  *	Toby Deshane
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -29,8 +27,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -41,6 +39,10 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("InterAct digital joystick driver");
+MODULE_LICENSE("GPL");
+
 #define INTERACT_MAX_START	400	/* 400 us */
 #define INTERACT_MAX_STROBE	40	/* 40 us */
 #define INTERACT_MAX_LENGTH	32	/* 32 bits */
@@ -58,6 +60,7 @@
 	int reads;
 	unsigned char type;
 	unsigned char length;
+	char phys[32];
 };
 
 static short interact_abs_hhfx[] = 
@@ -137,40 +140,41 @@
 
 	if (interact_read_packet(interact->gameport, interact->length, data) < interact->length) {
 		interact->bads++;
-	} else
+	} else {
 
-	for (i = 0; i < 3; i++)
-		data[i] <<= INTERACT_MAX_LENGTH - interact->length;
+		for (i = 0; i < 3; i++)
+			data[i] <<= INTERACT_MAX_LENGTH - interact->length;
 
-	switch (interact->type) {
+		switch (interact->type) {
 
-		case INTERACT_TYPE_HHFX:
+			case INTERACT_TYPE_HHFX:
 
-			for (i = 0; i < 4; i++)
-				input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff);
+				for (i = 0; i < 4; i++)
+					input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff);
 
-			for (i = 0; i < 2; i++)
-				input_report_abs(dev, ABS_HAT0Y - i,
-					((data[1] >> ((i << 1) + 17)) & 1)  - ((data[1] >> ((i << 1) + 16)) & 1));
+				for (i = 0; i < 2; i++)
+					input_report_abs(dev, ABS_HAT0Y - i,
+						((data[1] >> ((i << 1) + 17)) & 1)  - ((data[1] >> ((i << 1) + 16)) & 1));
 
-			for (i = 0; i < 8; i++)
-				input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1);
+				for (i = 0; i < 8; i++)
+					input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1);
 
-			for (i = 0; i < 4; i++)
-				input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1);
+				for (i = 0; i < 4; i++)
+					input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1);
 
-			break;
+				break;
 
-		case INTERACT_TYPE_PP8D:
+			case INTERACT_TYPE_PP8D:
 
-			for (i = 0; i < 2; i++)
-				input_report_abs(dev, interact_abs_pp8d[i], 
-					((data[0] >> ((i << 1) + 20)) & 1)  - ((data[0] >> ((i << 1) + 21)) & 1));
+				for (i = 0; i < 2; i++)
+					input_report_abs(dev, interact_abs_pp8d[i], 
+						((data[0] >> ((i << 1) + 20)) & 1)  - ((data[0] >> ((i << 1) + 21)) & 1));
 
-			for (i = 0; i < 8; i++)
-				input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1);
+				for (i = 0; i < 8; i++)
+					input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1);
 
-			break;
+				break;
+		}
 	}
 
 	mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
@@ -235,11 +239,13 @@
 			break;
 
 	if (!interact_type[i].length) {
-		printk(KERN_WARNING "interact.c: Unknown joystick on gameport%d. [len %d d0 %08x d1 %08x i2 %08x]\n",
-			gameport->number, i, data[0], data[1], data[2]);
+		printk(KERN_WARNING "interact.c: Unknown joystick on %s. [len %d d0 %08x d1 %08x i2 %08x]\n",
+			gameport->phys, i, data[0], data[1], data[2]);
 		goto fail2;	
 	}
 
+	sprintf(interact->phys, "%s/input0", gameport->phys);
+
 	interact->type = i;
 	interact->length = interact_type[i].length;
 
@@ -248,6 +254,7 @@
 	interact->dev.close = interact_close;
 
 	interact->dev.name = interact_type[i].name;
+	interact->dev.phys = interact->phys;
 	interact->dev.idbus = BUS_GAMEPORT;
 	interact->dev.idvendor = GAMEPORT_ID_VENDOR_INTERACT;
 	interact->dev.idproduct = interact_type[i].id;
@@ -270,8 +277,8 @@
 		set_bit(t, interact->dev.keybit);
 
 	input_register_device(&interact->dev);
-	printk(KERN_INFO "input%d: %s on gameport%d.0\n",
-		interact->dev.number, interact_type[interact->type].name, gameport->number);
+	printk(KERN_INFO "input: %s on %s\n",
+		interact_type[interact->type].name, gameport->phys);
 
 	return;
 fail2:	gameport_close(gameport);
@@ -304,5 +311,3 @@
 
 module_init(interact_init);
 module_exit(interact_exit);
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.6-pre1/drivers/input/joystick/magellan.c linux-2.5.6-pre2/drivers/input/joystick/magellan.c
--- linux-2.5.6-pre1/drivers/input/joystick/magellan.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/magellan.c	Thu Feb 28 13:34:21 2002
@@ -1,9 +1,7 @@
 /*
- * $Id: magellan.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $
+ * $Id: magellan.c,v 1.16 2002/01/22 20:28:39 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  */
 
 /*
@@ -27,7 +25,7 @@
  * 
  *  Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -37,15 +35,19 @@
 #include <linux/serio.h>
 #include <linux/init.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Magellan and SpaceMouse 6dof controller driver");
+MODULE_LICENSE("GPL");
+
 /*
  * Definitions & global arrays.
  */
 
 #define	MAGELLAN_MAX_LENGTH	32
 
-static int magellan_buttons[] = { BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8};
-static int magellan_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ};
-static char *magellan_name = "LogiCad3D Magellan";
+static int magellan_buttons[] = { BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
+static int magellan_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
+static char *magellan_name = "LogiCad3D Magellan / SpaceMouse";
 
 /*
  * Per-Magellan data.
@@ -55,6 +57,7 @@
 	struct input_dev dev;
 	int idx;
 	unsigned char data[MAGELLAN_MAX_LENGTH];
+	char phys[32];
 };
 
 /*
@@ -162,8 +165,11 @@
 		magellan->dev.absmax[t] =  360;
 	}
 
+	sprintf(magellan->phys, "%s/input0", serio->phys);
+
 	magellan->dev.private = magellan;
 	magellan->dev.name = magellan_name;
+	magellan->dev.phys = magellan->phys;
 	magellan->dev.idbus = BUS_RS232;
 	magellan->dev.idvendor = SERIO_MAGELLAN;
 	magellan->dev.idproduct = 0x0001;
@@ -178,7 +184,7 @@
 
 	input_register_device(&magellan->dev);
 
-	printk(KERN_INFO "input%d: %s on serio%d\n", magellan->dev.number, magellan_name, serio->number);
+	printk(KERN_INFO "input: %s on %s\n", magellan_name, serio->phys);
 }
 
 /*
@@ -208,5 +214,3 @@
 
 module_init(magellan_init);
 module_exit(magellan_exit);
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.6-pre1/drivers/input/joystick/sidewinder.c linux-2.5.6-pre2/drivers/input/joystick/sidewinder.c
--- linux-2.5.6-pre1/drivers/input/joystick/sidewinder.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/sidewinder.c	Thu Feb 28 13:34:21 2002
@@ -1,9 +1,7 @@
 /*
- * $Id: sidewinder.c,v 1.20 2001/05/19 08:14:54 vojtech Exp $
+ * $Id: sidewinder.c,v 1.29 2002/01/22 20:28:51 vojtech Exp $
  *
  *  Copyright (c) 1998-2001 Vojtech Pavlik
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -26,8 +24,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/delay.h>
@@ -38,12 +36,16 @@
 #include <linux/input.h>
 #include <linux/gameport.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Microsoft SideWinder joystick family driver");
+MODULE_LICENSE("GPL");
+
 /*
  * These are really magic values. Changing them can make a problem go away,
  * as well as break everything.
  */
 
-#undef SW_DEBUG
+#define SW_DEBUG
 
 #define SW_START	400	/* The time we wait for the first bit [400 us] */
 #define SW_STROBE	45	/* Max time per bit [45 us] */
@@ -114,6 +116,7 @@
 	struct timer_list timer;
 	struct input_dev dev[4];
 	char name[64];
+	char phys[4][32];
 	int length;
 	int type;
 	int bits;
@@ -411,8 +414,8 @@
 	if (sw->type == SW_ID_3DP && sw->length == 66 && i != 66) {		/* Broken packet, try to fix */
 
 		if (i == 64 && !sw_check(sw_get_bits(buf,0,64,1))) {		/* Last init failed, 1 bit mode */
-			printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on gameport%d"
-				" - going to reinitialize.\n", sw->gameport->number);
+			printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on %s"
+				" - going to reinitialize.\n", sw->gameport->phys);
 			sw->fail = SW_FAIL;					/* Reinitialize */
 			i = 128;						/* Bogus value */
 		}
@@ -437,8 +440,8 @@
 		if (sw->type == SW_ID_3DP && sw->length == 66			/* Many packets OK */
 			&& sw->ok > SW_OK) {
 
-			printk(KERN_INFO "sidewinder.c: No more trouble on gameport%d"
-				" - enabling optimization again.\n", sw->gameport->number);
+			printk(KERN_INFO "sidewinder.c: No more trouble on %s"
+				" - enabling optimization again.\n", sw->gameport->phys);
 			sw->length = 22;
 		}
 
@@ -450,15 +453,15 @@
 
 	if (sw->type == SW_ID_3DP && sw->length == 22 && sw->fail > SW_BAD) {	/* Consecutive bad packets */
 
-		printk(KERN_INFO "sidewinder.c: Many bit errors on gameport%d"
-			" - disabling optimization.\n", sw->gameport->number);
+		printk(KERN_INFO "sidewinder.c: Many bit errors on %s"
+			" - disabling optimization.\n", sw->gameport->phys);
 		sw->length = 66;
 	}
 
 	if (sw->fail < SW_FAIL) return -1;					/* Not enough, don't reinitialize yet */
 
-	printk(KERN_WARNING "sidewinder.c: Too many bit errors on gameport%d"
-		" - reinitializing joystick.\n", sw->gameport->number);
+	printk(KERN_WARNING "sidewinder.c: Too many bit errors on %s"
+		" - reinitializing joystick.\n", sw->gameport->phys);
 
 	if (!i && sw->type == SW_ID_3DP) {					/* 3D Pro can be in analog mode */
 		udelay(3 * SW_TIMEOUT);
@@ -582,8 +585,8 @@
 	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
 		goto fail1;
 
-	dbg("Init 0: Opened gameport %d, io %#x, speed %d",
-		gameport->number, gameport->io, gameport->speed);
+	dbg("Init 0: Opened %s, io %#x, speed %d",
+		gameport->phys, gameport->io, gameport->speed);
 
 	i = sw_read_packet(gameport, buf, SW_LENGTH, 0);		/* Read normal packet */
 	m |= sw_guess_mode(buf, i);					/* Data packet (1-bit) can carry mode info [FSP] */
@@ -673,7 +676,7 @@
 
 	if (sw->type == -1) {
 		printk(KERN_WARNING "sidewinder.c: unknown joystick device detected "
-			"on gameport%d, contact <vojtech@suse.cz>\n", gameport->number);
+			"on %s, contact <vojtech@ucw.cz>\n", gameport->phys);
 		sw_print_packet("ID", j * 3, idbuf, 3);
 		sw_print_packet("Data", i * m, buf, m);
 		goto fail2;
@@ -691,6 +694,7 @@
 		int bits, code;
 
 		sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]);
+		sprintf(sw->phys[i], "%s/input%d", gameport->phys, i);
 
 		sw->dev[i].private = sw;
 
@@ -698,6 +702,7 @@
 		sw->dev[i].close = sw_close;
 
 		sw->dev[i].name = sw->name;
+		sw->dev[i].phys = sw->phys[i];
 		sw->dev[i].idbus = BUS_GAMEPORT;
 		sw->dev[i].idvendor = GAMEPORT_ID_VENDOR_MICROSOFT;
 		sw->dev[i].idproduct = sw->type;
@@ -719,8 +724,8 @@
 			set_bit(code, sw->dev[i].keybit);
 
 		input_register_device(sw->dev + i);
-		printk(KERN_INFO "input%d: %s%s on gameport%d.%d [%d-bit id %d data %d]\n",
-			sw->dev[i].number, sw->name, comment, gameport->number, i, m, l, k);
+		printk(KERN_INFO "input: %s%s on %s [%d-bit id %d data %d]\n",
+			sw->name, comment, gameport->phys, m, l, k);
 	}
 
 	return;
@@ -757,5 +762,3 @@
 
 module_init(sw_init);
 module_exit(sw_exit);
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.6-pre1/drivers/input/joystick/spaceball.c linux-2.5.6-pre2/drivers/input/joystick/spaceball.c
--- linux-2.5.6-pre1/drivers/input/joystick/spaceball.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/spaceball.c	Thu Feb 28 13:34:21 2002
@@ -1,17 +1,15 @@
 /*
- * $Id: spaceball.c,v 1.8 2000/11/23 11:42:39 vojtech Exp $
+ * $Id: spaceball.c,v 1.17 2002/01/22 20:29:03 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  Based on the work of:
  *  	David Thompson
  *  	Joseph Krahn
- *
- *  Sponsored by SuSE
  */
 
 /*
- * SpaceTec SpaceBall 4000 FLX driver for Linux
+ * SpaceTec SpaceBall 2003/3003/4000 FLX driver for Linux
  */
 
 /*
@@ -30,8 +28,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  *  Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -41,13 +39,29 @@
 #include <linux/input.h>
 #include <linux/serio.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("SpaceTec SpaceBall 2003/3003/4000 FLX driver");
+MODULE_LICENSE("GPL");
+
 /*
  * Constants.
  */
 
-#define JS_SBALL_MAX_LENGTH	128
+#define SPACEBALL_MAX_LENGTH	128
+#define SPACEBALL_MAX_ID	8
+
+#define SPACEBALL_1003      1
+#define SPACEBALL_2003B     3
+#define SPACEBALL_2003C     4
+#define SPACEBALL_3003C     7
+#define SPACEBALL_4000FLX   8
+#define SPACEBALL_4000FLX_L 9
+
 static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY };
-static char *spaceball_name = "SpaceTec SpaceBall 4000 FLX"; 
+static char *spaceball_names[] = {
+	"?", "SpaceTec SpaceBall 1003", "SpaceTec SpaceBall 2003", "SpaceTec SpaceBall 2003B", 
+	"SpaceTec SpaceBall 2003C", "SpaceTec SpaceBall 3003", "SpaceTec SpaceBall SpaceController", 
+	"SpaceTec SpaceBall 3003C", "SpaceTec SpaceBall 4000FLX", "SpaceTec SpaceBall 4000FLX Lefty" };
 
 /*
  * Per-Ball data.
@@ -58,7 +72,8 @@
 	struct serio *serio;
 	int idx;
 	int escape;
-	unsigned char data[JS_SBALL_MAX_LENGTH];
+	unsigned char data[SPACEBALL_MAX_LENGTH];
+	char phys[32];
 };
 
 /*
@@ -74,35 +89,53 @@
 
 	if (spaceball->idx < 2) return;
 
-	printk("%c %d\n", spaceball->data[0], spaceball->idx);
-
 	switch (spaceball->data[0]) {
 
-		case '@':					/* Reset packet */
-			spaceball->data[spaceball->idx - 1] = 0;
-			for (i = 1; i < spaceball->idx && spaceball->data[i] == ' '; i++);
-			printk(KERN_INFO "input%d: %s [%s] on serio%d\n",
-				spaceball->dev.number, spaceball_name, spaceball->data + i, spaceball->serio->number);
-			break;
-
 		case 'D':					/* Ball data */
 			if (spaceball->idx != 15) return;
-			for (i = 0; i < 6; i++) {
+			for (i = 0; i < 6; i++)
 				input_report_abs(dev, spaceball_axes[i], 
 					(__s16)((data[2 * i + 3] << 8) | data[2 * i + 2]));
-			}
 			break;
 
-		case '.':				/* Button data, part2 */
+		case 'K':					/* Button data */
 			if (spaceball->idx != 3) return;
-			input_report_key(dev, BTN_0,  data[2] & 1);
-			input_report_key(dev, BTN_1, data[2] & 2);
+			input_report_key(dev, BTN_1, (data[2] & 0x01) || (data[2] & 0x20));
+			input_report_key(dev, BTN_2, data[2] & 0x02);
+			input_report_key(dev, BTN_3, data[2] & 0x04);
+			input_report_key(dev, BTN_4, data[2] & 0x08);
+			input_report_key(dev, BTN_5, data[1] & 0x01);
+			input_report_key(dev, BTN_6, data[1] & 0x02);
+			input_report_key(dev, BTN_7, data[1] & 0x04);
+			input_report_key(dev, BTN_8, data[1] & 0x10);
 			break;
 
-		case '?':				/* Error packet */
+		case '.':					/* Advanced button data */
+			if (spaceball->idx != 3) return;
+			input_report_key(dev, BTN_1, data[2] & 0x01);
+			input_report_key(dev, BTN_2, data[2] & 0x02);
+			input_report_key(dev, BTN_3, data[2] & 0x04);
+			input_report_key(dev, BTN_4, data[2] & 0x08);
+			input_report_key(dev, BTN_5, data[2] & 0x10);
+			input_report_key(dev, BTN_6, data[2] & 0x20);
+			input_report_key(dev, BTN_7, data[2] & 0x80);
+			input_report_key(dev, BTN_8, data[1] & 0x01);
+			input_report_key(dev, BTN_9, data[1] & 0x02);
+			input_report_key(dev, BTN_A, data[1] & 0x04);
+			input_report_key(dev, BTN_B, data[1] & 0x08);
+			input_report_key(dev, BTN_C, data[1] & 0x10);
+			input_report_key(dev, BTN_MODE, data[1] & 0x20);
+			break;
+
+		case 'E':					/* Device error */
 			spaceball->data[spaceball->idx - 1] = 0;
 			printk(KERN_ERR "spaceball: Device error. [%s]\n", spaceball->data + 1);
 			break;
+
+		case '?':					/* Bad command packet */
+			spaceball->data[spaceball->idx - 1] = 0;
+			printk(KERN_ERR "spaceball: Bad command. [%s]\n", spaceball->data + 1);
+			break;
 	}
 }
 
@@ -136,11 +169,9 @@
 				data &= 0x1f;
 			}
 		default:
-			if (spaceball->escape) {
+			if (spaceball->escape)
 				spaceball->escape = 0;
-				printk(KERN_WARNING "spaceball.c: Unknown escaped character: %#x (%c)\n", data, data);
-			}
-			if (spaceball->idx < JS_SBALL_MAX_LENGTH)
+			if (spaceball->idx < SPACEBALL_MAX_LENGTH)
 				spaceball->data[spaceball->idx++] = data;
 			return;
 	}
@@ -167,9 +198,12 @@
 static void spaceball_connect(struct serio *serio, struct serio_dev *dev)
 {
 	struct spaceball *spaceball;
-	int i, t;
+	int i, t, id;
 
-	if (serio->type != (SERIO_RS232 | SERIO_SPACEBALL))
+	if ((serio->type & ~SERIO_ID) != (SERIO_RS232 | SERIO_SPACEBALL))
+		return;
+
+	if ((id = (serio->type & SERIO_ID) >> 8) > SPACEBALL_MAX_ID)
 		return;
 
 	if (!(spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL)))
@@ -177,7 +211,18 @@
 	memset(spaceball, 0, sizeof(struct spaceball));
 
 	spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
-	spaceball->dev.keybit[LONG(BTN_0)] = BIT(BTN_0) | BIT(BTN_1);
+
+	switch (id) {
+		case SPACEBALL_4000FLX:
+		case SPACEBALL_4000FLX_L:
+			spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_9);
+			spaceball->dev.keybit[LONG(BTN_A)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_MODE);
+		default:
+			spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) 
+				| BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7) | BIT(BTN_8);
+		case SPACEBALL_3003C:
+			spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_1) | BIT(BTN_8);
+	}
 
 	for (i = 0; i < 6; i++) {
 		t = spaceball_axes[i];
@@ -191,10 +236,13 @@
 	spaceball->serio = serio;
 	spaceball->dev.private = spaceball;
 
-	spaceball->dev.name = spaceball_name;
+	sprintf(spaceball->phys, "%s/input0", serio->phys);
+
+	spaceball->dev.name = spaceball_names[id];
+	spaceball->dev.phys = spaceball->phys;
 	spaceball->dev.idbus = BUS_RS232;
 	spaceball->dev.idvendor = SERIO_SPACEBALL;
-	spaceball->dev.idproduct = 0x0001;
+	spaceball->dev.idproduct = id;
 	spaceball->dev.idversion = 0x0100;
 	
 	serio->private = spaceball;
@@ -205,6 +253,9 @@
 	}
 
 	input_register_device(&spaceball->dev);
+
+	printk(KERN_INFO "input: %s on serio%s\n",
+		spaceball_names[id], serio->phys);
 }
 
 /*
@@ -234,5 +285,3 @@
 
 module_init(spaceball_init);
 module_exit(spaceball_exit);
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.6-pre1/drivers/input/joystick/spaceorb.c linux-2.5.6-pre2/drivers/input/joystick/spaceorb.c
--- linux-2.5.6-pre1/drivers/input/joystick/spaceorb.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/spaceorb.c	Thu Feb 28 13:34:21 2002
@@ -1,12 +1,10 @@
 /*
- * $Id: spaceorb.c,v 1.7 2000/05/29 11:19:51 vojtech Exp $
+ * $Id: spaceorb.c,v 1.15 2002/01/22 20:29:19 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  * 
  *  Based on the work of:
  *  	David Thompson
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -29,8 +27,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  *  Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -40,15 +38,19 @@
 #include <linux/input.h>
 #include <linux/serio.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("SpaceTec SpaceOrb 360 and Avenger 6dof controller driver");
+MODULE_LICENSE("GPL");
+
 /*
  * Constants.
  */
 
 #define SPACEORB_MAX_LENGTH	64
 
-static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A, BTN_MODE};
-static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ};
-static char *spaceorb_name = "SpaceTec SpaceOrb 360";
+static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A };
+static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
+static char *spaceorb_name = "SpaceTec SpaceOrb 360 / Avenger";
 
 /*
  * Per-Orb data.
@@ -59,6 +61,7 @@
 	struct serio *serio;
 	int idx;
 	unsigned char data[SPACEORB_MAX_LENGTH];
+	char phys[32];
 };
 
 static unsigned char spaceorb_xor[] = "SpaceWare";
@@ -88,8 +91,8 @@
 		case 'R':				/* Reset packet */
 			spaceorb->data[spaceorb->idx - 1] = 0;
 			for (i = 1; i < spaceorb->idx && spaceorb->data[i] == ' '; i++);
-			printk(KERN_INFO "input%d: %s [%s] on serio%d\n",
-				 spaceorb->dev.number, spaceorb_name, spaceorb->data + i, spaceorb->serio->number);
+			printk(KERN_INFO "input: %s [%s] on %s\n",
+				 spaceorb_name, spaceorb->data + i, spaceorb->serio->phys);
 			break;
 
 		case 'D':				/* Ball + button data */
@@ -103,7 +106,7 @@
 			axes[5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3);
 			for (i = 0; i < 6; i++)
 				input_report_abs(dev, spaceorb_axes[i], axes[i] - ((axes[i] & 0x200) ? 1024 : 0));
-			for (i = 0; i < 8; i++)
+			for (i = 0; i < 6; i++)
 				input_report_key(dev, spaceorb_buttons[i], (data[1] >> i) & 1);
 			break;
 
@@ -167,8 +170,8 @@
 
 	spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);	
 
-	for (i = 0; i < 7; i++)
-		set_bit(spaceorb_buttons[i], &spaceorb->dev.keybit);
+	for (i = 0; i < 6; i++)
+		set_bit(spaceorb_buttons[i], spaceorb->dev.keybit);
 
 	for (i = 0; i < 6; i++) {
 		t = spaceorb_axes[i];
@@ -180,7 +183,10 @@
 	spaceorb->serio = serio;
 	spaceorb->dev.private = spaceorb;
 
+	sprintf(spaceorb->phys, "%s/input0", serio->phys);
+
 	spaceorb->dev.name = spaceorb_name;
+	spaceorb->dev.phys = spaceorb->phys;
 	spaceorb->dev.idbus = BUS_RS232;
 	spaceorb->dev.idvendor = SERIO_SPACEORB;
 	spaceorb->dev.idproduct = 0x0001;
@@ -223,5 +229,3 @@
 
 module_init(spaceorb_init);
 module_exit(spaceorb_exit);
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.6-pre1/drivers/input/joystick/stinger.c linux-2.5.6-pre2/drivers/input/joystick/stinger.c
--- linux-2.5.6-pre1/drivers/input/joystick/stinger.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/stinger.c	Thu Feb 28 13:34:21 2002
@@ -1,10 +1,8 @@
 /*
- * $Id: stinger.c,v 1.4 2001/05/23 09:25:02 vojtech Exp $
+ * $Id: stinger.c,v 1.10 2002/01/22 20:29:31 vojtech Exp $
  *
  *  Copyright (c) 2000-2001 Vojtech Pavlik
  *  Copyright (c) 2000 Mark Fletcher
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -28,7 +26,7 @@
  *
  *  Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -38,6 +36,10 @@
 #include <linux/serio.h>
 #include <linux/init.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Gravis Stinger gamepad driver");
+MODULE_LICENSE("GPL");
+
 /*
  * Constants.
  */
@@ -54,6 +56,7 @@
 	struct input_dev dev;
 	int idx;
 	unsigned char data[STINGER_MAX_LENGTH];
+	char phys[32];
 };
 
 /*
@@ -145,7 +148,10 @@
 					   BIT(BTN_START) | BIT(BTN_SELECT);
 	stinger->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
 
+	sprintf(stinger->phys, "%s/serio0", serio->phys);
+
 	stinger->dev.name = stinger_name;
+	stinger->dev.phys = stinger->phys;
 	stinger->dev.idbus = BUS_RS232;
 	stinger->dev.idvendor = SERIO_STINGER;
 	stinger->dev.idproduct = 0x0001;
@@ -168,7 +174,7 @@
 
 	input_register_device(&stinger->dev);
 
-	printk(KERN_INFO "input%d: %s on serio%d\n", stinger->dev.number, stinger_name, serio->number);
+	printk(KERN_INFO "input: %s on %s\n",  stinger_name, serio->phys);
 }
 
 /*
@@ -198,5 +204,3 @@
 
 module_init(stinger_init);
 module_exit(stinger_exit);
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.6-pre1/drivers/input/joystick/tmdc.c linux-2.5.6-pre2/drivers/input/joystick/tmdc.c
--- linux-2.5.6-pre1/drivers/input/joystick/tmdc.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/tmdc.c	Thu Feb 28 13:34:21 2002
@@ -1,13 +1,10 @@
 /*
- * $Id: tmdc.c,v 1.23 2000/11/29 19:52:24 vojtech Exp $
+ * $Id: tmdc.c,v 1.31 2002/01/22 20:29:52 vojtech Exp $
  *
- *  Copyright (c) 1998-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
+ *  Copyright (c) 1998-2001 Vojtech Pavlik
  *
  *   Based on the work of:
  *	Trystan Larey-Williams 
- *
  */
 
 /*
@@ -30,8 +27,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/delay.h>
@@ -42,6 +39,10 @@
 #include <linux/gameport.h>
 #include <linux/input.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("ThrustMaster DirectConnect joystick driver");
+MODULE_LICENSE("GPL");
+
 #define TMDC_MAX_START		400	/* 400 us */
 #define TMDC_MAX_STROBE		45	/* 45 us */
 #define TMDC_MAX_LENGTH		13
@@ -94,6 +95,7 @@
 	struct timer_list timer;
 	struct input_dev dev[2];
 	char name[2][64];
+	char phys[2][32];
 	int mode[2];
 	signed char *abs[2];
 	short *btn[2];
@@ -172,6 +174,7 @@
 
 	if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists)
 		bad = 1;
+	else
 
 	for (j = 0; j < 2; j++) 
 		if (r & (1 << j) & tmdc->exists) {
@@ -302,11 +305,14 @@
 			sprintf(tmdc->name[j], models[m].name, models[m].abs,
 				(data[j][TMDC_BYTE_DEF] & 0xf) << 3, tmdc->mode[j]);
 
+			sprintf(tmdc->phys[j], "%s/input%d", gameport->phys, j);
+
 			tmdc->dev[j].private = tmdc;
 			tmdc->dev[j].open = tmdc_open;
 			tmdc->dev[j].close = tmdc_close;
 
 			tmdc->dev[j].name = tmdc->name[j];
+			tmdc->dev[j].phys = tmdc->phys[j];
 			tmdc->dev[j].idbus = BUS_GAMEPORT;
 			tmdc->dev[j].idvendor = GAMEPORT_ID_VENDOR_THRUSTMASTER;
 			tmdc->dev[j].idproduct = models[m].id;
@@ -336,8 +342,7 @@
 			}
 
 			input_register_device(tmdc->dev + j);
-			printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
-				tmdc->dev[j].number, tmdc->name[j], gameport->number, j);
+			printk(KERN_INFO "input: %s on %s\n", tmdc->name[j], gameport->phys);
 		}
 
 	return;
@@ -374,5 +379,3 @@
 
 module_init(tmdc_init);
 module_exit(tmdc_exit);
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.6-pre1/drivers/input/joystick/turbografx.c linux-2.5.6-pre2/drivers/input/joystick/turbografx.c
--- linux-2.5.6-pre1/drivers/input/joystick/turbografx.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/turbografx.c	Thu Feb 28 13:34:21 2002
@@ -1,12 +1,10 @@
 /*
- * $Id: turbografx.c,v 1.8 2000/05/29 20:39:38 vojtech Exp $
+ * $Id: turbografx.c,v 1.14 2002/01/22 20:30:39 vojtech Exp $
  *
- *  Copyright (c) 1998-2000 Vojtech Pavlik
+ *  Copyright (c) 1998-2001 Vojtech Pavlik
  *
  *  Based on the work of:
  *	Steffen Schwenke
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -29,8 +27,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -39,8 +37,10 @@
 #include <linux/module.h>
 #include <linux/init.h>
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("TurboGraFX parallel port interface driver");
 MODULE_LICENSE("GPL");
+
 MODULE_PARM(tgfx, "2-8i");
 MODULE_PARM(tgfx_2, "2-8i");
 MODULE_PARM(tgfx_3, "2-8i");
@@ -69,6 +69,7 @@
 	struct pardevice *pd;
 	struct timer_list timer;
 	struct input_dev dev[7];
+	char phys[7][32];
 	int sticks;
 	int used;
 } *tgfx_base[3];
@@ -174,7 +175,10 @@
 			tgfx->dev[i].open = tgfx_open;
 			tgfx->dev[i].close = tgfx_close;
 
+			sprintf(tgfx->phys[i], "%s/input0", tgfx->pd->port->name);
+
 			tgfx->dev[i].name = tgfx_name;
+			tgfx->dev[i].phys = tgfx->phys[i];
 			tgfx->dev[i].idbus = BUS_PARPORT;
 			tgfx->dev[i].idvendor = 0x0003;
 			tgfx->dev[i].idproduct = config[i+1];
@@ -190,8 +194,8 @@
 			tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1;
 
 			input_register_device(tgfx->dev + i);
-			printk(KERN_INFO "input%d: %d-button Multisystem joystick on %s\n",
-				tgfx->dev[i].number, config[i+1], tgfx->pd->port->name);
+			printk(KERN_INFO "input: %d-button Multisystem joystick on %s\n",
+				config[i+1], tgfx->pd->port->name);
 		}
 
         if (!tgfx->sticks) {
diff -urN linux-2.5.6-pre1/drivers/input/joystick/warrior.c linux-2.5.6-pre2/drivers/input/joystick/warrior.c
--- linux-2.5.6-pre1/drivers/input/joystick/warrior.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/input/joystick/warrior.c	Thu Feb 28 13:34:21 2002
@@ -1,9 +1,7 @@
 /*
- * $Id: warrior.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $
+ * $Id: warrior.c,v 1.14 2002/01/22 20:32:10 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  */
 
 /*
@@ -27,7 +25,7 @@
  * 
  *  Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/kernel.h>
@@ -37,6 +35,10 @@
 #include <linux/serio.h>
 #include <linux/init.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Logitech WingMan Warrior joystick driver");
+MODULE_LICENSE("GPL");
+
 /*
  * Constants.
  */
@@ -53,6 +55,7 @@
 	struct input_dev dev;
 	int idx, len;
 	unsigned char data[WARRIOR_MAX_LENGTH];
+	char phys[32];
 };
 
 /*
@@ -149,7 +152,10 @@
 	warrior->dev.relbit[0] = BIT(REL_DIAL);
 	warrior->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y);
 
+	sprintf(warrior->phys, "%s/input0", serio->phys);
+
 	warrior->dev.name = warrior_name;
+	warrior->dev.phys = warrior->phys;
 	warrior->dev.idbus = BUS_RS232;
 	warrior->dev.idvendor = SERIO_WARRIOR;
 	warrior->dev.idproduct = 0x0001;
@@ -180,7 +186,7 @@
 
 	input_register_device(&warrior->dev);
 
-	printk(KERN_INFO "input%d: Logitech WingMan Warrior on serio%d\n", warrior->dev.number, serio->number);
+	printk(KERN_INFO "input: Logitech WingMan Warrior on %s\n", serio->phys);
 }
 
 /*
@@ -210,5 +216,3 @@
 
 module_init(warrior_init);
 module_exit(warrior_exit);
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.6-pre1/drivers/input/serio/serio.c linux-2.5.6-pre2/drivers/input/serio/serio.c
--- linux-2.5.6-pre1/drivers/input/serio/serio.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/drivers/input/serio/serio.c	Thu Feb 28 13:34:21 2002
@@ -1,9 +1,7 @@
 /*
- * $Id: serio.c,v 1.5 2000/06/04 17:44:59 vojtech Exp $
+ * $Id: serio.c,v 1.15 2002/01/22 21:12:03 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
- *
- *  Sponsored by SuSE
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  */
 
 /*
@@ -27,14 +25,16 @@
  * 
  * Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/stddef.h>
 #include <linux/module.h>
 #include <linux/serio.h>
+#include <linux/errno.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Serio abstraction core");
 MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(serio_register_port);
@@ -47,7 +47,6 @@
 
 static struct serio *serio_list;
 static struct serio_dev *serio_dev;
-static int serio_number;
 
 static void serio_find_dev(struct serio *serio)
 {
@@ -69,7 +68,6 @@
 
 void serio_register_port(struct serio *serio)
 {
-	serio->number = serio_number++;
 	serio->next = serio_list;	
 	serio_list = serio;
 	serio_find_dev(serio);
@@ -84,8 +82,6 @@
 
 	if (serio->dev && serio->dev->disconnect)
 		serio->dev->disconnect(serio);
-
-	serio_number--;
 }
 
 void serio_register_device(struct serio_dev *dev)
diff -urN linux-2.5.6-pre1/drivers/input/serio/serport.c linux-2.5.6-pre2/drivers/input/serio/serport.c
--- linux-2.5.6-pre1/drivers/input/serio/serport.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/input/serio/serport.c	Thu Feb 28 13:34:21 2002
@@ -1,9 +1,7 @@
 /*
- * $Id: serport.c,v 1.7 2001/05/25 19:00:27 jdeneux Exp $
+ * $Id: serport_old.c,v 1.10 2002/01/24 19:52:57 vojtech Exp $
  *
  *  Copyright (c) 1999-2001 Vojtech Pavlik
- *
- *  Sponsored by SuSE
  */
 
 /*
@@ -28,7 +26,7 @@
  * 
  *  Should you need to contact me, the author, you can do so either by
  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
 #include <asm/uaccess.h>
@@ -39,12 +37,19 @@
 #include <linux/serio.h>
 #include <linux/tty.h>
 
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Input device TTY line discipline");
+MODULE_LICENSE("GPL");
+
 struct serport {
 	struct tty_struct *tty;
 	wait_queue_head_t wait;
 	struct serio serio;
+	char phys[32];
 };
 
+char serport_name[] = "Serial port";
+
 /*
  * Callback functions from the serio code.
  */
@@ -75,6 +80,8 @@
 static int serport_ldisc_open(struct tty_struct *tty)
 {
 	struct serport *serport;
+	char ttyname[64];
+	int i;
 
 	MOD_INC_USE_COUNT;
 
@@ -85,9 +92,19 @@
 
 	memset(serport, 0, sizeof(struct serport));
 
+	set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 	serport->tty = tty;
 	tty->disc_data = serport;
 
+	strcpy(ttyname, tty->driver.name);
+	for (i = 0; ttyname[i] != 0 && ttyname[i] != '/'; i++);
+	ttyname[i] = 0;
+
+	sprintf(serport->phys, "%s%d/serio0", ttyname, minor(tty->device) - tty->driver.minor_start);
+
+	serport->serio.name = serport_name;
+	serport->serio.phys = serport->phys;
+
 	serport->serio.type = SERIO_RS232;
 	serport->serio.write = serport_serio_write;
 	serport->serio.open = serport_serio_open;
@@ -156,14 +173,14 @@
 
 	serio_register_port(&serport->serio);
 
-	printk(KERN_INFO "serio%d: Serial port %s\n", serport->serio.number, name);
+	printk(KERN_INFO "serio: Serial port %s\n", name);
 
 	add_wait_queue(&serport->wait, &wait);
-	current->state = TASK_INTERRUPTIBLE;
+	set_current_state(TASK_INTERRUPTIBLE);
 
 	while(serport->serio.type && !signal_pending(current)) schedule();
 
-	current->state = TASK_RUNNING;
+	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&serport->wait, &wait);
 
 	serio_unregister_port(&serport->serio);
@@ -187,6 +204,14 @@
 	return -EINVAL;
 }
 
+static void serport_ldisc_write_wakeup(struct tty_struct * tty)
+{
+	struct serport *sp = (struct serport *) tty->disc_data;
+
+	serio_dev_write_wakeup(&sp->serio);
+
+}
+
 /*
  * The line discipline structure.
  */
@@ -199,6 +224,7 @@
 	ioctl:		serport_ldisc_ioctl,
 	receive_buf:	serport_ldisc_receive,
 	receive_room:	serport_ldisc_room,
+	write_wakeup:	serport_ldisc_write_wakeup
 };
 
 /*
@@ -222,5 +248,3 @@
 
 module_init(serport_init);
 module_exit(serport_exit);
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.6-pre1/drivers/macintosh/via-pmu.c linux-2.5.6-pre2/drivers/macintosh/via-pmu.c
--- linux-2.5.6-pre1/drivers/macintosh/via-pmu.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/macintosh/via-pmu.c	Thu Feb 28 13:34:21 2002
@@ -1434,7 +1434,7 @@
 	 * BenH: Moved to _after_ sleep request and changed video
 	 * drivers to vmalloc() during sleep request. This way, all
 	 * vmalloc's are done before actual sleep of block drivers */
-	fsync_dev(0);
+	sys_sync();
 
 	/* Sleep can fail now. May not be very robust but useful for debugging */
 	ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
@@ -1589,7 +1589,7 @@
 	 * BenH: Moved to _after_ sleep request and changed video
 	 * drivers to vmalloc() during sleep request. This way, all
 	 * vmalloc's are done before actual sleep of block drivers */
-	fsync_dev(0);
+	sys_sync();
 
 	/* Sleep can fail now. May not be very robust but useful for debugging */
 	ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
@@ -1764,7 +1764,7 @@
 	 * BenH: Moved to _after_ sleep request and changed video
 	 * drivers to vmalloc() during sleep request. This way, all
 	 * vmalloc's are done before actual sleep of block drivers */
-	fsync_dev(0);
+	sys_sync();
 
 	/* Sleep can fail now. May not be very robust but useful for debugging */
 	ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
diff -urN linux-2.5.6-pre1/drivers/macintosh/via-pmu68k.c linux-2.5.6-pre2/drivers/macintosh/via-pmu68k.c
--- linux-2.5.6-pre1/drivers/macintosh/via-pmu68k.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/drivers/macintosh/via-pmu68k.c	Thu Feb 28 13:34:21 2002
@@ -916,7 +916,7 @@
 	/* Sync the disks. */
 	/* XXX It would be nice to have some way to ensure that
 	 * nobody is dirtying any new buffers while we wait. */
-	fsync_dev(0);
+	sys_sync();
 
 	/* Turn off the display backlight */
 	save_backlight = backlight_enabled;
diff -urN linux-2.5.6-pre1/drivers/md/lvm.c linux-2.5.6-pre2/drivers/md/lvm.c
--- linux-2.5.6-pre1/drivers/md/lvm.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/drivers/md/lvm.c	Thu Feb 28 13:34:21 2002
@@ -878,7 +878,7 @@
 
 		P_IOCTL("BLKFLSBUF\n");
 
-		fsync_dev(inode->i_rdev);
+		fsync_bdev(inode->i_bdev);
 		invalidate_buffers(inode->i_rdev);
 		break;
 
diff -urN linux-2.5.6-pre1/drivers/md/md.c linux-2.5.6-pre2/drivers/md/md.c
--- linux-2.5.6-pre1/drivers/md/md.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/drivers/md/md.c	Thu Feb 28 13:34:21 2002
@@ -890,7 +890,8 @@
 
 static int write_disk_sb(mdk_rdev_t * rdev)
 {
-	struct address_space *mapping = rdev->bdev->bd_inode->i_mapping;
+	struct block_device *bdev = rdev->bdev;
+	struct address_space *mapping = bdev->bd_inode->i_mapping;
 	struct page *page;
 	unsigned offs;
 	int error;
@@ -929,7 +930,7 @@
 	}
 
 	printk(KERN_INFO "(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset);
-	fsync_dev(dev);
+	fsync_bdev(bdev);
 	page = grab_cache_page(mapping, sb_offset/(PAGE_CACHE_SIZE/BLOCK_SIZE));
 	offs = sb_offset % (PAGE_CACHE_SIZE/BLOCK_SIZE);
 	if (!page)
@@ -946,7 +947,7 @@
 	UnlockPage(page);
 	wait_on_page(page);
 	page_cache_release(page);
-	fsync_dev(dev);
+	fsync_bdev(bdev);
 skip:
 	return 0;
 unlock:
diff -urN linux-2.5.6-pre1/drivers/message/i2o/i2o_block.c linux-2.5.6-pre2/drivers/message/i2o/i2o_block.c
--- linux-2.5.6-pre1/drivers/message/i2o/i2o_block.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/drivers/message/i2o/i2o_block.c	Thu Feb 28 13:34:21 2002
@@ -1137,9 +1137,6 @@
 	if(!dev->i2odev)
 		return 0;
 
-	/* Sync the device so we don't get errors */
-	fsync_dev(inode->i_rdev);
-
 	if (dev->refcnt <= 0)
 		printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt);
 	dev->refcnt--;
diff -urN linux-2.5.6-pre1/drivers/mtd/devices/blkmtd.c linux-2.5.6-pre2/drivers/mtd/devices/blkmtd.c
--- linux-2.5.6-pre1/drivers/mtd/devices/blkmtd.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/drivers/mtd/devices/blkmtd.c	Thu Feb 28 13:34:21 2002
@@ -1,10 +1,11 @@
 /* 
- * $Id: blkmtd.c,v 1.3 2001/10/02 15:33:20 dwmw2 Exp $
+ * $Id: blkmtd.c,v 1.7 2001/11/10 17:06:30 spse Exp $
+ *
  * blkmtd.c - use a block device as a fake MTD
  *
  * Author: Simon Evans <spse@secret.org.uk>
  *
- * Copyright (C) 2001 Simon Evans <spse@secret.org.uk>
+ * Copyright (C) 2001 Simon Evans
  * 
  * Licence: GPL
  *
@@ -13,7 +14,7 @@
  *       cache to cache access. Writes update the page cache with the
  *       new data but make a copy of the new page(s) and then a kernel
  *       thread writes pages out to the device in the background. This
- *       ensures tht writes are order even if a page is updated twice.
+ *       ensures that writes are order even if a page is updated twice.
  *       Also, since pages in the page cache are never marked as dirty,
  *       we dont have to worry about writepage() being called on some 
  *       random page which may not be in the write order.
@@ -30,7 +31,7 @@
  *       small memory systems and too small on large memory systems.
  * 
  *       Page cache usage may still be a bit wrong. Check we are doing
- *       everything proberly.
+ *       everything properly.
  * 
  *       Somehow allow writes to dirty the page cache so we dont use too
  *       much memory making copies of outgoing pages. Need to handle case
@@ -39,19 +40,14 @@
  * 
  *       Reading should read multiple pages at once rather than using 
  *       readpage() for each one. This is easy and will be fixed asap.
- *
- *       Dont run the write_thread if readonly. This is also easy and will
- *       be fixed asap.
- * 
- *       Even though the multiple erase regions are used if the default erase
- *       block size doesnt match the device properly, erases currently wont
- *       work on the last page if it is not a full page.
  */
 
+
 #include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/fs.h>
+#include <linux/blkdev.h>
 #include <linux/pagemap.h>
 #include <linux/iobuf.h>
 #include <linux/slab.h>
@@ -59,19 +55,30 @@
 #include <linux/mtd/compatmac.h>
 #include <linux/mtd/mtd.h>
 
+#ifdef CONFIG_MTD_DEBUG
+#ifdef CONFIG_PROC_FS
+#  include <linux/proc_fs.h>
+#  define BLKMTD_PROC_DEBUG
+   static struct proc_dir_entry *blkmtd_proc;
+#endif
+#endif
+
+
 /* Default erase size in K, always make it a multiple of PAGE_SIZE */
 #define CONFIG_MTD_BLKDEV_ERASESIZE 128
-#define VERSION "1.1"
+#define VERSION "1.7"
 extern int *blk_size[];
 
 /* Info for the block device */
 typedef struct mtd_raw_dev_data_s {
   struct block_device *binding;
-  int sector_size, sector_bits, total_sectors;
+  int sector_size, sector_bits;
+  int partial_last_page;   // 0 if device ends on page boundary, else page no of last page
+  int last_page_sectors;   // Number of sectors in last page if partial_last_page != 0
   size_t totalsize;
   int readonly;
   struct address_space as;
-  struct file *file;
+  struct mtd_info mtd_info;
 } mtd_raw_dev_data_t;
 
 /* Info for each queue item in the write queue */
@@ -84,24 +91,28 @@
 } mtdblkdev_write_queue_t;
 
 
+/* Our erase page - always remains locked. */
+static struct page *erase_page;
+
 /* Static info about the MTD, used in cleanup_module */
-static struct mtd_info *mtd_info;
+static mtd_raw_dev_data_t *mtd_rawdevice;
 
 /* Write queue fixed size */
 #define WRITE_QUEUE_SZ 512
 
 /* Storage for the write queue */
-static mtdblkdev_write_queue_t write_queue[WRITE_QUEUE_SZ];
+static mtdblkdev_write_queue_t *write_queue;
+static int write_queue_sz = WRITE_QUEUE_SZ;
 static int volatile write_queue_head;
 static int volatile write_queue_tail;
 static int volatile write_queue_cnt;
 static spinlock_t mbd_writeq_lock = SPIN_LOCK_UNLOCKED;
 
 /* Tell the write thread to finish */
-static volatile int write_task_finish = 0;
+static volatile int write_task_finish;
 
 /* ipc with the write thread */
-#if LINUX_VERSION_CODE > 0x020300
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
 static DECLARE_MUTEX_LOCKED(thread_sem);
 static DECLARE_WAIT_QUEUE_HEAD(thr_wq);
 static DECLARE_WAIT_QUEUE_HEAD(mtbd_sync_wq);
@@ -112,13 +123,14 @@
 #endif
 
 
-
 /* Module parameters passed by insmod/modprobe */
 char *device;    /* the block device to use */
 int erasesz;     /* optional default erase size */
 int ro;          /* optional read only flag */
 int bs;          /* optionally force the block size (avoid using) */
 int count;       /* optionally force the block count (avoid using) */
+int wqs;         /* optionally set the write queue size */
+
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
 MODULE_LICENSE("GPL");
@@ -134,10 +146,10 @@
 MODULE_PARM_DESC(bs, "force the block size in bytes");
 MODULE_PARM(count, "i");
 MODULE_PARM_DESC(count, "force the block count");
+MODULE_PARM(wqs, "i");
 #endif
 
 
-
 /* Page cache stuff */
 
 /* writepage() - should never be called - catch it anyway */
@@ -149,13 +161,13 @@
 
 
 /* readpage() - reads one page from the block device */                 
-static int blkmtd_readpage(struct file *file, struct page *page)
+static int blkmtd_readpage(mtd_raw_dev_data_t *rawdevice, struct page *page)
 {  
   int err;
   int sectornr, sectors, i;
   struct kiobuf *iobuf;
-  mtd_raw_dev_data_t *rawdevice = (mtd_raw_dev_data_t *)file->private_data;
   kdev_t dev;
+  unsigned long *blocks;
 
   if(!rawdevice) {
     printk("blkmtd: readpage: PANIC file->private_data == NULL\n");
@@ -167,7 +179,7 @@
 	bdevname(dev), page, page->index);
 
   if(Page_Uptodate(page)) {
-    DEBUG(1, "blkmtd: readpage page %ld is already upto date\n", page->index);
+    DEBUG(2, "blkmtd: readpage page %ld is already upto date\n", page->index);
     UnlockPage(page);
     return 0;
   }
@@ -183,8 +195,9 @@
       mtdblkdev_write_queue_t *item = &write_queue[i];
       if(page->index >= item->pagenr && page->index < item->pagenr+item->pagecnt) {
 	/* yes it is */
-	int index = item->pagenr - page->index;
-	DEBUG(1, "blkmtd: readpage: found page %ld in outgoing write queue\n",
+	int index = page->index - item->pagenr;
+		
+	DEBUG(2, "blkmtd: readpage: found page %ld in outgoing write queue\n",
 	      page->index);
 	if(item->iserase) {
 	  memset(page_address(page), 0xff, PAGE_SIZE);
@@ -198,7 +211,7 @@
 	return 0;
       }
       i++;
-      i %= WRITE_QUEUE_SZ;
+      i %= write_queue_sz;
     }
   }
   spin_unlock(&mbd_writeq_lock);
@@ -207,8 +220,24 @@
   DEBUG(3, "blkmtd: readpage: getting kiovec\n");
   err = alloc_kiovec(1, &iobuf);
   if (err) {
+    printk("blkmtd: cant allocate kiobuf\n");
+    SetPageError(page);
     return err;
   }
+
+  /* Pre 2.4.4 doesnt have space for the block list in the kiobuf */ 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+  blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long));
+  if(blocks == NULL) {
+    printk("blkmtd: cant allocate iobuf blocks\n");
+    free_kiovec(1, &iobuf);
+    SetPageError(page);
+    return -ENOMEM;
+  }
+#else 
+  blocks = iobuf->blocks;
+#endif
+
   iobuf->offset = 0;
   iobuf->nr_pages = 1;
   iobuf->length = PAGE_SIZE;
@@ -216,16 +245,34 @@
   iobuf->maplist[0] = page;
   sectornr = page->index << (PAGE_SHIFT - rawdevice->sector_bits);
   sectors = 1 << (PAGE_SHIFT - rawdevice->sector_bits);
+  if(rawdevice->partial_last_page && page->index == rawdevice->partial_last_page) {
+    DEBUG(3, "blkmtd: handling partial last page\n");
+    sectors = rawdevice->last_page_sectors;
+  }
   DEBUG(3, "blkmtd: readpage: sectornr = %d sectors = %d\n", sectornr, sectors);
   for(i = 0; i < sectors; i++) {
-    iobuf->blocks[i] = sectornr++;
+    blocks[i] = sectornr++;
   }
+  /* If only a partial page read in, clear the rest of the page */
+  if(rawdevice->partial_last_page && page->index == rawdevice->partial_last_page) {
+    int offset = rawdevice->last_page_sectors << rawdevice->sector_bits;
+    int count = PAGE_SIZE-offset;
+    DEBUG(3, "blkmtd: clear last partial page: offset = %d count = %d\n", offset, count);
+    memset(page_address(page)+offset, 0, count);
+    sectors = rawdevice->last_page_sectors;
+  }
+
 
   DEBUG(3, "bklmtd: readpage: starting brw_kiovec\n");
-  err = brw_kiovec(READ, 1, &iobuf, dev, iobuf->blocks, rawdevice->sector_size);
+  err = brw_kiovec(READ, 1, &iobuf, dev, blocks, rawdevice->sector_size);
   DEBUG(3, "blkmtd: readpage: finished, err = %d\n", err);
   iobuf->locked = 0;
   free_kiovec(1, &iobuf);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+  kfree(blocks);
+#endif
+
   if(err != PAGE_SIZE) {
     printk("blkmtd: readpage: error reading page %ld\n", page->index);
     memset(page_address(page), 0, PAGE_SIZE);
@@ -245,7 +292,7 @@
                     
 static struct address_space_operations blkmtd_aops = {
   writepage:     blkmtd_writepage,
-  readpage:      blkmtd_readpage,
+  readpage:      NULL,
 }; 
 
 
@@ -255,6 +302,7 @@
   int err;
   struct task_struct *tsk = current;
   struct kiobuf *iobuf;
+  unsigned long *blocks;
 
   DECLARE_WAITQUEUE(wait, tsk);
   DEBUG(1, "blkmtd: writetask: starting (pid = %d)\n", tsk->pid);
@@ -266,8 +314,23 @@
   recalc_sigpending();
   spin_unlock_irq(&tsk->sigmask_lock);
 
-  if(alloc_kiovec(1, &iobuf))
+  if(alloc_kiovec(1, &iobuf)) {
+    printk("blkmtd: write_queue_task cant allocate kiobuf\n");
     return 0;
+  }
+
+  /* Pre 2.4.4 doesnt have space for the block list in the kiobuf */ 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+  blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long));
+  if(blocks == NULL) {
+    printk("blkmtd: write_queue_task cant allocate iobuf blocks\n");
+    free_kiovec(1, &iobuf);
+    return 0;
+  }
+#else 
+  blocks = iobuf->blocks;
+#endif
+
   DEBUG(2, "blkmtd: writetask: entering main loop\n");
   add_wait_queue(&thr_wq, &wait);
 
@@ -278,30 +341,39 @@
       /* If nothing in the queue, wake up anyone wanting to know when there
 	 is space in the queue then sleep for 2*HZ */
       spin_unlock(&mbd_writeq_lock);
-      DEBUG(3, "blkmtd: writetask: queue empty\n");
+      DEBUG(4, "blkmtd: writetask: queue empty\n");
       if(waitqueue_active(&mtbd_sync_wq))
 	 wake_up(&mtbd_sync_wq);
       interruptible_sleep_on_timeout(&thr_wq, 2*HZ);
-      DEBUG(3, "blkmtd: writetask: woken up\n");
+      DEBUG(4, "blkmtd: writetask: woken up\n");
       if(write_task_finish)
 	break;
     } else {
       /* we have stuff to write */
       mtdblkdev_write_queue_t *item = &write_queue[write_queue_tail];
       struct page **pages = item->pages;
-      int pagecnt = item->pagecnt;
-      int pagenr = item->pagenr;
+
       int i;
+      int sectornr = item->pagenr << (PAGE_SHIFT - item->rawdevice->sector_bits);
+      int sectorcnt = item->pagecnt << (PAGE_SHIFT - item->rawdevice->sector_bits);
       int max_sectors = KIO_MAX_SECTORS >> (item->rawdevice->sector_bits - 9);
       kdev_t dev = to_kdev_t(item->rawdevice->binding->bd_dev);
-  
+
+      /* If we are writing to the last page on the device and it doesnt end
+       * on a page boundary, subtract the number of sectors that dont exist.
+       */
+      if(item->rawdevice->partial_last_page && 
+	 (item->pagenr + item->pagecnt -1) == item->rawdevice->partial_last_page) {
+	sectorcnt -= (1 << (PAGE_SHIFT - item->rawdevice->sector_bits));
+	sectorcnt += item->rawdevice->last_page_sectors;
+      }
 
       DEBUG(3, "blkmtd: writetask: got %d queue items\n", write_queue_cnt);
       set_current_state(TASK_RUNNING);
       spin_unlock(&mbd_writeq_lock);
 
-      DEBUG(2, "blkmtd: write_task: writing pagenr = %d pagecnt = %d", 
-	    item->pagenr, item->pagecnt);
+      DEBUG(2, "blkmtd: writetask: writing pagenr = %d pagecnt = %d sectornr = %d sectorcnt = %d\n", 
+	    item->pagenr, item->pagecnt, sectornr, sectorcnt);
 
       iobuf->offset = 0;
       iobuf->locked = 1;
@@ -309,31 +381,33 @@
       /* Loop through all the pages to be written in the queue item, remembering
 	 we can only write KIO_MAX_SECTORS at a time */
 	 
-      while(pagecnt) {
-	int sectornr = pagenr << (PAGE_SHIFT - item->rawdevice->sector_bits);
-	int sectorcnt = pagecnt << (PAGE_SHIFT - item->rawdevice->sector_bits);
+      while(sectorcnt) {
 	int cursectors = (sectorcnt < max_sectors) ? sectorcnt : max_sectors;
 	int cpagecnt = (cursectors << item->rawdevice->sector_bits) + PAGE_SIZE-1;
 	cpagecnt >>= PAGE_SHIFT;
 	
-	for(i = 0; i < cpagecnt; i++) 
+	for(i = 0; i < cpagecnt; i++) {
+	  if(item->iserase) {
+	    iobuf->maplist[i] = erase_page;
+	  } else {
 	    iobuf->maplist[i] = *(pages++);
+	  }
+	}
 	
 	for(i = 0; i < cursectors; i++) {
-	  iobuf->blocks[i] = sectornr++;
+	  blocks[i] = sectornr++;
 	}
 	
 	iobuf->nr_pages = cpagecnt;
 	iobuf->length = cursectors << item->rawdevice->sector_bits;
 	DEBUG(3, "blkmtd: write_task: about to kiovec\n");
-	err = brw_kiovec(WRITE, 1, &iobuf, dev, iobuf->blocks, item->rawdevice->sector_size);
+	err = brw_kiovec(WRITE, 1, &iobuf, dev, blocks, item->rawdevice->sector_size);
 	DEBUG(3, "bklmtd: write_task: done, err = %d\n", err);
 	if(err != (cursectors << item->rawdevice->sector_bits)) {
 	  /* if an error occured - set this to exit the loop */
-	  pagecnt = 0;
+	  sectorcnt = 0;
 	} else {
-	  pagenr += cpagecnt;
-	  pagecnt -= cpagecnt;
+	  sectorcnt -= cursectors;
 	}
       }
 
@@ -343,12 +417,14 @@
       spin_lock(&mbd_writeq_lock);
       write_queue_cnt--;
       write_queue_tail++;
-      write_queue_tail %= WRITE_QUEUE_SZ;
-      for(i = 0 ; i < item->pagecnt; i++) {
-	UnlockPage(item->pages[i]);
-	__free_pages(item->pages[i], 0);
+      write_queue_tail %= write_queue_sz;
+      if(!item->iserase) {
+	for(i = 0 ; i < item->pagecnt; i++) {
+	  UnlockPage(item->pages[i]);
+	  __free_pages(item->pages[i], 0);
+	}
+	kfree(item->pages);
       }
-      kfree(item->pages);
       item->pages = NULL;
       spin_unlock(&mbd_writeq_lock);
       /* Tell others there is some space in the write queue */
@@ -359,6 +435,11 @@
   remove_wait_queue(&thr_wq, &wait);
   DEBUG(1, "blkmtd: writetask: exiting\n");
   free_kiovec(1, &iobuf);
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+  kfree(blocks);
+#endif
+
   /* Tell people we have exitd */
   up(&thread_sem);
   return 0;
@@ -370,43 +451,45 @@
 			    int pagenr, int pagecnt, int iserase)
 {
   struct page *outpage;
-  struct page **new_pages;
+  struct page **new_pages = NULL;
   mtdblkdev_write_queue_t *item;
   int i;
   DECLARE_WAITQUEUE(wait, current);
-  DEBUG(2, "mtdblkdev: queue_page_write: adding pagenr = %d pagecnt = %d\n", pagenr, pagecnt);
+  DEBUG(2, "blkmtd: queue_page_write: adding pagenr = %d pagecnt = %d\n", pagenr, pagecnt);
 
   if(!pagecnt)
     return 0;
 
-  if(pages == NULL)
+  if(pages == NULL && !iserase)
     return -EINVAL;
 
   /* create a array for the list of pages */
-  new_pages = kmalloc(pagecnt * sizeof(struct page *), GFP_KERNEL);
-  if(new_pages == NULL)
-    return -ENOMEM;
+  if(!iserase) {
+    new_pages = kmalloc(pagecnt * sizeof(struct page *), GFP_KERNEL);
+    if(new_pages == NULL)
+      return -ENOMEM;
 
-  /* make copies of the pages in the page cache */
-  for(i = 0; i < pagecnt; i++) {
-    outpage = alloc_pages(GFP_KERNEL, 0);
-    if(!outpage) {
-      while(i--) {
-	UnlockPage(new_pages[i]);
-	__free_pages(new_pages[i], 0);
+    /* make copies of the pages in the page cache */
+    for(i = 0; i < pagecnt; i++) {
+      outpage = alloc_pages(GFP_KERNEL, 0);
+      if(!outpage) {
+	while(i--) {
+	  UnlockPage(new_pages[i]);
+	  __free_pages(new_pages[i], 0);
+	}
+	kfree(new_pages);
+	return -ENOMEM;
       }
-      kfree(new_pages);
-      return -ENOMEM;
+      lock_page(outpage);
+      memcpy(page_address(outpage), page_address(pages[i]), PAGE_SIZE);
+      new_pages[i] = outpage;
     }
-    lock_page(outpage);
-    memcpy(page_address(outpage), page_address(pages[i]), PAGE_SIZE);
-    new_pages[i] = outpage;
   }
 
   /* wait until there is some space in the write queue */
  test_lock:
   spin_lock(&mbd_writeq_lock);
-  if(write_queue_cnt == WRITE_QUEUE_SZ) {
+  if(write_queue_cnt == write_queue_sz) {
     spin_unlock(&mbd_writeq_lock);
     DEBUG(3, "blkmtd: queue_page: Queue full\n");
     current->state = TASK_UNINTERRUPTIBLE;
@@ -415,11 +498,11 @@
     schedule();
     current->state = TASK_RUNNING;
     remove_wait_queue(&mtbd_sync_wq, &wait);
-    DEBUG(3, "blkmtd: queue_page: Queue has %d items in it\n", write_queue_cnt);
+    DEBUG(3, "blkmtd: queue_page_write: Queue has %d items in it\n", write_queue_cnt);
     goto test_lock;
   }
 
-  DEBUG(3, "blkmtd: queue_write_page: qhead: %d qtail: %d qcnt: %d\n", 
+  DEBUG(3, "blkmtd: queue_page_write: qhead: %d qtail: %d qcnt: %d\n", 
 	write_queue_head, write_queue_tail, write_queue_cnt);
 
   /* fix up the queue item */
@@ -431,9 +514,9 @@
   item->iserase = iserase;
 
   write_queue_head++;
-  write_queue_head %= WRITE_QUEUE_SZ;
+  write_queue_head %= write_queue_sz;
   write_queue_cnt++;
-  DEBUG(3, "blkmtd: queue_write_page: qhead: %d qtail: %d qcnt: %d\n", 
+  DEBUG(3, "blkmtd: queue_page_write: qhead: %d qtail: %d qcnt: %d\n", 
 	write_queue_head, write_queue_tail, write_queue_cnt);
   spin_unlock(&mbd_writeq_lock);
   DEBUG(2, "blkmtd: queue_page_write: finished\n");
@@ -445,6 +528,8 @@
 static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
   mtd_raw_dev_data_t *rawdevice = mtd->priv;
+  struct mtd_erase_region_info *einfo = mtd->eraseregions;
+  int numregions = mtd->numeraseregions;
   size_t from;
   u_long len;
   int err = 0;
@@ -460,17 +545,23 @@
   from = instr->addr;
   len = instr->len;
 
-  /* check page alignment of start and length */
-  DEBUG(2, "blkmtd: erase: dev = `%s' from = %d len = %ld\n",
+  /* check erase region has valid start and length */
+  DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%x len = 0x%lx\n",
 	bdevname(rawdevice->binding->bd_dev), from, len);
-  if(from % PAGE_SIZE) {
-    printk("blkmtd: erase: addr not page aligned (addr = %d)\n", from);
-    instr->state = MTD_ERASE_FAILED;
-    err = -EIO;
+  while(numregions) {
+    DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n",
+	  einfo->offset, einfo->erasesize, einfo->numblocks);
+    if(from >= einfo->offset && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
+      if(len == einfo->erasesize && ( (from - einfo->offset) % einfo->erasesize == 0))
+	break;
+    }
+    numregions--;
+    einfo++;
   }
 
-  if(len % PAGE_SIZE) {
-    printk("blkmtd: erase: len not a whole number of pages (len = %ld)\n", len);
+  if(!numregions) {
+    /* Not a valid erase block */
+    printk("blkmtd: erase: invalid erase request 0x%lX @ 0x%08X\n", len, from);
     instr->state = MTD_ERASE_FAILED;
     err = -EIO;
   }
@@ -481,9 +572,14 @@
     struct page *page, **pages;
     int i = 0;
 
+    /* Handle the last page of the device not being whole */
+    if(len < PAGE_SIZE)
+      len = PAGE_SIZE;
+
     pagenr = from >> PAGE_SHIFT;
     pagecnt = len >> PAGE_SHIFT;
     DEBUG(3, "blkmtd: erase: pagenr = %d pagecnt = %d\n", pagenr, pagecnt);
+
     pages = kmalloc(pagecnt * sizeof(struct page *), GFP_KERNEL);
     if(pages == NULL) {
       err = -ENOMEM;
@@ -491,9 +587,10 @@
       goto erase_out;
     }
 
+
     while(pagecnt) {
       /* get the page via the page cache */
-      DEBUG(3, "blkmtd: erase: doing grap_cache_page() for page %d\n", pagenr);
+      DEBUG(3, "blkmtd: erase: doing grab_cache_page() for page %d\n", pagenr);
       page = grab_cache_page(&rawdevice->as, pagenr);
       if(!page) {
 	DEBUG(3, "blkmtd: erase: grab_cache_page() failed for page %d\n", pagenr);
@@ -509,7 +606,7 @@
       i++;
     }
     DEBUG(3, "blkmtd: erase: queuing page write\n");
-    err = queue_page_write(rawdevice, pages, from >> PAGE_SHIFT, len >> PAGE_SHIFT, 1);
+    err = queue_page_write(rawdevice, NULL, from >> PAGE_SHIFT, len >> PAGE_SHIFT, 1);
     pagecnt = len >> PAGE_SHIFT;
     if(!err) {
       while(pagecnt--) {
@@ -565,7 +662,7 @@
     struct page *page;
     int cpylen;
     DEBUG(3, "blkmtd: read: looking for page: %d\n", pagenr);
-    page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice->file);
+    page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice);
     if(IS_ERR(page)) {
       return PTR_ERR(page);
     }
@@ -681,7 +778,7 @@
     struct page *page;
     
     DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %d offset = %d\n", pagenr, len1, offset);
-    page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice->file);
+    page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice);
 
     if(IS_ERR(page)) {
       kfree(pages);
@@ -714,6 +811,7 @@
       memcpy(page_address(page), buf, PAGE_SIZE);
       pages[pagecnt++] = page;
       UnlockPage(page);
+      SetPageUptodate(page);
       pagenr++;
       pagesc--;
       buf += PAGE_SIZE;
@@ -726,7 +824,7 @@
     /* do the third region */
     struct page *page;
     DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %d\n", pagenr, len3);
-    page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice->file);
+    page = read_cache_page(&rawdevice->as, pagenr, (filler_t *)blkmtd_readpage, rawdevice);
     if(IS_ERR(page)) {
       err = PTR_ERR(page);
       goto write_err;
@@ -764,6 +862,10 @@
 static void blkmtd_sync(struct mtd_info *mtd)
 {
   DECLARE_WAITQUEUE(wait, current);
+  mtd_raw_dev_data_t *rawdevice = mtd->priv;
+  if(rawdevice->readonly)
+    return;
+
   DEBUG(2, "blkmtd: sync: called\n");
 
  stuff_inq:
@@ -782,36 +884,144 @@
   }
   spin_unlock(&mbd_writeq_lock);
 
-  DEBUG(2, "blkmtdL sync: finished\n");
+  DEBUG(2, "blkmtd: sync: finished\n");
 }
 
+
+#ifdef BLKMTD_PROC_DEBUG
+/* procfs stuff */
+static int blkmtd_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+  int clean = 0, dirty = 0, locked = 0;
+  struct list_head *temp;
+  int i, len, pages = 0, cnt;
+  MOD_INC_USE_COUNT;
+  spin_lock(&mbd_writeq_lock);
+  cnt = write_queue_cnt;
+  i = write_queue_tail;
+  while(cnt) {
+    if(!write_queue[i].iserase)
+      pages += write_queue[i].pagecnt;
+    i++;
+    i %= write_queue_sz;
+    cnt--;
+  }
+
+  /* Count the size of the page lists */
+  list_for_each(temp, &mtd_rawdevice->as.clean_pages) {
+    clean++;
+  }
+  list_for_each(temp, &mtd_rawdevice->as.dirty_pages) {
+    dirty++;
+  }
+  list_for_each(temp, &mtd_rawdevice->as.locked_pages) {
+    locked++;
+  }
+
+  len = sprintf(page, "Write queue head: %d\nWrite queue tail: %d\n"
+		"Write queue count: %d\nPages in queue: %d (%dK)\n"
+		"Clean Pages: %d\nDirty Pages: %d\nLocked Pages: %d\n"
+		"nrpages: %ld\n",
+		write_queue_head, write_queue_tail, write_queue_cnt,
+		pages, pages << (PAGE_SHIFT-10), clean, dirty, locked,
+		mtd_rawdevice->as.nrpages);
+  if(len <= count)
+    *eof = 1;
+  spin_unlock(&mbd_writeq_lock);
+  MOD_DEC_USE_COUNT;
+  return len;
+}
+#endif
+
+
 /* Cleanup and exit - sync the device and kill of the kernel thread */
 static void __exit cleanup_blkmtd(void)
 {
-  if (mtd_info) {
-    mtd_raw_dev_data_t *rawdevice = mtd_info->priv;
-    // sync the device
-    if (rawdevice) {
-      blkmtd_sync(mtd_info);
+#ifdef BLKMTD_PROC_DEBUG
+  if(blkmtd_proc) {
+    remove_proc_entry("blkmtd_debug", NULL);
+  }
+#endif
+
+  if (mtd_rawdevice) {
+    /* sync the device */
+    if (!mtd_rawdevice->readonly) {
+      blkmtd_sync(&mtd_rawdevice->mtd_info);
       write_task_finish = 1;
       wake_up_interruptible(&thr_wq);
       down(&thread_sem);
-      if(rawdevice->binding != NULL)
-	blkdev_put(rawdevice->binding, BDEV_RAW);
-      filp_close(rawdevice->file, NULL);
-      kfree(mtd_info->priv);
     }
-    if(mtd_info->eraseregions)
-      kfree(mtd_info->eraseregions);
-    del_mtd_device(mtd_info);
-    kfree(mtd_info);
-    mtd_info = NULL;
+    del_mtd_device(&mtd_rawdevice->mtd_info);
+    if(mtd_rawdevice->binding != NULL)
+      blkdev_put(mtd_rawdevice->binding, BDEV_RAW);
+
+    if(mtd_rawdevice->mtd_info.eraseregions)
+      kfree(mtd_rawdevice->mtd_info.eraseregions);
+    if(mtd_rawdevice->mtd_info.name)
+      kfree(mtd_rawdevice->mtd_info.name);
+
+    kfree(mtd_rawdevice);
+  }
+  if(write_queue)
+    kfree(write_queue);
+
+  if(erase_page) {
+    UnlockPage(erase_page);
+    __free_pages(erase_page, 0);
   }
   printk("blkmtd: unloaded for %s\n", device);
 }
 
 extern struct module __this_module;
 
+#ifndef MODULE
+
+/* Handle kernel boot params */
+
+
+static int __init param_blkmtd_device(char *str)
+{
+  device = str;
+  return 1;
+}
+
+
+static int __init param_blkmtd_erasesz(char *str)
+{
+  erasesz = simple_strtol(str, NULL, 0);
+  return 1;
+}
+
+
+static int __init param_blkmtd_ro(char *str)
+{
+  ro = simple_strtol(str, NULL, 0);
+  return 1;
+}
+
+
+static int __init param_blkmtd_bs(char *str)
+{
+  bs = simple_strtol(str, NULL, 0);
+  return 1;
+}
+
+
+static int __init param_blkmtd_count(char *str)
+{
+  count = simple_strtol(str, NULL, 0);
+  return 1;
+}
+
+__setup("blkmtd_device=", param_blkmtd_device);
+__setup("blkmtd_erasesz=", param_blkmtd_erasesz);
+__setup("blkmtd_ro=", param_blkmtd_ro);
+__setup("blkmtd_bs=", param_blkmtd_bs);
+__setup("blkmtd_count=", param_blkmtd_count);
+
+#endif
+
+
 /* for a given size and initial erase size, calculate the number and size of each
    erase region */
 static int __init calc_erase_regions(struct mtd_erase_region_info *info, size_t erase_size, size_t total_size)
@@ -840,12 +1050,16 @@
 }
 
 
+extern kdev_t name_to_kdev_t(char *line) __init;
+
 /* Startup */
 static int __init init_blkmtd(void)
 {
+#ifdef MODULE
   struct file *file = NULL;
   struct inode *inode;
-  mtd_raw_dev_data_t *rawdevice = NULL;
+#endif
+
   int maj, min;
   int i, blocksize, blocksize_bits;
   loff_t size = 0;
@@ -854,15 +1068,12 @@
   kdev_t rdev;
   int err;
   int mode;
-  int totalsize = 0, total_sectors = 0;
   int regions;
 
-  mtd_info = NULL;
-
-  // Check args
+  /* Check args */
   if(device == 0) {
     printk("blkmtd: error, missing `device' name\n");
-    return 1;
+    return -EINVAL;
   }
 
   if(ro)
@@ -871,12 +1082,25 @@
   if(erasesz)
     erase_size = erasesz;
 
-  DEBUG(1, "blkmtd: got device = `%s' erase size = %dK readonly = %s\n", device, erase_size, readonly ? "yes" : "no");
-  // Get a handle on the device
+  if(wqs) {
+    if(wqs < 16) 
+      wqs = 16;
+    if(wqs > 4*WRITE_QUEUE_SZ)
+      wqs = 4*WRITE_QUEUE_SZ;
+    write_queue_sz = wqs;
+  }
+
+  DEBUG(1, "blkmtd: device = `%s' erase size = %dK readonly = %s queue size = %d\n",
+	device, erase_size, readonly ? "yes" : "no", write_queue_sz);
+  /* Get a handle on the device */
   mode = (readonly) ? O_RDONLY : O_RDWR;
+
+#ifdef MODULE
+
   file = filp_open(device, mode, 0);
   if(IS_ERR(file)) {
-    DEBUG(2, "blkmtd: open_namei returned %ld\n", PTR_ERR(file));
+    printk("blkmtd: error, cant open device %s\n", device);
+    DEBUG(2, "blkmtd: filp_open returned %ld\n", PTR_ERR(file));
     return 1;
   }
   
@@ -889,11 +1113,19 @@
     return 1;
   }
   rdev = inode->i_rdev;
-  //filp_close(file, NULL);
-  DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n",
-	 MAJOR(rdev), MINOR(rdev));
-  maj = MAJOR(rdev);
-  min = MINOR(rdev);
+  filp_close(file, NULL);
+#else
+  rdev = name_to_kdev_t(device);
+#endif
+
+  maj = major(rdev);
+  min = minor(rdev);
+  DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n", maj, min);
+
+  if(kdev_none(rdev)) {
+    printk("blkmtd: bad block device: `%s'\n", device);
+    return 1;
+  }
 
   if(maj == MTD_BLOCK_MAJOR) {
     printk("blkmtd: attempting to use an MTD device as a block device\n");
@@ -918,116 +1150,159 @@
       size = ((loff_t) blk_size[maj][min] << BLOCK_SIZE_BITS) >> blocksize_bits;
     }
   }
-  total_sectors = size;
   size *= blocksize;
-  totalsize = size;
   DEBUG(1, "blkmtd: size = %ld\n", (long int)size);
 
   if(size == 0) {
     printk("blkmtd: cant determine size\n");
     return 1;
   }
-  rawdevice = (mtd_raw_dev_data_t *)kmalloc(sizeof(mtd_raw_dev_data_t), GFP_KERNEL);
-  if(rawdevice == NULL) {
+
+  mtd_rawdevice = (mtd_raw_dev_data_t *)kmalloc(sizeof(mtd_raw_dev_data_t), GFP_KERNEL);
+  if(mtd_rawdevice == NULL) {
     err = -ENOMEM;
     goto init_err;
   }
-  memset(rawdevice, 0, sizeof(mtd_raw_dev_data_t));
-  // get the block device
-  rawdevice->binding = bdget(kdev_t_to_nr(MKDEV(maj, min)));
-  err = blkdev_get(rawdevice->binding, mode, 0, BDEV_RAW);
+  memset(mtd_rawdevice, 0, sizeof(mtd_raw_dev_data_t));
+  /* get the block device */
+  mtd_rawdevice->binding = bdget(kdev_t_to_nr(mk_kdev(maj, min)));
+  err = blkdev_get(mtd_rawdevice->binding, mode, 0, BDEV_RAW);
   if (err) {
     goto init_err;
   }
-  rawdevice->totalsize = totalsize;
-  rawdevice->total_sectors = total_sectors;
-  rawdevice->sector_size = blocksize;
-  rawdevice->sector_bits = blocksize_bits;
-  rawdevice->readonly = readonly;
-
-  DEBUG(2, "sector_size = %d, sector_bits = %d\n", rawdevice->sector_size, rawdevice->sector_bits);
-
-  mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-  if (mtd_info == NULL) {
-    err = -ENOMEM;
+  mtd_rawdevice->totalsize = size;
+  mtd_rawdevice->sector_size = blocksize;
+  mtd_rawdevice->sector_bits = blocksize_bits;
+  mtd_rawdevice->readonly = readonly;
+
+  /* See if device ends on page boundary */
+  if(size % PAGE_SIZE) {
+    mtd_rawdevice->partial_last_page = size >> PAGE_SHIFT;
+    mtd_rawdevice->last_page_sectors = (size & (PAGE_SIZE-1)) >> blocksize_bits;
+  }
+
+  DEBUG(2, "sector_size = %d, sector_bits = %d, partial_last_page = %d last_page_sectors = %d\n", 
+	mtd_rawdevice->sector_size, mtd_rawdevice->sector_bits,
+	mtd_rawdevice->partial_last_page, mtd_rawdevice->last_page_sectors);
+
+  /* Setup the MTD structure */
+  /* make the name contain the block device in */
+  mtd_rawdevice->mtd_info.name = kmalloc(9 + strlen(device), GFP_KERNEL);
+  if(mtd_rawdevice->mtd_info.name == NULL)
     goto init_err;
-  }
-  memset(mtd_info, 0, sizeof(*mtd_info));
 
-  // Setup the MTD structure
-  mtd_info->name = "blkmtd block device";
+  sprintf(mtd_rawdevice->mtd_info.name, "blkmtd: %s", device);
   if(readonly) {
-    mtd_info->type = MTD_ROM;
-    mtd_info->flags = MTD_CAP_ROM;
-    mtd_info->erasesize = erase_size << 10;
+    mtd_rawdevice->mtd_info.type = MTD_ROM;
+    mtd_rawdevice->mtd_info.flags = MTD_CAP_ROM;
+    mtd_rawdevice->mtd_info.erasesize = erase_size << 10;
   } else {
-    mtd_info->type = MTD_RAM;
-    mtd_info->flags = MTD_CAP_RAM;
-    mtd_info->erasesize = erase_size << 10;
-  }
-  mtd_info->size = size;
-  mtd_info->erase = blkmtd_erase;
-  mtd_info->read = blkmtd_read;
-  mtd_info->write = blkmtd_write;
-  mtd_info->sync = blkmtd_sync;
-  mtd_info->point = 0;
-  mtd_info->unpoint = 0;
+    mtd_rawdevice->mtd_info.type = MTD_RAM;
+    mtd_rawdevice->mtd_info.flags = MTD_CAP_RAM;
+    mtd_rawdevice->mtd_info.erasesize = erase_size << 10;
+  }
+  mtd_rawdevice->mtd_info.size = size;
+  mtd_rawdevice->mtd_info.erase = blkmtd_erase;
+  mtd_rawdevice->mtd_info.read = blkmtd_read;
+  mtd_rawdevice->mtd_info.write = blkmtd_write;
+  mtd_rawdevice->mtd_info.sync = blkmtd_sync;
+  mtd_rawdevice->mtd_info.point = 0;
+  mtd_rawdevice->mtd_info.unpoint = 0;
 
-  mtd_info->priv = rawdevice;
+  mtd_rawdevice->mtd_info.priv = mtd_rawdevice;
   regions = calc_erase_regions(NULL, erase_size << 10, size);
   DEBUG(1, "blkmtd: init: found %d erase regions\n", regions);
-  mtd_info->eraseregions = kmalloc(regions * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
-  if(mtd_info->eraseregions == NULL) {
+  mtd_rawdevice->mtd_info.eraseregions = kmalloc(regions * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
+  if(mtd_rawdevice->mtd_info.eraseregions == NULL) {
+    err = -ENOMEM;
+    goto init_err;
   }
-  mtd_info->numeraseregions = regions;
-  calc_erase_regions(mtd_info->eraseregions, erase_size << 10, size);
+  mtd_rawdevice->mtd_info.numeraseregions = regions;
+  calc_erase_regions(mtd_rawdevice->mtd_info.eraseregions, erase_size << 10, size);
 
   /* setup the page cache info */
-  INIT_LIST_HEAD(&rawdevice->as.clean_pages);
-  INIT_LIST_HEAD(&rawdevice->as.dirty_pages);
-  INIT_LIST_HEAD(&rawdevice->as.locked_pages);
-  rawdevice->as.nrpages = 0;
-  rawdevice->as.a_ops = &blkmtd_aops;
-  rawdevice->as.host = inode;
-  INIT_LIST_HEAD(&rawdevice->as.i_mmap);
-  INIT_LIST_HEAD(&rawdevice->as.i_mmap_shared);
-  spin_lock_init(&rawdevice->as.i_shared_lock);
-  rawdevice->as.gfp_mask = GFP_KERNEL;
-  rawdevice->file = file;
-
-  file->private_data = rawdevice;
+  
+  mtd_rawdevice->as.nrpages = 0;
+  INIT_LIST_HEAD(&mtd_rawdevice->as.clean_pages);
+  INIT_LIST_HEAD(&mtd_rawdevice->as.dirty_pages);
+  INIT_LIST_HEAD(&mtd_rawdevice->as.locked_pages);
+  mtd_rawdevice->as.host = NULL;
+  spin_lock_init(&(mtd_rawdevice->as.i_shared_lock));
+
+  mtd_rawdevice->as.a_ops = &blkmtd_aops;
+  INIT_LIST_HEAD(&mtd_rawdevice->as.i_mmap);
+  INIT_LIST_HEAD(&mtd_rawdevice->as.i_mmap_shared);
+  mtd_rawdevice->as.gfp_mask = GFP_KERNEL;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-   mtd_info->module = THIS_MODULE;			
+  mtd_rawdevice->mtd_info.module = THIS_MODULE;			
 #endif
-   if (add_mtd_device(mtd_info)) {
-     err = -EIO;
-     goto init_err;
-   }
-   init_waitqueue_head(&thr_wq);
-   init_waitqueue_head(&mtbd_sync_wq);
-   DEBUG(3, "blkmtd: init: kernel task @ %p\n", write_queue_task);
-   DEBUG(2, "blkmtd: init: starting kernel task\n");
-   kernel_thread(write_queue_task, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-   DEBUG(2, "blkmtd: init: started\n");
-   printk("blkmtd loaded: version = %s using %s erase_size = %dK %s\n", VERSION, device, erase_size, (readonly) ? "(read-only)" : "");
-   return 0;
+  if (add_mtd_device(&mtd_rawdevice->mtd_info)) {
+    err = -EIO;
+    goto init_err;
+  }
 
+  if(!mtd_rawdevice->readonly) {
+    /* Allocate the write queue */
+    write_queue = kmalloc(write_queue_sz * sizeof(mtdblkdev_write_queue_t), GFP_KERNEL);
+    if(!write_queue) {
+      err = -ENOMEM;
+      goto init_err;
+    }
+    /* Set up the erase page */
+    erase_page = alloc_pages(GFP_KERNEL, 0);
+    if(erase_page == NULL) {
+      err = -ENOMEM;
+      goto init_err;
+    }
+    memset(page_address(erase_page), 0xff, PAGE_SIZE);
+    lock_page(erase_page);
+
+    init_waitqueue_head(&thr_wq);
+    init_waitqueue_head(&mtbd_sync_wq);
+    DEBUG(3, "blkmtd: init: kernel task @ %p\n", write_queue_task);
+    DEBUG(2, "blkmtd: init: starting kernel task\n");
+    kernel_thread(write_queue_task, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+    DEBUG(2, "blkmtd: init: started\n");
+    printk("blkmtd loaded: version = %s using %s erase_size = %dK %s\n",
+	   VERSION, device, erase_size, (readonly) ? "(read-only)" : "");
+  }
+
+#ifdef BLKMTD_PROC_DEBUG
+  /* create proc entry */
+  DEBUG(2, "Creating /proc/blkmtd_debug\n");
+  blkmtd_proc = create_proc_read_entry("blkmtd_debug", 0444,
+				       NULL, blkmtd_proc_read, NULL);
+  if(blkmtd_proc == NULL) {
+    printk("Cant create /proc/blkmtd_debug\n");
+  } else {
+    blkmtd_proc->owner = THIS_MODULE;
+  }
+#endif
+  
+  /* Everything is ok if we got here */
+  return 0;
+  
  init_err:
-   if(!rawdevice) {
-     if(rawdevice->binding) 
-       blkdev_put(rawdevice->binding, BDEV_RAW);
 
-     kfree(rawdevice);
-     rawdevice = NULL;
-   }
-   if(mtd_info) {
-     if(mtd_info->eraseregions)
-       kfree(mtd_info->eraseregions);
-     kfree(mtd_info);
-     mtd_info = NULL;
-   }
-   return err;
+  if(mtd_rawdevice) {
+    if(mtd_rawdevice->mtd_info.eraseregions)
+      kfree(mtd_rawdevice->mtd_info.eraseregions);
+    if(mtd_rawdevice->mtd_info.name)
+      kfree(mtd_rawdevice->mtd_info.name);
+    if(mtd_rawdevice->binding) 
+      blkdev_put(mtd_rawdevice->binding, BDEV_RAW);
+    kfree(mtd_rawdevice);
+  }
+
+  if(write_queue) {
+    kfree(write_queue);
+    write_queue = NULL;
+  }
+
+  if(erase_page) 
+    __free_pages(erase_page, 0);
+  return err;
 }
 
 module_init(init_blkmtd);
diff -urN linux-2.5.6-pre1/drivers/mtd/mtdblock.c linux-2.5.6-pre2/drivers/mtd/mtdblock.c
--- linux-2.5.6-pre1/drivers/mtd/mtdblock.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/mtd/mtdblock.c	Thu Feb 28 13:34:21 2002
@@ -16,11 +16,8 @@
 
 #define MAJOR_NR MTD_BLOCK_MAJOR
 #define DEVICE_NAME "mtdblock"
-#define DEVICE_REQUEST mtdblock_request
 #define DEVICE_NR(device) (device)
-#define DEVICE_ON(device)
-#define DEVICE_OFF(device)
-#define DEVICE_NO_RANDOM
+#define LOCAL_END_REQUEST
 #include <linux/blk.h>
 /* for old kernels... */
 #ifndef QUEUE_EMPTY
@@ -283,7 +280,7 @@
 	if (!inode)
 		return -EINVAL;
 	
-	dev = MINOR(inode->i_rdev);
+	dev = minor(inode->i_rdev);
 	if (dev >= MAX_MTD_DEVICES)
 		return -EINVAL;
 
@@ -373,7 +370,7 @@
 
 	invalidate_device(inode->i_rdev, 1);
 
-	dev = MINOR(inode->i_rdev);
+	dev = minor(inode->i_rdev);
 	mtdblk = mtdblks[dev];
 
 	down(&mtdblk->cache_sem);
@@ -417,18 +414,20 @@
 		INIT_REQUEST;
 		req = CURRENT;
 		spin_unlock_irq(&QUEUE->queue_lock);
-		mtdblk = mtdblks[MINOR(req->rq_dev)];
+		mtdblk = mtdblks[minor(req->rq_dev)];
 		res = 0;
 
-		if (MINOR(req->rq_dev) >= MAX_MTD_DEVICES)
+		if (minor(req->rq_dev) >= MAX_MTD_DEVICES)
 			panic(__FUNCTION__": minor out of bound");
 
+		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 (req->cmd)
-		{
+		switch (rq_data_dir(CURRENT)) {
 			int err;
 
 			case READ:
@@ -459,7 +458,11 @@
 
 end_req:
 		spin_lock_irq(&QUEUE->queue_lock);
-		end_request(res);
+		if (!end_that_request_first(req, res, req->hard_cur_sectors)) {
+			blkdev_dequeue_request(req);
+			end_that_request_last(req);
+		}
+
 	}
 }
 
@@ -519,7 +522,7 @@
 {
 	struct mtdblk_dev *mtdblk;
 
-	mtdblk = mtdblks[MINOR(inode->i_rdev)];
+	mtdblk = mtdblks[minor(inode->i_rdev)];
 
 #ifdef PARANOIA
 	if (!mtdblk)
@@ -537,7 +540,7 @@
 		if(!capable(CAP_SYS_ADMIN))
 			return -EACCES;
 #endif
-		fsync_dev(inode->i_rdev);
+		fsync_bdev(inode->i_bdev);
 		invalidate_buffers(inode->i_rdev);
 		down(&mtdblk->cache_sem);
 		write_cached_data(mtdblk);
@@ -597,6 +600,8 @@
 }
 #endif
 
+static spinlock_t mtddev_lock = SPIN_LOCK_UNLOCKED;
+
 int __init init_mtdblock(void)
 {
 	int i;
@@ -630,7 +635,7 @@
 	blksize_size[MAJOR_NR] = mtd_blksizes;
 	blk_size[MAJOR_NR] = mtd_sizes;
 	
-	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);
+	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request, &mtddev_lock);
 	kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
 	return 0;
 }
diff -urN linux-2.5.6-pre1/drivers/mtd/mtdblock_ro.c linux-2.5.6-pre2/drivers/mtd/mtdblock_ro.c
--- linux-2.5.6-pre1/drivers/mtd/mtdblock_ro.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/drivers/mtd/mtdblock_ro.c	Thu Feb 28 13:34:21 2002
@@ -16,13 +16,10 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/compatmac.h>
 
+#define LOCAL_END_REQUEST
 #define MAJOR_NR MTD_BLOCK_MAJOR
 #define DEVICE_NAME "mtdblock"
-#define DEVICE_REQUEST mtdblock_request
 #define DEVICE_NR(device) (device)
-#define DEVICE_ON(device)
-#define DEVICE_OFF(device)
-#define DEVICE_NO_RANDOM
 #include <linux/blk.h>
 
 #if LINUX_VERSION_CODE < 0x20300
@@ -52,7 +49,7 @@
 	if (inode == 0)
 		return -EINVAL;
 	
-	dev = MINOR(inode->i_rdev);
+	dev = minor(inode->i_rdev);
 	
 	mtd = get_mtd_device(NULL, dev);
 	if (!mtd)
@@ -81,7 +78,7 @@
    
 	invalidate_device(inode->i_rdev, 1);
 
-	dev = MINOR(inode->i_rdev);
+	dev = minor(inode->i_rdev);
 	mtd = __get_mtd_device(NULL, dev);
 
 	if (!mtd) {
@@ -97,8 +94,15 @@
 	DEBUG(1, "ok\n");
 
 	release_return(0);
-}  
+}
 
+static inline void mtdblock_end_request(struct request *req, int uptodate)
+{
+	if (end_that_request_first(req, uptodate, req->hard_cur_sectors))
+		return;
+	blkdev_dequeue_request(req);
+	end_that_request_last(req);
+}
 
 static void mtdblock_request(RQFUNC_ARG)
 {
@@ -113,19 +117,19 @@
       INIT_REQUEST;
       current_request = CURRENT;
    
-      if (MINOR(current_request->rq_dev) >= MAX_MTD_DEVICES)
+      if (minor(current_request->rq_dev) >= MAX_MTD_DEVICES)
       {
 	 printk("mtd: Unsupported device!\n");
-	 end_request(0);
+	 mtdblock_end_request(current_request, 0);
 	 continue;
       }
       
       // Grab our MTD structure
 
-      mtd = __get_mtd_device(NULL, MINOR(current_request->rq_dev));
+      mtd = __get_mtd_device(NULL, minor(current_request->rq_dev));
       if (!mtd) {
 	      printk("MTD device %d doesn't appear to exist any more\n", CURRENT_DEV);
-	      end_request(0);
+	      mtdblock_end_request(current_request, 0);
       }
 
       if (current_request->sector << 9 > mtd->size ||
@@ -133,7 +137,7 @@
       {
 	 printk("mtd: Attempt to read past end of device!\n");
 	 printk("size: %x, sector: %lx, nr_sectors %lx\n", mtd->size, current_request->sector, current_request->nr_sectors);
-	 end_request(0);
+	 mtdblock_end_request(current_request, 0);
 	 continue;
       }
       
@@ -192,7 +196,7 @@
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
 	spin_lock_irq(&io_request_lock);
 #endif
-	end_request(res);
+	mtdblock_end_request(current_request, res);
    }
 }
 
@@ -203,7 +207,7 @@
 {
 	struct mtd_info *mtd;
 
-	mtd = __get_mtd_device(NULL, MINOR(inode->i_rdev));
+	mtd = __get_mtd_device(NULL, minor(inode->i_rdev));
 
 	if (!mtd) return -EINVAL;
 
@@ -217,7 +221,7 @@
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
 		if(!capable(CAP_SYS_ADMIN))  return -EACCES;
 #endif
-		fsync_dev(inode->i_rdev);
+		fsync_bdev(inode->i_bdev);
 		invalidate_buffers(inode->i_rdev);
 		if (mtd->sync)
 			mtd->sync(mtd);
diff -urN linux-2.5.6-pre1/drivers/mtd/mtdchar.c linux-2.5.6-pre2/drivers/mtd/mtdchar.c
--- linux-2.5.6-pre1/drivers/mtd/mtdchar.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/mtd/mtdchar.c	Thu Feb 28 13:34:21 2002
@@ -64,7 +64,7 @@
 
 static int mtd_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	int devnum = minor >> 1;
 	struct mtd_info *mtd;
 
diff -urN linux-2.5.6-pre1/drivers/mtd/nftlcore.c linux-2.5.6-pre2/drivers/mtd/nftlcore.c
--- linux-2.5.6-pre1/drivers/mtd/nftlcore.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/drivers/mtd/nftlcore.c	Thu Feb 28 13:34:21 2002
@@ -795,7 +795,7 @@
 	}
 	case BLKFLSBUF:
 		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-		fsync_dev(inode->i_rdev);
+		fsync_bdev(inode->i_bdev);
 		invalidate_buffers(inode->i_rdev);
 		if (nftl->mtd->sync)
 			nftl->mtd->sync(nftl->mtd);
diff -urN linux-2.5.6-pre1/drivers/net/8139cp.c linux-2.5.6-pre2/drivers/net/8139cp.c
--- linux-2.5.6-pre1/drivers/net/8139cp.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/drivers/net/8139cp.c	Thu Feb 28 13:34:21 2002
@@ -1,6 +1,6 @@
 /* 8139cp.c: A Linux PCI Ethernet driver for the RealTek 8139C+ chips. */
 /*
-	Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+	Copyright 2001,2002 Jeff Garzik <jgarzik@mandrakesoft.com>
 
 	Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) [sungem.c]
 	Copyright 2001 Manfred Spraul				    [natsemi.c]
@@ -32,19 +32,20 @@
 	* Rx checksumming
 	* Tx checksumming
 	* ETHTOOL_GREGS, ETHTOOL_[GS]WOL,
-	* Jumbo frames / dev->change_mtu
 	* Investigate using skb->priority with h/w VLAN priority
 	* Investigate using High Priority Tx Queue with skb->priority
 	* Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error
 	* Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error
         * Implement Tx software interrupt mitigation via
 	          Tx descriptor bit
+	* Determine correct value for CP_{MIN,MAX}_MTU, instead of
+	  using conservative guesses.
 
  */
 
 #define DRV_NAME		"8139cp"
-#define DRV_VERSION		"0.0.6cvs"
-#define DRV_RELDATE		"Nov 19, 2001"
+#define DRV_VERSION		"0.0.7"
+#define DRV_RELDATE		"Feb 27, 2002"
 
 
 #include <linux/module.h>
@@ -55,7 +56,6 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ethtool.h>
-#include <linux/crc32.h>
 #include <linux/mii.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -107,8 +107,11 @@
 #define TX_EARLY_THRESH		256	/* Early Tx threshold, in bytes */
 
 /* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (6*HZ)
+#define TX_TIMEOUT		(6*HZ)
 
+/* hardware minimum and maximum for a single frame's data payload */
+#define CP_MIN_MTU		60	/* FIXME: this is a guess */
+#define CP_MAX_MTU		1500	/* FIXME: this is a guess */
 
 enum {
 	/* NIC register offsets */
@@ -321,6 +324,17 @@
 };
 MODULE_DEVICE_TABLE(pci, cp_pci_tbl);
 
+static inline void cp_set_rxbufsize (struct cp_private *cp)
+{
+	unsigned int mtu = cp->dev->mtu;
+	
+	if (mtu > ETH_DATA_LEN)
+		/* MTU + ethernet header + FCS + optional VLAN tag */
+		cp->rx_buf_sz = mtu + ETH_HLEN + 8;
+	else
+		cp->rx_buf_sz = PKT_BUF_SZ;
+}
+
 static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb)
 {
 	skb->protocol = eth_type_trans (skb, cp->dev);
@@ -705,9 +719,6 @@
 	return 0;
 }
 
-/* Set or clear the multicast filter for this adaptor.
-   This routine is not state sensitive and need not be SMP locked. */
-
 static void __cp_set_rx_mode (struct net_device *dev)
 {
 	struct cp_private *cp = dev->priv;
@@ -812,6 +823,12 @@
 	printk(KERN_ERR "%s: hardware reset timeout\n", cp->dev->name);
 }
 
+static inline void cp_start_hw (struct cp_private *cp)
+{
+	cpw8(Cmd, RxOn | TxOn);
+	cpw16(CpCmd, PCIMulRW | CpRxOn | CpTxOn);
+}
+
 static void cp_init_hw (struct cp_private *cp)
 {
 	struct net_device *dev = cp->dev;
@@ -824,8 +841,7 @@
 	cpw32_f (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
 	cpw32_f (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
 
-	cpw8(Cmd, RxOn | TxOn);
-	cpw16(CpCmd, PCIMulRW | CpRxOn | CpTxOn);
+	cp_start_hw(cp);
 	cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */
 
 	__cp_set_rx_mode(dev);
@@ -957,8 +973,6 @@
 	if (netif_msg_ifup(cp))
 		printk(KERN_DEBUG "%s: enabling interface\n", dev->name);
 
-	cp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
-
 	rc = cp_alloc_rings(cp);
 	if (rc)
 		return rc;
@@ -993,6 +1007,36 @@
 	return 0;
 }
 
+static int cp_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct cp_private *cp = dev->priv;
+	int rc;
+
+	/* check for invalid MTU, according to hardware limits */
+	if (new_mtu < CP_MIN_MTU || new_mtu > CP_MAX_MTU)
+		return -EINVAL;
+
+	/* if network interface not up, no need for complexity */
+	if (!netif_running(dev)) {
+		cp_set_rxbufsize(cp);	/* set new rx buf size */
+		return 0;
+	}
+
+	spin_lock_irq(&cp->lock);
+
+	cp_stop_hw(cp);			/* stop h/w and free rings */
+	cp_clean_rings(cp);
+
+	cp_set_rxbufsize(cp);		/* set new rx buf size */
+
+	rc = cp_init_rings(cp);		/* realloc and restart h/w */
+	cp_start_hw(cp);
+
+	spin_unlock_irq(&cp->lock);
+
+	return rc;
+}
+
 static char mii_2_8139_map[8] = {
 	BasicModeCtrl,
 	BasicModeStatus,
@@ -1231,6 +1275,7 @@
 	cp->mii_if.mdio_read = mdio_read;
 	cp->mii_if.mdio_write = mdio_write;
 	cp->mii_if.phy_id = CP_INTERNAL_PHY;
+	cp_set_rxbufsize(cp);
 
 	rc = pci_enable_device(pdev);
 	if (rc)
@@ -1284,6 +1329,7 @@
 	dev->hard_start_xmit = cp_start_xmit;
 	dev->get_stats = cp_get_stats;
 	dev->do_ioctl = cp_ioctl;
+	dev->change_mtu = cp_change_mtu;
 #if 0
 	dev->tx_timeout = cp_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
diff -urN linux-2.5.6-pre1/drivers/net/e1000/e1000.h linux-2.5.6-pre2/drivers/net/e1000/e1000.h
--- linux-2.5.6-pre1/drivers/net/e1000/e1000.h	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/drivers/net/e1000/e1000.h	Thu Feb 28 13:34:21 2002
@@ -117,9 +117,6 @@
 
 #define BAR_0 0
 
-/* Advertise that we can DMA from any address location */
-#define E1000_DMA_MASK (~0x0UL)
-
 #if DBG
 #define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args)
 #else
diff -urN linux-2.5.6-pre1/drivers/net/e1000/e1000_main.c linux-2.5.6-pre2/drivers/net/e1000/e1000_main.c
--- linux-2.5.6-pre1/drivers/net/e1000/e1000_main.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/drivers/net/e1000/e1000_main.c	Thu Feb 28 13:34:21 2002
@@ -79,7 +79,7 @@
 
 char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
 
-char e1000_driver_version[] = "4.2.4-k1";
+char e1000_driver_version[] = "4.2.4-k2";
 
 char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation.";
 
@@ -368,13 +368,21 @@
 	static int cards_found = 0;
 	unsigned long mmio_start;
 	int mmio_len;
+	int pci_using_dac;
 	int i;
 
 	if((i = pci_enable_device(pdev)))
 		return i;
 
-	if((i = pci_set_dma_mask(pdev, E1000_DMA_MASK)))
-		return i;
+	if(!(i = pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff))) {
+		pci_using_dac = 1;
+	} else {
+		if((i = pci_set_dma_mask(pdev, (u64) 0xffffffff))) {
+			E1000_ERR("No usable DMA configuration, aborting\n");
+			return i;
+		}
+		pci_using_dac = 0;
+	}
 
 	if((i = pci_request_regions(pdev, e1000_driver_name)))
 		return i;
@@ -422,13 +430,14 @@
 	e1000_sw_init(adapter);
 
 	if(adapter->shared.mac_type >= e1000_82543) {
-		netdev->features = NETIF_F_SG |
-		                   NETIF_F_IP_CSUM |
-		                   NETIF_F_HIGHDMA;
+		netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM;
 	} else {
-		netdev->features = NETIF_F_SG | NETIF_F_HIGHDMA;
+		netdev->features = NETIF_F_SG;
 	}
 
+	if(pci_using_dac)
+		netdev->features |= NETIF_F_HIGHDMA;
+
 	/* make sure the EEPROM is good */
 
 	if(!e1000_validate_eeprom_checksum(&adapter->shared))
@@ -783,12 +792,6 @@
 
 	E1000_WRITE_REG(&adapter->shared, TCTL, tctl);
 
-#ifdef CONFIG_PPC
-	if(adapter->shared.mac_type >= e1000_82543) {
-		E1000_WRITE_REG(&adapter->shared, TXDCTL, 0x00020000);
-	}
-#endif
-
 	/* Setup Transmit Descriptor Settings for this adapter */
 	adapter->txd_cmd = E1000_TXD_CMD_IFCS;
 
@@ -927,12 +930,6 @@
 		E1000_WRITE_REG(&adapter->shared, RXCSUM, rxcsum);
 	}
 
-#ifdef CONFIG_PPC
-	if(adapter->shared.mac_type >= e1000_82543) {
-		E1000_WRITE_REG(&adapter->shared, RXDCTL, 0x00020000);
-	}
-#endif
-
 	/* Enable Receives */
 
 	E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
diff -urN linux-2.5.6-pre1/drivers/parport/ChangeLog linux-2.5.6-pre2/drivers/parport/ChangeLog
--- linux-2.5.6-pre1/drivers/parport/ChangeLog	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/parport/ChangeLog	Thu Feb 28 13:34:22 2002
@@ -1,3 +1,21 @@
+2001-11-14  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c (parport_pc_pci_probe): Hooks for PCI cards before
+	and after probing for ports.
+	* parport_serial.c (parport_register): Likewise.
+
+2002-01-20  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c (parport_pc_compat_write_block_pio,
+	parport_pc_ecp_write_block_pio, parport_pc_ecp_read_block_pio):
+	Use the default implementations if the caller wants to use
+	O_NONBLOCK.
+
+2002-02-25  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c: Make sure that priv->ctr_writable includes IntEn
+	even if IRQ is given as a parameter.
+
 2002-01-21  Tim Waugh  <twaugh@redhat.com>
 
 	* daisy.c: Apply patch from Max Vorobiev to make parport_daisy_select
diff -urN linux-2.5.6-pre1/drivers/parport/parport_pc.c linux-2.5.6-pre2/drivers/parport/parport_pc.c
--- linux-2.5.6-pre1/drivers/parport/parport_pc.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/drivers/parport/parport_pc.c	Thu Feb 28 13:34:22 2002
@@ -818,8 +818,9 @@
 	long int expire;
 	const struct parport_pc_private *priv = port->physport->private_data;
 
-	/* Special case: a timeout of zero means we cannot call schedule(). */
-	if (!port->physport->cad->timeout)
+	/* Special case: a timeout of zero means we cannot call schedule().
+	 * Also if O_NONBLOCK is set then use the default implementation. */
+	if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
 		return parport_ieee1284_write_compat (port, buf,
 						      length, flags);
 
@@ -894,8 +895,9 @@
 	long int expire;
 	const struct parport_pc_private *priv = port->physport->private_data;
 
-	/* Special case: a timeout of zero means we cannot call schedule(). */
-	if (!port->physport->cad->timeout)
+	/* Special case: a timeout of zero means we cannot call schedule().
+	 * Also if O_NONBLOCK is set then use the default implementation. */
+	if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
 		return parport_ieee1284_ecp_write_data (port, buf,
 							length, flags);
 
@@ -1014,8 +1016,9 @@
 DPRINTK (KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n");
 dump_parport_state ("enter fcn", port);
 
-	/* Special case: a timeout of zero means we cannot call schedule(). */
-	if (!port->cad->timeout)
+	/* Special case: a timeout of zero means we cannot call schedule().
+	 * Also if O_NONBLOCK is set then use the default implementation. */
+	if (port->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
 		return parport_ieee1284_ecp_read_data (port, buf,
 						       length, flags);
 
@@ -2136,8 +2139,6 @@
 {
 	struct parport_pc_private *priv = pb->private_data;
 
-	priv->ctr_writable |= 0x10;
-
 	if (priv->ecr) {
 		pb->irq = programmable_irq_support(pb);
 
@@ -2162,9 +2163,6 @@
 	if (pb->irq == PARPORT_IRQ_NONE)
 		pb->irq = get_superio_irq(pb);
 
-	if (pb->irq == PARPORT_IRQ_NONE)
-		priv->ctr_writable &= ~0x10;
-
 	return pb->irq;
 }
 
@@ -2293,6 +2291,7 @@
 	}
 	if (p->irq != PARPORT_IRQ_NONE) {
 		printk(", irq %d", p->irq);
+		priv->ctr_writable |= 0x10;
 
 		if (p->dma == PARPORT_DMA_AUTO) {
 			p->dma = PARPORT_DMA_NONE;
@@ -2720,6 +2719,15 @@
 		int hi; /* -1 if not there, >6 for offset-method (max
                            BAR is 6) */
 	} addr[4];
+
+	/* If set, this is called immediately after pci_enable_device.
+	 * If it returns non-zero, no probing will take place and the
+	 * ports will not be used. */
+	int (*preinit_hook) (struct pci_dev *pdev, int autoirq, int autodma);
+
+	/* If set, this is called after probing for ports.  If 'failed'
+	 * is non-zero we couldn't use any of the ports. */
+	void (*postinit_hook) (struct pci_dev *pdev, int failed);
 } cards[] __devinitdata = {
 	/* siig_1s1p_10x_550 */		{ 1, { { 3, 4 }, } },
 	/* siig_1s1p_10x_650 */		{ 1, { { 3, 4 }, } },
@@ -2896,6 +2904,10 @@
 	if ((err = pci_enable_device (dev)) != 0)
 		return err;
 
+	if (cards[i].preinit_hook &&
+	    cards[i].preinit_hook (dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE))
+		return -ENODEV;
+
 	for (n = 0; n < cards[i].numports; n++) {
 		int lo = cards[i].addr[n].lo;
 		int hi = cards[i].addr[n].hi;
@@ -2918,6 +2930,9 @@
 			count++;
 	}
 
+	if (cards[i].postinit_hook)
+		cards[i].postinit_hook (dev, count == 0);
+
 	return count == 0 ? -ENODEV : 0;
 }
 
diff -urN linux-2.5.6-pre1/drivers/parport/parport_serial.c linux-2.5.6-pre2/drivers/parport/parport_serial.c
--- linux-2.5.6-pre1/drivers/parport/parport_serial.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/drivers/parport/parport_serial.c	Thu Feb 28 13:34:22 2002
@@ -53,6 +53,15 @@
 		int hi; /* -1 if not there, >6 for offset-method (max
                            BAR is 6) */
 	} addr[4];
+
+	/* If set, this is called immediately after pci_enable_device.
+	 * If it returns non-zero, no probing will take place and the
+	 * ports will not be used. */
+	int (*preinit_hook) (struct pci_dev *pdev, int autoirq, int autodma);
+
+	/* If set, this is called after probing for ports.  If 'failed'
+	 * is non-zero we couldn't use any of the ports. */
+	void (*postinit_hook) (struct pci_dev *pdev, int failed);
 } cards[] __devinitdata = {
 	/* titan_110l */		{ 1, { { 3, -1 }, } },
 	/* titan_210l */		{ 1, { { 3, -1 }, } },
@@ -239,6 +248,10 @@
 	int i = id->driver_data, n;
 	int success = 0;
 
+	if (cards[i].preinit_hook &&
+	    cards[i].preinit_hook (dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE))
+		return -ENODEV;
+
 	for (n = 0; n < cards[i].numports; n++) {
 		struct parport *port;
 		int lo = cards[i].addr[n].lo;
@@ -265,6 +278,9 @@
 		}
 	}
 
+	if (cards[i].postinit_hook)
+		cards[i].postinit_hook (dev, !success);
+
 	return success ? 0 : 1;
 }
 
diff -urN linux-2.5.6-pre1/drivers/pci/quirks.c linux-2.5.6-pre2/drivers/pci/quirks.c
--- linux-2.5.6-pre1/drivers/pci/quirks.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/drivers/pci/quirks.c	Thu Feb 28 13:34:22 2002
@@ -444,13 +444,15 @@
 static void __init quirk_amd_ordering(struct pci_dev *dev)
 {
 	u32 pcic;
-	
-	pci_read_config_dword(dev, 0x42, &pcic);
-	if((pcic&2)==0)
+	pci_read_config_dword(dev, 0x4C, &pcic);
+	if((pcic&6)!=6)
 	{
-		pcic |= 2;
-		printk(KERN_WARNING "BIOS disabled PCI ordering compliance, so we enabled it again.\n");
-		pci_write_config_dword(dev, 0x42, pcic);		
+		pcic |= 6;
+		printk(KERN_WARNING "BIOS failed to enable PCI standards compliance, fixing this error.\n");
+		pci_write_config_dword(dev, 0x4C, pcic);
+		pci_read_config_dword(dev, 0x84, &pcic);
+		pcic |= (1<<23);	/* Required in this mode */
+		pci_write_config_dword(dev, 0x84, pcic);
 	}
 }
 
diff -urN linux-2.5.6-pre1/drivers/s390/block/xpram.c linux-2.5.6-pre2/drivers/s390/block/xpram.c
--- linux-2.5.6-pre1/drivers/s390/block/xpram.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/s390/block/xpram.c	Thu Feb 28 13:34:22 2002
@@ -654,7 +654,7 @@
 			   (u64 *) arg);
 
 	case BLKFLSBUF: /* flush, 0x1261 */
-		fsync_dev(inode->i_rdev);
+		fsync_bdev(inode->i_bdev);
 		if ( capable(CAP_SYS_ADMIN) )invalidate_buffers(inode->i_rdev);
 		return 0;
 
@@ -1191,10 +1191,7 @@
 {
 	int i;
 
-	/* first of all, flush it all and reset all the data structures */
-
-	for (i=0; i<xpram_devs; i++)
-		fsync_dev(MKDEV(xpram_major, i)); /* flush the devices */
+	/* first of all, reset all the data structures */
 
 #if (XPRAM_VERSION == 22)
 	blk_dev[major].request_fn = NULL;
diff -urN linux-2.5.6-pre1/drivers/scsi/ide-scsi.c linux-2.5.6-pre2/drivers/scsi/ide-scsi.c
--- linux-2.5.6-pre1/drivers/scsi/ide-scsi.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/drivers/scsi/ide-scsi.c	Thu Feb 28 13:34:22 2002
@@ -182,7 +182,7 @@
 
 	if (!test_bit(PC_TRANSFORM, &pc->flags))
 		return;
-	if (drive->media == ide_cdrom || drive->media == ide_optical) {
+	if (drive->type == ATA_ROM || drive->type == ATA_MOD) {
 		if (c[0] == READ_6 || c[0] == WRITE_6) {
 			c[8] = c[4];		c[5] = c[3];		c[4] = c[2];
 			c[3] = c[1] & 0x1f;	c[2] = 0;		c[1] &= 0xe0;
@@ -221,7 +221,7 @@
 
 	if (!test_bit(PC_TRANSFORM, &pc->flags))
 		return;
-	if (drive->media == ide_cdrom || drive->media == ide_optical) {
+	if (drive->type == ATA_ROM || drive->type == ATA_MOD) {
 		if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) {
 			scsi_buf[0] = atapi_buf[1];		/* Mode data length */
 			scsi_buf[1] = atapi_buf[2];		/* Medium type */
@@ -508,7 +508,8 @@
  */
 static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id)
 {
-	DRIVER(drive)->busy++;
+	ata_ops(drive)->busy++;
+
 	idescsi_drives[id] = drive;
 	drive->driver_data = scsi;
 	drive->ready_stat = 0;
@@ -535,18 +536,13 @@
 	return 0;
 }
 
-int idescsi_init(void);
-int idescsi_reinit(ide_drive_t *drive);
+static int idescsi_reinit(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
  */
-static ide_driver_t idescsi_driver = {
-	name:			"ide-scsi",
-	media:			ide_scsi,
-	busy:			0,
-	supports_dma:		1,
-	supports_dsc_overlap:	0,
+static struct ata_operations idescsi_driver = {
+	owner:			THIS_MODULE,
 	cleanup:		idescsi_cleanup,
 	standby:		NULL,
 	flushcache:		NULL,
@@ -561,54 +557,23 @@
 	capacity:		NULL,
 	special:		NULL,
 	proc:			NULL,
-	driver_init:		idescsi_init,
 	driver_reinit:		idescsi_reinit,
 };
 
-int idescsi_reinit (ide_drive_t *drive)
+static int idescsi_reinit (ide_drive_t *drive)
 {
-#if 0
-	idescsi_scsi_t *scsi;
-	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
-	int i, failed, id;
-
-	if (!idescsi_initialized)
-		return 0;
-	for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++)
-		idescsi_drives[i] = NULL;
-
-	MOD_INC_USE_COUNT;
-	for (i = 0; media[i] != 255; i++) {
-		failed = 0;
-		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {
-
-			if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
-				printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
-				continue;
-			}
-			if (ide_register_subdriver (drive, &idescsi_driver)) {
-				printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
-				kfree (scsi);
-				continue;
-			}
-			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
-				idescsi_setup (drive, scsi, id);
-			failed--;
-		}
-	}
-	ide_register_module(&idescsi_module);
-	MOD_DEC_USE_COUNT;
-#endif
 	return 0;
 }
 
 /*
  *	idescsi_init will register the driver for each scsi.
  */
-int idescsi_init (void)
+static int idescsi_init(void)
 {
 	ide_drive_t *drive;
 	idescsi_scsi_t *scsi;
+	/* FIXME: The following is just plain wrong, since those are definitely *not* the
+	 * media types supported by the ATA layer */
 	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
 	int i, failed, id;
 
@@ -620,7 +585,7 @@
 	MOD_INC_USE_COUNT;
 	for (i = 0; media[i] != 255; i++) {
 		failed = 0;
-		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {
+		while ((drive = ide_scan_devices (media[i], "ide-scsi", NULL, failed++)) != NULL) {
 
 			if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
 				printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
@@ -636,7 +601,7 @@
 			failed--;
 		}
 	}
-	ide_register_module(&idescsi_driver);
+	revalidate_drives();
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -668,7 +633,7 @@
 	for (id = 0; id < MAX_HWIFS * MAX_DRIVES; id++) {
 		drive = idescsi_drives[id];
 		if (drive)
-			DRIVER(drive)->busy--;
+			ata_ops(drive)->busy--;
 	}
 	return 0;
 }
@@ -898,15 +863,22 @@
 	int i, failed;
 
 	scsi_unregister_host(&idescsi_template);
+
+	/* FIXME: The media types scanned here have literally nothing to do
+	 * with the media types used by the overall ATA code!
+	 *
+	 * This is basically showing us, that there is something wrong with the
+	 * ide_scan_devices function.
+	 */
+
 	for (i = 0; media[i] != 255; i++) {
 		failed = 0;
-		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL)
+		while ((drive = ide_scan_devices (media[i], "ide-scsi", &idescsi_driver, failed)) != NULL)
 			if (idescsi_cleanup (drive)) {
 				printk ("%s: exit_idescsi_module() called while still busy\n", drive->name);
 				failed++;
 			}
 	}
-	ide_unregister_module(&idescsi_driver);
 }
 
 module_init(init_idescsi_module);
diff -urN linux-2.5.6-pre1/drivers/scsi/qlogicfas.c linux-2.5.6-pre2/drivers/scsi/qlogicfas.c
--- linux-2.5.6-pre1/drivers/scsi/qlogicfas.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/drivers/scsi/qlogicfas.c	Thu Feb 28 13:34:22 2002
@@ -344,6 +344,7 @@
 unsigned int	reqlen; 		/* total length of transfer */
 struct scatterlist	*sglist;	/* scatter-gather list pointer */
 unsigned int	sgcount;		/* sg counter */
+char *buf;
 
 rtrc(1)
 	j = inb(qbase + 6);
@@ -391,7 +392,8 @@
 					REG0;
 					return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
 				}
-				if (ql_pdma(phase, sglist->address, sglist->length))
+				buf = page_address(sglist->page) + sglist->offset;
+				if (ql_pdma(phase, buf, sglist->length))
 					break;
 				sglist++;
 			}
diff -urN linux-2.5.6-pre1/drivers/usb/audio.c linux-2.5.6-pre2/drivers/usb/audio.c
--- linux-2.5.6-pre1/drivers/usb/audio.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/drivers/usb/audio.c	Thu Feb 28 13:34:22 2002
@@ -124,9 +124,7 @@
  * conversions. We never do sample rate conversion; these are too
  * expensive to be performed in the kernel.
  *
- * Current status:
- * - Pretty stable on UHCI-Acher/Fliegl/Sailer
- * - Does not work on OHCI due to lack of OHCI driver supporting URB's
+ * Current status: no known HCD-specific issues.
  *
  * Generally: Due to the brokenness of the Audio Class spec
  * it seems generally impossible to write a generic Audio Class driver,
@@ -298,12 +296,10 @@
 
 struct my_data_urb {
 	struct urb *urb;
-	struct usb_iso_packet_descriptor isoframe[DESCFRAMES];
 };
 
 struct my_sync_urb {
 	struct urb *urb;
-	struct usb_iso_packet_descriptor isoframe[SYNCFRAMES];
 };
 
 
@@ -2829,14 +2825,14 @@
 	init_waitqueue_head(&as->usbin.dma.wait);
 	init_waitqueue_head(&as->usbout.dma.wait);
 	spin_lock_init(&as->lock);
-	as->usbin.durb[0].urb = usb_alloc_urb(0, GFP_KERNEL);
-	as->usbin.durb[1].urb = usb_alloc_urb(0, GFP_KERNEL);
-	as->usbin.surb[0].urb = usb_alloc_urb(0, GFP_KERNEL);
-	as->usbin.surb[1].urb = usb_alloc_urb(0, GFP_KERNEL);
-	as->usbout.durb[0].urb = usb_alloc_urb(0, GFP_KERNEL);
-	as->usbout.durb[1].urb = usb_alloc_urb(0, GFP_KERNEL);
-	as->usbout.surb[0].urb = usb_alloc_urb(0, GFP_KERNEL);
-	as->usbout.surb[1].urb = usb_alloc_urb(0, GFP_KERNEL);
+	as->usbin.durb[0].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
+	as->usbin.durb[1].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
+	as->usbin.surb[0].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
+	as->usbin.surb[1].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
+	as->usbout.durb[0].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
+	as->usbout.durb[1].urb = usb_alloc_urb (DESCFRAMES, GFP_KERNEL);
+	as->usbout.surb[0].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
+	as->usbout.surb[1].urb = usb_alloc_urb (SYNCFRAMES, GFP_KERNEL);
 	if ((!as->usbin.durb[0].urb) ||
 	    (!as->usbin.durb[1].urb) ||
 	    (!as->usbin.surb[0].urb) ||
diff -urN linux-2.5.6-pre1/drivers/usb/auerswald.c linux-2.5.6-pre2/drivers/usb/auerswald.c
--- linux-2.5.6-pre1/drivers/usb/auerswald.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/drivers/usb/auerswald.c	Thu Feb 28 13:34:22 2002
@@ -61,7 +61,7 @@
 #define ID_AUERSWALD  	0x09BF
 
 #ifndef AUER_MINOR_BASE		/* allow external override */
-#define AUER_MINOR_BASE	80	/* auerswald driver minor number */
+#define AUER_MINOR_BASE	112	/* auerswald driver minor number */
 #endif
 
 /* we can have up to this number of device plugged in at once */
diff -urN linux-2.5.6-pre1/drivers/usb/devices.c linux-2.5.6-pre2/drivers/usb/devices.c
--- linux-2.5.6-pre1/drivers/usb/devices.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/drivers/usb/devices.c	Thu Feb 28 13:34:22 2002
@@ -4,8 +4,6 @@
  * (C) Copyright 1999,2000 Thomas Sailer <sailer@ife.ee.ethz.ch>. (proc file per device)
  * (C) Copyright 1999 Deti Fliegl (new USB architecture)
  *
- * $id$
- *
  * 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
@@ -61,6 +59,8 @@
 #include <linux/usbdevice_fs.h>
 #include <asm/uaccess.h>
 
+#include "hcd.h"
+
 #define MAX_TOPO_LEVEL		6
 
 /* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
@@ -429,6 +429,10 @@
 	 * count = device count at this level
 	 */
 	/* If this is the root hub, display the bandwidth information */
+	    /* FIXME high speed reserves 20% frametime for non-periodic,
+	     * while full/low speed reserves only 10% ... so this is wrong
+	     * for high speed busses.  also, change how bandwidth is recorded.
+	     */
 	if (level == 0)
 		data_end += sprintf(data_end, format_bandwidth, bus->bandwidth_allocated,
 				FRAME_TIME_MAX_USECS_ALLOC,
diff -urN linux-2.5.6-pre1/drivers/usb/hcd/ehci-hcd.c linux-2.5.6-pre2/drivers/usb/hcd/ehci-hcd.c
--- linux-2.5.6-pre1/drivers/usb/hcd/ehci-hcd.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/usb/hcd/ehci-hcd.c	Thu Feb 28 13:34:22 2002
@@ -44,6 +44,7 @@
 #include <linux/usb.h>
 #include "../hcd.h"
 
+#include <asm/byteorder.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
diff -urN linux-2.5.6-pre1/drivers/usb/hcd/ehci-hub.c linux-2.5.6-pre2/drivers/usb/hcd/ehci-hub.c
--- linux-2.5.6-pre1/drivers/usb/hcd/ehci-hub.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/drivers/usb/hcd/ehci-hub.c	Thu Feb 28 13:34:22 2002
@@ -18,8 +18,6 @@
 
 /* this file is part of ehci-hcd.c */
 
-#include <asm/byteorder.h>
-
 /*-------------------------------------------------------------------------*/
 
 /*
diff -urN linux-2.5.6-pre1/drivers/usb/hcd/ehci-mem.c linux-2.5.6-pre2/drivers/usb/hcd/ehci-mem.c
--- linux-2.5.6-pre1/drivers/usb/hcd/ehci-mem.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/usb/hcd/ehci-mem.c	Thu Feb 28 13:34:22 2002
@@ -18,8 +18,6 @@
 
 /* this file is part of ehci-hcd.c */
 
-#include <asm/byteorder.h>
-
 /*-------------------------------------------------------------------------*/
 
 /*
diff -urN linux-2.5.6-pre1/drivers/usb/hcd/ehci-q.c linux-2.5.6-pre2/drivers/usb/hcd/ehci-q.c
--- linux-2.5.6-pre1/drivers/usb/hcd/ehci-q.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/drivers/usb/hcd/ehci-q.c	Thu Feb 28 13:34:22 2002
@@ -18,8 +18,6 @@
 
 /* this file is part of ehci-hcd.c */
 
-#include <asm/byteorder.h>
-
 /*-------------------------------------------------------------------------*/
 
 /*
diff -urN linux-2.5.6-pre1/drivers/usb/hcd/ehci-sched.c linux-2.5.6-pre2/drivers/usb/hcd/ehci-sched.c
--- linux-2.5.6-pre1/drivers/usb/hcd/ehci-sched.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/drivers/usb/hcd/ehci-sched.c	Thu Feb 28 13:34:22 2002
@@ -20,8 +20,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-#include "ehci.h"
-
 /*
  * EHCI scheduled transaction support:  interrupt, iso, split iso
  * These are called "periodic" transactions in the EHCI spec.
@@ -395,6 +393,9 @@
 				frame += period;
 			} while (frame < ehci->periodic_size);
 
+			/* update bandwidth utilization records (for usbfs) */
+			usb_claim_bandwidth (urb->dev, urb, usecs, 0);
+
 			/* maybe enable periodic schedule processing */
 			if (!ehci->periodic_urbs++) {
 				u32	cmd;
diff -urN linux-2.5.6-pre1/drivers/usb/hcd/ohci-q.c linux-2.5.6-pre2/drivers/usb/hcd/ohci-q.c
--- linux-2.5.6-pre1/drivers/usb/hcd/ohci-q.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/usb/hcd/ohci-q.c	Thu Feb 28 13:34:22 2002
@@ -8,8 +8,6 @@
  * $Id: ohci-q.c,v 1.6 2002/01/19 00:23:15 dbrownell Exp $
  */
 
-#include <asm/byteorder.h>
- 
 static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
 {
 	int		last = urb_priv->length - 1;
diff -urN linux-2.5.6-pre1/drivers/usb/hcd.c linux-2.5.6-pre2/drivers/usb/hcd.c
--- linux-2.5.6-pre1/drivers/usb/hcd.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/usb/hcd.c	Thu Feb 28 13:34:22 2002
@@ -1,5 +1,11 @@
 /*
- * Copyright (c) 2001 by David Brownell
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
+ * (C) Copyright Deti Fliegl 1999
+ * (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000-2002
  * 
  * 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
@@ -33,9 +39,6 @@
 #include <linux/interrupt.h>
 #include <linux/uts.h>			/* for UTS_SYSNAME */
 
-#ifndef CONFIG_USB_DEBUG
-	#define CONFIG_USB_DEBUG	/* this is experimental! */
-#endif
 
 #ifdef CONFIG_USB_DEBUG
 	#define DEBUG
@@ -53,6 +56,8 @@
 #include <asm/byteorder.h>
 
 
+// #define USB_BANDWIDTH_MESSAGES
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -78,19 +83,28 @@
  * usb client device drivers.
  *
  * Contributors of ideas or unattributed patches include: David Brownell,
- * Roman Weissgaerber, Rory Bolt, ...
+ * Roman Weissgaerber, Rory Bolt, Greg Kroah-Hartman, ...
  *
  * HISTORY:
+ * 2002-02-21	Pull in most of the usb_bus support from usb.c; some
+ *		associated cleanup.  "usb_hcd" still != "usb_bus".
  * 2001-12-12	Initial patch version for Linux 2.5.1 kernel.
  */
 
 /*-------------------------------------------------------------------------*/
 
 /* host controllers we manage */
-static LIST_HEAD (hcd_list);
+LIST_HEAD (usb_bus_list);
+
+/* used when allocating bus numbers */
+#define USB_MAXBUS		64
+struct usb_busmap {
+	unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))];
+};
+static struct usb_busmap busmap;
 
 /* used when updating list of hcds */
-static DECLARE_MUTEX (hcd_list_lock);
+DECLARE_MUTEX (usb_bus_list_lock);	/* exported only for usbfs */
 
 /* used when updating hcd data */
 static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
@@ -105,6 +119,9 @@
 
 /*-------------------------------------------------------------------------*/
 
+#define KERNEL_REL	((LINUX_VERSION_CODE >> 16) & 0x0ff)
+#define KERNEL_VER	((LINUX_VERSION_CODE >> 8) & 0x0ff)
+
 /* usb 2.0 root hub device descriptor */
 static const u8 usb2_rh_dev_descriptor [18] = {
 	0x12,       /*  __u8  bLength; */
@@ -118,7 +135,7 @@
 
 	0x00, 0x00, /*  __u16 idVendor; */
  	0x00, 0x00, /*  __u16 idProduct; */
- 	0x40, 0x02, /*  __u16 bcdDevice; (v2.4) */
+	KERNEL_VER, KERNEL_REL, /*  __u16 bcdDevice */
 
 	0x03,       /*  __u8  iManufacturer; */
 	0x02,       /*  __u8  iProduct; */
@@ -141,7 +158,7 @@
 
 	0x00, 0x00, /*  __u16 idVendor; */
  	0x00, 0x00, /*  __u16 idProduct; */
- 	0x40, 0x02, /*  __u16 bcdDevice; (v2.4) */
+	KERNEL_VER, KERNEL_REL, /*  __u16 bcdDevice */
 
 	0x03,       /*  __u8  iManufacturer; */
 	0x02,       /*  __u8  iProduct; */
@@ -506,6 +523,346 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* exported only within usbcore */
+void usb_bus_get (struct usb_bus *bus)
+{
+	atomic_inc (&bus->refcnt);
+}
+
+/* exported only within usbcore */
+void usb_bus_put (struct usb_bus *bus)
+{
+	if (atomic_dec_and_test (&bus->refcnt))
+		kfree (bus);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* shared initialization code */
+static void usb_init_bus (struct usb_bus *bus)
+{
+	memset (&bus->devmap, 0, sizeof(struct usb_devmap));
+
+#ifdef DEVNUM_ROUND_ROBIN
+	bus->devnum_next = 1;
+#endif /* DEVNUM_ROUND_ROBIN */
+
+	bus->root_hub = NULL;
+	bus->hcpriv = NULL;
+	bus->busnum = -1;
+	bus->bandwidth_allocated = 0;
+	bus->bandwidth_int_reqs  = 0;
+	bus->bandwidth_isoc_reqs = 0;
+
+	INIT_LIST_HEAD (&bus->bus_list);
+
+	atomic_set (&bus->refcnt, 1);
+}
+
+/**
+ * usb_alloc_bus - creates a new USB host controller structure
+ * @op: pointer to a struct usb_operations that this bus structure should use
+ * Context: !in_interrupt()
+ *
+ * Creates a USB host controller bus structure with the specified 
+ * usb_operations and initializes all the necessary internal objects.
+ *
+ * If no memory is available, NULL is returned.
+ *
+ * The caller should call usb_free_bus() when it is finished with the structure.
+ */
+struct usb_bus *usb_alloc_bus (struct usb_operations *op)
+{
+	struct usb_bus *bus;
+
+	bus = kmalloc (sizeof *bus, GFP_KERNEL);
+	if (!bus)
+		return NULL;
+	usb_init_bus (bus);
+	bus->op = op;
+	return bus;
+}
+EXPORT_SYMBOL (usb_alloc_bus);
+
+/**
+ * usb_free_bus - frees the memory used by a bus structure
+ * @bus: pointer to the bus to free
+ *
+ * To be invoked by a HCD, only as the last step of decoupling from
+ * hardware.  It is an error to call this if the reference count is
+ * anything but one.  That would indicate that some system component
+ * did not correctly shut down, and thought the hardware was still
+ * accessible.
+ */
+void usb_free_bus (struct usb_bus *bus)
+{
+	if (!bus)
+		return;
+	if (atomic_read (&bus->refcnt) != 1)
+		err ("usb_free_bus #%d, count != 1", bus->busnum);
+	usb_bus_put (bus);
+}
+EXPORT_SYMBOL (usb_free_bus);
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_register_bus - registers the USB host controller with the usb core
+ * @bus: pointer to the bus to register
+ * Context: !in_interrupt()
+ *
+ * Assigns a bus number, and links the controller into usbcore data
+ * structures so that it can be seen by scanning the bus list.
+ */
+void usb_register_bus(struct usb_bus *bus)
+{
+	int busnum;
+
+	down (&usb_bus_list_lock);
+	busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
+	if (busnum < USB_MAXBUS) {
+		set_bit (busnum, busmap.busmap);
+		bus->busnum = busnum;
+	} else
+		warn ("too many buses");
+
+	usb_bus_get (bus);
+
+	/* Add it to the list of buses */
+	list_add (&bus->bus_list, &usb_bus_list);
+	up (&usb_bus_list_lock);
+
+	usbfs_add_bus (bus);
+
+	info ("new USB bus registered, assigned bus number %d", bus->busnum);
+}
+EXPORT_SYMBOL (usb_register_bus);
+
+/**
+ * usb_deregister_bus - deregisters the USB host controller
+ * @bus: pointer to the bus to deregister
+ * Context: !in_interrupt()
+ *
+ * Recycles the bus number, and unlinks the controller from usbcore data
+ * structures so that it won't be seen by scanning the bus list.
+ */
+void usb_deregister_bus (struct usb_bus *bus)
+{
+	info ("USB bus %d deregistered", bus->busnum);
+
+	/*
+	 * NOTE: make sure that all the devices are removed by the
+	 * controller code, as well as having it call this when cleaning
+	 * itself up
+	 */
+	down (&usb_bus_list_lock);
+	list_del (&bus->bus_list);
+	up (&usb_bus_list_lock);
+
+	usbfs_remove_bus (bus);
+
+	clear_bit (bus->busnum, busmap.busmap);
+
+	usb_bus_put (bus);
+}
+EXPORT_SYMBOL (usb_deregister_bus);
+
+/**
+ * usb_register_root_hub - called by HCD to register its root hub 
+ * @usb_dev: the usb root hub device to be registered.
+ * @parent_dev: the parent device of this root hub.
+ *
+ * The USB host controller calls this function to register the root hub
+ * properly with the USB subsystem.  It sets up the device properly in
+ * the driverfs tree, and then calls usb_new_device() to register the
+ * usb device.
+ */
+int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev)
+{
+	int retval;
+
+	usb_dev->dev.parent = parent_dev;
+	strcpy (&usb_dev->dev.name[0], "usb_name");
+	strcpy (&usb_dev->dev.bus_id[0], "usb_bus");
+	retval = usb_new_device (usb_dev);
+	if (retval)
+		put_device (&usb_dev->dev);
+	return retval;
+}
+EXPORT_SYMBOL (usb_register_root_hub);
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * usb_calc_bus_time:
+ * Returns approximate bus time in nanoseconds for a periodic transaction.
+ * See USB 2.0 spec section 5.11.3
+ */
+static long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
+{
+	unsigned long	tmp;
+
+	switch (speed) {
+	case USB_SPEED_LOW: 	/* INTR only */
+		if (is_input) {
+			tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L;
+			return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
+		} else {
+			tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L;
+			return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
+		}
+	case USB_SPEED_FULL:	/* ISOC or INTR */
+		if (isoc) {
+			tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
+			return (((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);
+		} else {
+			tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
+			return (9107L + BW_HOST_DELAY + tmp);
+		}
+	case USB_SPEED_HIGH:	/* ISOC or INTR */
+		// FIXME merge from EHCI code; caller will need to handle
+		// each part of a split separately.
+		return 0;
+	default:
+		dbg ("bogus device speed!");
+		return -1;
+	}
+}
+
+/*
+ * usb_check_bandwidth():
+ *
+ * old_alloc is from host_controller->bandwidth_allocated in microseconds;
+ * bustime is from calc_bus_time(), but converted to microseconds.
+ *
+ * returns <bustime in us> if successful,
+ * or -ENOSPC if bandwidth request fails.
+ *
+ * FIXME:
+ * This initial implementation does not use Endpoint.bInterval
+ * in managing bandwidth allocation.
+ * It probably needs to be expanded to use Endpoint.bInterval.
+ * This can be done as a later enhancement (correction).
+ *
+ * This will also probably require some kind of
+ * frame allocation tracking...meaning, for example,
+ * that if multiple drivers request interrupts every 10 USB frames,
+ * they don't all have to be allocated at
+ * frame numbers N, N+10, N+20, etc.  Some of them could be at
+ * N+11, N+21, N+31, etc., and others at
+ * N+12, N+22, N+32, etc.
+ *
+ * Similarly for isochronous transfers...
+ *
+ * Individual HCDs can schedule more directly ... this logic
+ * is not correct for high speed transfers.
+ */
+int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
+{
+	unsigned int	pipe = urb->pipe;
+	long		bustime;
+	int		is_in = usb_pipein (pipe);
+	int		is_iso = usb_pipeisoc (pipe);
+	int		old_alloc = dev->bus->bandwidth_allocated;
+	int		new_alloc;
+
+
+	bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso,
+			usb_maxpacket (dev, pipe, !is_in)));
+	if (is_iso)
+		bustime /= urb->number_of_packets;
+
+	new_alloc = old_alloc + (int) bustime;
+	if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) {
+#ifdef	DEBUG
+		char	*mode = 
+#ifdef CONFIG_USB_BANDWIDTH
+			"";
+#else
+			"would have ";
+#endif
+		dbg ("usb_check_bandwidth %sFAILED: %d + %ld = %d usec",
+			mode, old_alloc, bustime, new_alloc);
+#endif
+#ifdef CONFIG_USB_BANDWIDTH
+		bustime = -ENOSPC;	/* report error */
+#endif
+	}
+
+	return bustime;
+}
+EXPORT_SYMBOL (usb_check_bandwidth);
+
+
+/**
+ * usb_claim_bandwidth - records bandwidth for a periodic transfer
+ * @dev: source/target of request
+ * @urb: request (urb->dev == dev)
+ * @bustime: bandwidth consumed, in (average) microseconds per frame
+ * @isoc: true iff the request is isochronous
+ *
+ * Bus bandwidth reservations are recorded purely for diagnostic purposes.
+ * HCDs are expected not to overcommit periodic bandwidth, and to record such
+ * reservations whenever endpoints are added to the periodic schedule.
+ *
+ * FIXME averaging per-frame is suboptimal.  Better to sum over the HCD's
+ * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable
+ * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how
+ * large its periodic schedule is.
+ */
+void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
+{
+	dev->bus->bandwidth_allocated += bustime;
+	if (isoc)
+		dev->bus->bandwidth_isoc_reqs++;
+	else
+		dev->bus->bandwidth_int_reqs++;
+	urb->bandwidth = bustime;
+
+#ifdef USB_BANDWIDTH_MESSAGES
+	dbg ("bandwidth alloc increased by %d (%s) to %d for %d requesters",
+		bustime,
+		isoc ? "ISOC" : "INTR",
+		dev->bus->bandwidth_allocated,
+		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
+#endif
+}
+EXPORT_SYMBOL (usb_claim_bandwidth);
+
+
+/**
+ * usb_release_bandwidth - reverses effect of usb_claim_bandwidth()
+ * @dev: source/target of request
+ * @urb: request (urb->dev == dev)
+ * @isoc: true iff the request is isochronous
+ *
+ * This records that previously allocated bandwidth has been released.
+ * Bandwidth is released when endpoints are removed from the host controller's
+ * periodic schedule.
+ */
+void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)
+{
+	dev->bus->bandwidth_allocated -= urb->bandwidth;
+	if (isoc)
+		dev->bus->bandwidth_isoc_reqs--;
+	else
+		dev->bus->bandwidth_int_reqs--;
+
+#ifdef USB_BANDWIDTH_MESSAGES
+	dbg ("bandwidth alloc reduced by %d (%s) to %d for %d requesters",
+		urb->bandwidth,
+		isoc ? "ISOC" : "INTR",
+		dev->bus->bandwidth_allocated,
+		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
+#endif
+	urb->bandwidth = 0;
+}
+EXPORT_SYMBOL (usb_release_bandwidth);
+
+
+/*-------------------------------------------------------------------------*/
+
 #ifdef CONFIG_PCI
 
 /* PCI-based HCs are normal, but custom bus glue should be ok */
@@ -522,6 +879,7 @@
  * usb_hcd_pci_probe - initialize PCI-based HCDs
  * @dev: USB Host Controller being probed
  * @id: pci hotplug id connecting controller to HCD framework
+ * Context: !in_interrupt()
  *
  * Allocates basic PCI resources for this USB host controller, and
  * then invokes the start() method for the HCD associated with it
@@ -535,7 +893,6 @@
 	unsigned long		resource, len;
 	void			*base;
 	u8			latency, limit;
-	struct usb_bus		*bus;
 	struct usb_hcd		*hcd;
 	int			retval, region;
 	char			buf [8], *bufp = buf;
@@ -631,7 +988,6 @@
 			!= 0) {
 		err ("request interrupt %s failed", bufp);
 		retval = -EBUSY;
-clean_3:
 		driver->hcd_free (hcd);
 		goto clean_2;
 	}
@@ -643,26 +999,15 @@
 		(driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
 		base);
 
-// FIXME simpler: make "bus" be that data, not pointer to it.
-	bus = usb_alloc_bus (&hcd_operations);
-	if (bus == NULL) {
-		dbg ("usb_alloc_bus fail");
-		retval = -ENOMEM;
-		free_irq (dev->irq, hcd);
-		goto clean_3;
-	}
-	hcd->bus = bus;
+	usb_init_bus (&hcd->self);
+	hcd->self.op = &hcd_operations;
+	hcd->self.hcpriv = (void *) hcd;
+	hcd->bus = &hcd->self;
 	hcd->bus_name = dev->slot_name;
-	bus->hcpriv = (void *) hcd;
 
 	INIT_LIST_HEAD (&hcd->dev_list);
-	INIT_LIST_HEAD (&hcd->hcd_list);
 
-	down (&hcd_list_lock);
-	list_add (&hcd->hcd_list, &hcd_list);
-	up (&hcd_list_lock);
-
-	usb_register_bus (bus);
+	usb_register_bus (&hcd->self);
 
 	if ((retval = driver->start (hcd)) < 0)
 		usb_hcd_pci_remove (dev);
@@ -678,6 +1023,7 @@
 /**
  * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
  * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
  *
  * Reverses the effect of usb_hcd_pci_probe(), first invoking
  * the HCD's stop() method.  It is always called from a thread
@@ -717,12 +1063,9 @@
 			pci_resource_len (dev, hcd->region));
 	}
 
-	down (&hcd_list_lock);
-	list_del (&hcd->hcd_list);
-	up (&hcd_list_lock);
-
 	usb_deregister_bus (hcd->bus);
-	usb_free_bus (hcd->bus);
+	if (atomic_read (&hcd->self.refcnt) != 1)
+		err ("usb_hcd_pci_remove %s, count != 1", hcd->bus_name);
 	hcd->bus = NULL;
 
 	hcd->driver->hcd_free (hcd);
@@ -1257,6 +1600,7 @@
  * usb_hcd_giveback_urb - return URB from HCD to device driver
  * @hcd: host controller returning the URB
  * @urb: urb being returned to the USB device driver.
+ * Context: in_interrupt()
  *
  * This hands the URB from HCD to its USB device driver, using its
  * completion function.  The HCD has freed all per-urb resources
@@ -1279,16 +1623,9 @@
 	struct usb_device	*dev;
 
 	/* Release periodic transfer bandwidth */
-	if (urb->bandwidth) {
-		switch (usb_pipetype (urb->pipe)) {
-		case PIPE_INTERRUPT:
-			usb_release_bandwidth (urb->dev, urb, 0);
-			break;
-		case PIPE_ISOCHRONOUS:
-			usb_release_bandwidth (urb->dev, urb, 1);
-			break;
-		}
-	}
+	if (urb->bandwidth)
+		usb_release_bandwidth (urb->dev, urb,
+			usb_pipeisoc (urb->pipe));
 
 	/* clear all state linking urb to this dev (and hcd) */
 
diff -urN linux-2.5.6-pre1/drivers/usb/hcd.h linux-2.5.6-pre2/drivers/usb/hcd.h
--- linux-2.5.6-pre1/drivers/usb/hcd.h	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/drivers/usb/hcd.h	Thu Feb 28 13:34:22 2002
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2001 by David Brownell
- * 
+ * Copyright (c) 2001-2002 by David Brownell
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2 of the License, or (at your
@@ -17,6 +17,8 @@
  */
 
 
+#ifdef __KERNEL__
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -33,8 +35,8 @@
 	/*
 	 * housekeeping
 	 */
-	struct usb_bus		*bus;		/* hcd is-a bus */
-	struct list_head	hcd_list;
+	struct usb_bus		*bus;		/* FIXME only use "self" */
+	struct usb_bus		self;		/* hcd is-a bus */
 
 	const char		*bus_name;
 
@@ -98,6 +100,19 @@
 
 /*-------------------------------------------------------------------------*/
 
+/*
+ * FIXME usb_operations should vanish or become hc_driver,
+ * when usb_bus and usb_hcd become the same thing.
+ */
+
+struct usb_operations {
+	int (*allocate)(struct usb_device *);
+	int (*deallocate)(struct usb_device *);
+	int (*get_frame_number) (struct usb_device *usb_dev);
+	int (*submit_urb) (struct urb *urb, int mem_flags);
+	int (*unlink_urb) (struct urb *urb);
+};
+
 /* each driver provides one of these, and hardware init support */
 
 struct hc_driver {
@@ -126,8 +141,6 @@
 	/* return current frame number */
 	int	(*get_frame_number) (struct usb_hcd *hcd);
 
-// FIXME: rework generic-to-specific HCD linkage (specific contains generic)
-
 	/* memory lifecycle */
 	struct usb_hcd	*(*hcd_alloc) (void);
 	void		(*hcd_free) (struct usb_hcd *hcd);
@@ -152,7 +165,8 @@
 extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
 
 #ifdef CONFIG_PCI
-
+struct pci_dev;
+struct pci_device_id;
 extern int usb_hcd_pci_probe (struct pci_dev *dev,
 				const struct pci_device_id *id);
 extern void usb_hcd_pci_remove (struct pci_dev *dev);
@@ -206,6 +220,59 @@
 
 /*-------------------------------------------------------------------------*/
 
+/*
+ * Generic bandwidth allocation constants/support
+ */
+#define FRAME_TIME_USECS	1000L
+#define BitTime(bytecount)  (7 * 8 * bytecount / 6)  /* with integer truncation */
+		/* Trying not to use worst-case bit-stuffing
+                   of (7/6 * 8 * bytecount) = 9.33 * bytecount */
+		/* bytecount = data payload byte count */
+
+#define NS_TO_US(ns)	((ns + 500L) / 1000L)
+			/* convert & round nanoseconds to microseconds */
+
+extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb,
+		int bustime, int isoc);
+extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
+		int isoc);
+
+/*
+ * Full/low speed bandwidth allocation constants/support.
+ */
+#define BW_HOST_DELAY	1000L		/* nanoseconds */
+#define BW_HUB_LS_SETUP	333L		/* nanoseconds */
+                        /* 4 full-speed bit times (est.) */
+
+#define FRAME_TIME_BITS         12000L		/* frame = 1 millisecond */
+#define FRAME_TIME_MAX_BITS_ALLOC	(90L * FRAME_TIME_BITS / 100L)
+#define FRAME_TIME_MAX_USECS_ALLOC	(90L * FRAME_TIME_USECS / 100L)
+
+extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
+
+/*-------------------------------------------------------------------------*/
+
+extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
+extern void usb_free_bus (struct usb_bus *);
+
+extern void usb_register_bus (struct usb_bus *);
+extern void usb_deregister_bus (struct usb_bus *);
+
+extern int usb_register_root_hub (struct usb_device *usb_dev,
+		struct device *parent_dev);
+
+/*-------------------------------------------------------------------------*/
+
+/* exported only within usbcore */
+
+extern struct list_head usb_bus_list;
+extern struct semaphore usb_bus_list_lock;
+
+extern void usb_bus_get (struct usb_bus *bus);
+extern void usb_bus_put (struct usb_bus *bus);
+
+/*-------------------------------------------------------------------------*/
+
 /* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */
 // bleech -- resurfaced in 2.4.11 or 2.4.12
 #define bitmap 	DeviceRemovable
@@ -217,3 +284,7 @@
 
 #define	RUN_CONTEXT (in_irq () ? "in_irq" \
 		: (in_interrupt () ? "in_interrupt" : "can sleep"))
+
+
+#endif /* __KERNEL__ */
+
diff -urN linux-2.5.6-pre1/drivers/usb/hid-core.c linux-2.5.6-pre2/drivers/usb/hid-core.c
--- linux-2.5.6-pre1/drivers/usb/hid-core.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/usb/hid-core.c	Thu Feb 28 13:34:22 2002
@@ -1452,7 +1452,8 @@
 }
 
 static struct usb_device_id hid_usb_ids [] = {
-	{ bInterfaceClass: USB_INTERFACE_CLASS_HID },
+	{ match_flags: USB_DEVICE_ID_MATCH_INT_CLASS,
+	    bInterfaceClass: USB_INTERFACE_CLASS_HID },
 	{ }						/* Terminating entry */
 };
 
diff -urN linux-2.5.6-pre1/drivers/usb/serial/Config.help linux-2.5.6-pre2/drivers/usb/serial/Config.help
--- linux-2.5.6-pre1/drivers/usb/serial/Config.help	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/Config.help	Thu Feb 28 13:34:22 2002
@@ -40,9 +40,10 @@
   module, say M here and read <file:Documentation/modules.txt>.
 
 CONFIG_USB_SERIAL_IPAQ
-  Say Y here if you want to connect to your Compaq iPAQ running
-  Windows CE 3.0 using a USB autosync cable. For information on using
-  the driver, read <file:Documentation/usb/usb-serial.txt>.
+  Say Y here if you want to connect to your Compaq iPAQ or HP Jornada
+  548/568 running Windows CE 3.0 or PocketPC 2002 using a USB
+  cradle/cable. For information on using the driver,
+  read <file:Documentation/usb/usb-serial.txt>.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
diff -urN linux-2.5.6-pre1/drivers/usb/serial/Config.in linux-2.5.6-pre2/drivers/usb/serial/Config.in
--- linux-2.5.6-pre1/drivers/usb/serial/Config.in	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/Config.in	Thu Feb 28 13:34:22 2002
@@ -15,7 +15,7 @@
 dep_tristate '  USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Handspring Visor / Palm m50x / Sony Clie Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
-dep_tristate '  USB Compaq iPAQ Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL
+dep_tristate '  USB Compaq iPAQ / HP Jornada Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL
 dep_tristate '  USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
diff -urN linux-2.5.6-pre1/drivers/usb/serial/belkin_sa.c linux-2.5.6-pre2/drivers/usb/serial/belkin_sa.c
--- linux-2.5.6-pre1/drivers/usb/serial/belkin_sa.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/belkin_sa.c	Thu Feb 28 13:34:22 2002
@@ -207,8 +207,6 @@
 
 	dbg(__FUNCTION__" port %d", port->number);
 
-	down (&port->sem);
-	
 	++port->open_count;
 	
 	if (port->open_count == 1) {
@@ -230,8 +228,6 @@
 	}
 	
 exit:
-	up (&port->sem);
-
 	return retval;
 } /* belkin_sa_open */
 
@@ -249,8 +245,6 @@
 
 	dbg(__FUNCTION__" port %d", port->number);
 
-	down (&port->sem);
-
 	--port->open_count;
 
 	if (port->open_count <= 0) {
@@ -262,8 +256,6 @@
 		}
 		port->open_count = 0;
 	}
-	
-	up (&port->sem);
 } /* belkin_sa_close */
 
 
diff -urN linux-2.5.6-pre1/drivers/usb/serial/cyberjack.c linux-2.5.6-pre2/drivers/usb/serial/cyberjack.c
--- linux-2.5.6-pre1/drivers/usb/serial/cyberjack.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/cyberjack.c	Thu Feb 28 13:34:22 2002
@@ -151,8 +151,6 @@
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	down (&port->sem);
-
 	++port->open_count;
 
 	if (port->open_count == 1) {
@@ -179,8 +177,6 @@
 		dbg(__FUNCTION__ " - usb_submit_urb(int urb)");
 	}
 
-	up (&port->sem);
-
 	return result;
 }
 
@@ -188,8 +184,6 @@
 {
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	down (&port->sem);
-
 	--port->open_count;
 
 	if (port->open_count <= 0) {
@@ -201,8 +195,6 @@
 		}
 		port->open_count = 0;
 	}
-
-	up (&port->sem);
 }
 
 static int cyberjack_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
@@ -225,8 +217,6 @@
 		return (0);
 	}
 
-	down (&port->sem);
-
 	if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ) {
 		/* To much data  for buffer. Reset buffer. */
 		priv->wrfilled=0;
@@ -235,8 +225,9 @@
 
 	/* Copy data */
 	if (from_user) {
-		if (copy_from_user(priv->wrbuf+priv->wrfilled, buf, count))
+		if (copy_from_user(priv->wrbuf+priv->wrfilled, buf, count)) {
 			return -EFAULT;
+		}
 	} else {
 		memcpy (priv->wrbuf+priv->wrfilled, buf, count);
 	}  
@@ -277,7 +268,6 @@
 			/* Throw away data. No better idea what to do with it. */
 			priv->wrfilled=0;
 			priv->wrsent=0;
-			up (&port->sem);
 			return 0;
 		}
 
@@ -292,7 +282,6 @@
 		}
 	}
 
-	up (&port->sem);
 	return (count);
 } 
 
@@ -432,8 +421,6 @@
 			return;
 		}
 
-		down (&port->sem);
-
 		dbg(__FUNCTION__ " - transmitting data (frame n)");
 
 		length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ?
@@ -459,7 +446,6 @@
 			/* Throw away data. No better idea what to do with it. */
 			priv->wrfilled=0;
 			priv->wrsent=0;
-			up (&port->sem);
 			queue_task(&port->tqueue, &tq_immediate);
 			mark_bh(IMMEDIATE_BH);
 			return;
@@ -477,7 +463,6 @@
 			priv->wrsent=0;
 		}
 
-		up (&port->sem);
 		queue_task(&port->tqueue, &tq_immediate);
 		mark_bh(IMMEDIATE_BH);
 		return;
diff -urN linux-2.5.6-pre1/drivers/usb/serial/empeg.c linux-2.5.6-pre2/drivers/usb/serial/empeg.c
--- linux-2.5.6-pre1/drivers/usb/serial/empeg.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/empeg.c	Thu Feb 28 13:34:22 2002
@@ -157,8 +157,6 @@
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	down (&port->sem);
-
 	++port->open_count;
 
 	if (port->open_count == 1) {
@@ -189,8 +187,6 @@
 
 	}
 
-	up (&port->sem);
-
 	return result;
 }
 
@@ -208,8 +204,6 @@
 	if (!serial)
 		return;
 
-	down (&port->sem);
-
 	--port->open_count;
 
 	if (port->open_count <= 0) {
@@ -220,8 +214,6 @@
 		port->open_count = 0;
 	}
 
-	up (&port->sem);
-
 	/* Uncomment the following line if you want to see some statistics in your syslog */
 	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
 }
@@ -462,15 +454,7 @@
 static void empeg_throttle (struct usb_serial_port *port)
 {
 	dbg(__FUNCTION__ " - port %d", port->number);
-
-	down (&port->sem);
-
 	usb_unlink_urb (port->read_urb);
-
-	up (&port->sem);
-
-	return;
-
 }
 
 
@@ -480,8 +464,6 @@
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	down (&port->sem);
-
 	port->read_urb->dev = port->serial->dev;
 
 	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
@@ -489,10 +471,7 @@
 	if (result)
 		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 
-	up (&port->sem);
-
 	return;
-
 }
 
 
diff -urN linux-2.5.6-pre1/drivers/usb/serial/ftdi_sio.c linux-2.5.6-pre2/drivers/usb/serial/ftdi_sio.c
--- linux-2.5.6-pre1/drivers/usb/serial/ftdi_sio.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/ftdi_sio.c	Thu Feb 28 13:34:22 2002
@@ -319,8 +319,6 @@
 
 	dbg(__FUNCTION__);
 
-	down (&port->sem);
-	
 	++port->open_count;
 
 	if (port->open_count == 1){
@@ -361,7 +359,6 @@
 			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 	}
 
-	up (&port->sem);
 	return result;
 } /* ftdi_sio_open */
 
@@ -374,7 +371,6 @@
 
 	dbg( __FUNCTION__);
 
-	down (&port->sem);
 	--port->open_count;
 
 	if (port->open_count <= 0) {
@@ -411,9 +407,6 @@
 			tty_hangup(port->tty);
 		}
 	}
-
-	up (&port->sem);
-
 } /* ftdi_sio_close */
 
 
@@ -447,8 +440,6 @@
 		return (0);
 	}		
 
-	down(&port->sem);
-
 	count += data_offset;
 	count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
 
@@ -456,7 +447,6 @@
 	if (from_user) {
 		if (copy_from_user(port->write_urb->transfer_buffer + data_offset,
 				   buf, count - data_offset )){
-			up (&port->sem);
 			return -EFAULT;
 		}
 	} else {
@@ -482,14 +472,11 @@
 	result = usb_submit_urb(port->write_urb, GFP_KERNEL);
 	if (result) {
 		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
-		up (&port->sem);
 		return 0;
 	}
-	up (&port->sem);
 
 	dbg(__FUNCTION__ " write returning: %d", count - data_offset);
 	return (count - data_offset);
-
 } /* ftdi_sio_write */
 
 static void ftdi_sio_write_bulk_callback (struct urb *urb)
diff -urN linux-2.5.6-pre1/drivers/usb/serial/ipaq.c linux-2.5.6-pre2/drivers/usb/serial/ipaq.c
--- linux-2.5.6-pre1/drivers/usb/serial/ipaq.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/ipaq.c	Thu Feb 28 13:34:22 2002
@@ -1,7 +1,7 @@
 /*
  * USB Compaq iPAQ driver
  *
- *	Copyright (C) 2001
+ *	Copyright (C) 2001 - 2002
  *	    Ganesh Varadarajan <ganesh@veritas.com>
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -9,6 +9,9 @@
  *	the Free Software Foundation; either version 2 of the License, or
  *	(at your option) any later version.
  *
+ * (25/2/2002) ganesh
+ * 	Added support for the HP Jornada 548 and 568. Completely untested.
+ * 	Thanks to info from Heath Robinson and Arieh Davidoff.
  */
 
 #include <linux/config.h>
@@ -39,9 +42,9 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.1"
+#define DRIVER_VERSION "v0.2"
 #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>"
-#define DRIVER_DESC "USB Compaq iPAQ driver"
+#define DRIVER_DESC "USB Compaq iPAQ, HP Jornada driver"
 
 /* Function prototypes for an ipaq */
 static int  ipaq_open (struct usb_serial_port *port, struct file *filp);
@@ -61,7 +64,9 @@
 
 
 static __devinitdata struct usb_device_id ipaq_id_table [] = {
-	{ USB_DEVICE(IPAQ_VENDOR_ID, IPAQ_PRODUCT_ID) },
+	{ USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) },
+	{ USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -72,7 +77,7 @@
 	owner:			THIS_MODULE,
 	name:			"Compaq iPAQ",
 	id_table:		ipaq_id_table,
-	num_interrupt_in:	0,
+	num_interrupt_in:	NUM_DONT_CARE,
 	num_bulk_in:		1,
 	num_bulk_out:		1,
 	num_ports:		1,
@@ -104,8 +109,6 @@
 	
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	down(&port->sem);
-	
 	++port->open_count;
 	
 	if (port->open_count == 1) {
@@ -193,8 +196,6 @@
 		}
 	}
 	
-	up(&port->sem);
-	
 	return result;
 
 enomem:
@@ -219,8 +220,6 @@
 	serial = get_usb_serial(port, __FUNCTION__);
 	if (!serial)
 		return;
-	
-	down (&port->sem);
 
 	--port->open_count;
 
@@ -238,8 +237,6 @@
 		port->open_count = 0;
 
 	}
-	up (&port->sem);
-
 	/* Uncomment the following line if you want to see some statistics in your syslog */
 	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
 }
diff -urN linux-2.5.6-pre1/drivers/usb/serial/ipaq.h linux-2.5.6-pre2/drivers/usb/serial/ipaq.h
--- linux-2.5.6-pre1/drivers/usb/serial/ipaq.h	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/ipaq.h	Thu Feb 28 13:34:22 2002
@@ -1,7 +1,7 @@
 /*
  * USB Compaq iPAQ driver
  *
- *	Copyright (C) 2001
+ *	Copyright (C) 2001 - 2002
  *	    Ganesh Varadarajan <ganesh@veritas.com>
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -16,8 +16,12 @@
 #define __LINUX_USB_SERIAL_IPAQ_H
 
 
-#define IPAQ_VENDOR_ID			0x049f
-#define IPAQ_PRODUCT_ID			0x0003
+#define COMPAQ_VENDOR_ID	0x049f
+#define COMPAQ_IPAQ_ID		0x0003
+
+#define HP_VENDOR_ID		0x003f
+#define HP_JORNADA_548_ID	0x1016
+#define HP_JORNADA_568_ID	0x1116
 
 /*
  * Since we can't queue our bulk write urbs (don't know why - it just
diff -urN linux-2.5.6-pre1/drivers/usb/serial/ir-usb.c linux-2.5.6-pre2/drivers/usb/serial/ir-usb.c
--- linux-2.5.6-pre1/drivers/usb/serial/ir-usb.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/ir-usb.c	Thu Feb 28 13:34:22 2002
@@ -252,8 +252,6 @@
 	
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	down (&port->sem);
-	
 	++port->open_count;
 	
 	if (port->open_count == 1) {
@@ -293,9 +291,6 @@
 		if (result)
 			err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
 	}
-	
-	up (&port->sem);
-	
 	return result;
 }
 
@@ -312,8 +307,6 @@
 	if (!serial)
 		return;
 	
-	down (&port->sem);
-
 	--port->open_count;
 
 	if (port->open_count <= 0) {
@@ -324,7 +317,6 @@
 		port->open_count = 0;
 
 	}
-	up (&port->sem);
 }
 
 static int ir_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
diff -urN linux-2.5.6-pre1/drivers/usb/serial/keyspan.c linux-2.5.6-pre2/drivers/usb/serial/keyspan.c
--- linux-2.5.6-pre1/drivers/usb/serial/keyspan.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/keyspan.c	Thu Feb 28 13:34:22 2002
@@ -861,10 +861,8 @@
 	
 	dbg("keyspan_open called for port%d.\n", port->number); 
 
-	down (&port->sem);
 	already_active = port->open_count;
 	++port->open_count;
-	up (&port->sem);
 
 	if (already_active)
 		return 0;
@@ -926,8 +924,6 @@
 	p_priv->out_flip = 0;
 	p_priv->in_flip = 0;
 
-	down (&port->sem);
-
 	if (--port->open_count <= 0) {
 		if (serial->dev) {
 			/* Stop reading/writing urbs */
@@ -941,7 +937,6 @@
 		port->open_count = 0;
 		port->tty = 0;
 	}
-	up (&port->sem);
 }
 
 
diff -urN linux-2.5.6-pre1/drivers/usb/serial/keyspan_pda.c linux-2.5.6-pre2/drivers/usb/serial/keyspan_pda.c
--- linux-2.5.6-pre1/drivers/usb/serial/keyspan_pda.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/keyspan_pda.c	Thu Feb 28 13:34:22 2002
@@ -662,8 +662,6 @@
 	int rc = 0;
 	struct keyspan_pda_private *priv;
 
-	down (&port->sem);
-
 	++port->open_count;
 
 	if (port->open_count == 1) {
@@ -707,12 +705,9 @@
 
 	}
 
-
-	up (&port->sem);
 	return rc;
 error:
 	--port->open_count;
-	up (&port->sem);
 	return rc;
 }
 
@@ -721,8 +716,6 @@
 {
 	struct usb_serial *serial = port->serial;
 
-	down (&port->sem);
-
 	--port->open_count;
 
 	if (port->open_count <= 0) {
@@ -737,8 +730,6 @@
 		}
 		port->open_count = 0;
 	}
-
-	up (&port->sem);
 }
 
 
diff -urN linux-2.5.6-pre1/drivers/usb/serial/kl5kusb105.c linux-2.5.6-pre2/drivers/usb/serial/kl5kusb105.c
--- linux-2.5.6-pre1/drivers/usb/serial/kl5kusb105.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/kl5kusb105.c	Thu Feb 28 13:34:22 2002
@@ -358,8 +358,6 @@
 
 	dbg(__FUNCTION__" port %d", port->number);
 
-	down (&port->sem);
-	
 	++port->open_count;
 
 	if (port->open_count == 1) {
@@ -437,8 +435,6 @@
 	}
 
 exit:
-	up (&port->sem);
-	
 	return retval;
 } /* klsi_105_open */
 
@@ -455,8 +451,6 @@
 	if(!serial)
 		return;
 
-	down (&port->sem);
-
 	--port->open_count;
 
 	if (port->open_count <= 0) {
@@ -482,8 +476,6 @@
 		port->open_count = 0;
 		info("kl5kusb105 port stats: %ld bytes in, %ld bytes out", priv->bytes_in, priv->bytes_out);
 	}
-	
-	up (&port->sem);
 } /* klsi_105_close */
 
 
@@ -505,9 +497,6 @@
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	down (&port->sem);	/* to lock against someone else trying to
-				   take an URB we just selected from the pool */
-
 	while (count > 0) {
 		/* try to find a free urb (write 0 bytes if none) */
 		struct urb *urb = NULL;
@@ -543,7 +532,6 @@
 		if (from_user) {
 			if (copy_from_user(urb->transfer_buffer
 					   + KLSI_105_DATA_OFFSET, buf, size)) {
-				up (&port->sem);
 				return -EFAULT;
 			}
 		} else {
@@ -578,7 +566,6 @@
 		count -= size;
 	}
 exit:
-	up (&port->sem);
 	priv->bytes_out+=bytes_sent;
 
 	return bytes_sent;	/* that's how much we wrote */
@@ -1021,34 +1008,21 @@
 
 static void klsi_105_throttle (struct usb_serial_port *port)
 {
-
 	dbg(__FUNCTION__ " - port %d", port->number);
-
-	down (&port->sem);
-
 	usb_unlink_urb (port->read_urb);
-
-	up (&port->sem);
-
-	return;
 }
+
 static void klsi_105_unthrottle (struct usb_serial_port *port)
 {
 	int result;
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	down (&port->sem);
-
 	port->read_urb->dev = port->serial->dev;
 	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 	if (result)
 		err(__FUNCTION__ " - failed submitting read urb, error %d",
 		    result);
-
-	up (&port->sem);
-
-	return;
 }
 
 
diff -urN linux-2.5.6-pre1/drivers/usb/serial/mct_u232.c linux-2.5.6-pre2/drivers/usb/serial/mct_u232.c
--- linux-2.5.6-pre1/drivers/usb/serial/mct_u232.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/mct_u232.c	Thu Feb 28 13:34:22 2002
@@ -341,8 +341,6 @@
 
 	dbg(__FUNCTION__" port %d", port->number);
 
-	down (&port->sem);
-	
 	++port->open_count;
 
 	if (port->open_count == 1) {
@@ -398,8 +396,6 @@
 	}
 
 exit:
-	up (&port->sem);
-	
 	return 0;
 } /* mct_u232_open */
 
@@ -408,8 +404,6 @@
 {
 	dbg(__FUNCTION__" port %d", port->number);
 
-	down (&port->sem);
-
 	--port->open_count;
 
 	if (port->open_count <= 0) {
@@ -421,8 +415,6 @@
 		}
 		port->open_count = 0;
 	}
-	
-	up (&port->sem);
 } /* mct_u232_close */
 
 
@@ -454,16 +446,12 @@
 		
 	bytes_sent = 0;
 	while (count > 0) {
-		
-		down (&port->sem);
-		
 		size = (count > port->bulk_out_size) ? port->bulk_out_size : count;
 		
 		usb_serial_debug_data (__FILE__, __FUNCTION__, size, buf);
 		
 		if (from_user) {
 			if (copy_from_user(port->write_urb->transfer_buffer, buf, size)) {
-				up (&port->sem);
 				return -EFAULT;
 			}
 		}
@@ -486,12 +474,9 @@
 		if (result) {
 			err(__FUNCTION__
 			    " - failed submitting write urb, error %d", result);
-			up (&port->sem);
 			return result;
 		}
 
-		up (&port->sem);
-
 		bytes_sent += size;
 		if (write_blocking)
 			interruptible_sleep_on(&port->write_wait);
diff -urN linux-2.5.6-pre1/drivers/usb/serial/omninet.c linux-2.5.6-pre2/drivers/usb/serial/omninet.c
--- linux-2.5.6-pre1/drivers/usb/serial/omninet.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/omninet.c	Thu Feb 28 13:34:22 2002
@@ -157,8 +157,6 @@
 	if (!serial)
 		return -ENODEV;
 
-	down (&port->sem);
-
 	++port->open_count;
 
 	if (port->open_count == 1) {
@@ -166,7 +164,6 @@
 		if( !od ) {
 			err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct omninet_data));
 			port->open_count = 0;
-			up (&port->sem);
 			return -ENOMEM;
 		}
 
@@ -184,8 +181,6 @@
 			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 	}
 
-	up (&port->sem);
-
 	return result;
 }
 
@@ -204,8 +199,6 @@
 	if (!serial)
 		return;
 
-	down (&port->sem);
-
 	--port->open_count;
 
 	if (port->open_count <= 0) {
@@ -220,8 +213,6 @@
 		if (od)
 			kfree(od);
 	}
-
-	up (&port->sem);
 }
 
 
diff -urN linux-2.5.6-pre1/drivers/usb/serial/pl2303.c linux-2.5.6-pre2/drivers/usb/serial/pl2303.c
--- linux-2.5.6-pre1/drivers/usb/serial/pl2303.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/pl2303.c	Thu Feb 28 13:34:22 2002
@@ -367,8 +367,6 @@
 		
 	dbg (__FUNCTION__ " -  port %d", port->number);
 
-	down (&port->sem);
-
 	++port->open_count;
 
 	if (port->open_count == 1) {
@@ -407,7 +405,6 @@
 		result = usb_submit_urb (port->read_urb, GFP_KERNEL);
 		if (result) {
 			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
-			up (&port->sem);
 			pl2303_close (port, NULL);
 			return -EPROTO;
 		}
@@ -417,12 +414,10 @@
 		result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL);
 		if (result) {
 			err(__FUNCTION__ " - failed submitting interrupt urb, error %d", result);
-			up (&port->sem);
 			pl2303_close (port, NULL);
 			return -EPROTO;
 		}
 	}
-	up (&port->sem);
 	return 0;
 }
 
@@ -442,8 +437,6 @@
 	
 	dbg (__FUNCTION__ " - port %d", port->number);
 
-	down (&port->sem);
-
 	--port->open_count;
 	if (port->open_count <= 0) {
 		if (serial->dev) {
@@ -478,8 +471,6 @@
 		}
 		port->open_count = 0;
 	}
-
-	up (&port->sem);
 }
 
 static int set_modem_info (struct usb_serial_port *port, unsigned int cmd, unsigned int *value)
diff -urN linux-2.5.6-pre1/drivers/usb/serial/usbserial.c linux-2.5.6-pre2/drivers/usb/serial/usbserial.c
--- linux-2.5.6-pre1/drivers/usb/serial/usbserial.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/usbserial.c	Thu Feb 28 13:34:22 2002
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter driver
  *
- * Copyright (C) 1999 - 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
  * Copyright (c) 2000 Peter Berger (pberger@brimson.com)
  * Copyright (c) 2000 Al Borchers (borchers@steinerpoint.com)
  *
@@ -15,6 +15,13 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * (02/26/2002) gkh
+ *	Moved all locking into the main serial_* functions, instead of having 
+ *	the individual drivers have to grab the port semaphore.  This should
+ *	reduce races.
+ *	Reworked the MOD_INC logic a bit to always increment and decrement, even
+ *	if the generic driver is being used.
+ *
  * (10/10/2001) gkh
  *	usb_serial_disconnect() now sets the serial->dev pointer is to NULL to
  *	help prevent child drivers from accessing the device since it is now
@@ -337,6 +344,7 @@
 
 /* All of the device info needed for the Generic Serial Converter */
 static struct usb_serial_device_type generic_device = {
+	owner:			THIS_MODULE,
 	name:			"Generic",
 	id_table:		generic_device_ids,
 	num_interrupt_in:	NUM_DONT_CARE,
@@ -345,13 +353,6 @@
 	num_ports:		1,
 	shutdown:		generic_shutdown,
 };
-
-#define if_generic_do(x)			\
-	if ((serial->vendor == vendor) &&	\
-	    (serial->product == product))	\
-	                x
-#else
-#define if_generic_do(x)
 #endif
 
 
@@ -384,7 +385,7 @@
    via modprobe, and modprobe will load usbserial because the serial
    drivers depend on it.
 */
-   
+
 
 static int			serial_refcount;
 static struct tty_driver	serial_tty_driver;
@@ -392,8 +393,6 @@
 static struct termios *		serial_termios[SERIAL_TTY_MINORS];
 static struct termios *		serial_termios_locked[SERIAL_TTY_MINORS];
 static struct usb_serial	*serial_table[SERIAL_TTY_MINORS];	/* initially all NULL */
-
-
 static LIST_HEAD(usb_serial_driver_list);
 
 
@@ -402,7 +401,6 @@
 	return serial_table[minor];
 }
 
-
 static struct usb_serial *get_free_serial (int num_ports, unsigned int *minor)
 {
 	struct usb_serial *serial = NULL;
@@ -439,7 +437,6 @@
 	return NULL;
 }
 
-
 static void return_serial (struct usb_serial *serial)
 {
 	int i;
@@ -456,7 +453,6 @@
 	return;
 }
 
-
 #ifdef USES_EZUSB_FUNCTIONS
 /* EZ-USB Control and Status Register.  Bit 0 controls 8051 reset */
 #define CPUCS_REG    0x7F92
@@ -483,7 +479,6 @@
 	return result;
 }
 
-
 int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
 {
 	int	response;
@@ -497,7 +492,6 @@
 
 #endif	/* USES_EZUSB_FUNCTIONS */
 
-
 /*****************************************************************************
  * Driver tty interface functions
  *****************************************************************************/
@@ -516,266 +510,293 @@
 	/* get the serial object associated with this tty pointer */
 	serial = get_serial_by_minor (minor(tty->device));
 
-	if (serial_paranoia_check (serial, __FUNCTION__)) {
+	if (serial_paranoia_check (serial, __FUNCTION__))
 		return -ENODEV;
-	}
 
 	/* set up our port structure making the tty driver remember our port object, and us it */
 	portNumber = minor(tty->device) - serial->minor;
 	port = &serial->port[portNumber];
 	tty->driver_data = port;
+
+	down (&port->sem);
 	port->tty = tty;
 	 
+	/* lock this module before we call it */
+	if (serial->type->owner)
+		__MOD_INC_USE_COUNT(serial->type->owner);
+
 	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->open) {
-		if (serial->type->owner)
-			__MOD_INC_USE_COUNT(serial->type->owner);
+	if (serial->type->open)
 		retval = serial->type->open(port, filp);
-		if (retval)
-			__MOD_DEC_USE_COUNT(serial->type->owner);
-	} else {
+	else
 		retval = generic_open(port, filp);
-	}
 
+	if (retval)
+		__MOD_DEC_USE_COUNT(serial->type->owner);
+
+	up (&port->sem);
 	return retval;
 }
 
-
 static void serial_close(struct tty_struct *tty, struct file * filp)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
-	if (!serial) {
+	if (!serial)
 		return;
-	}
+
+	down (&port->sem);
 
 	dbg(__FUNCTION__ " - port %d", port->number);
-	
+
+	if (tty->driver_data == NULL) {
+		/* disconnect beat us to the punch here, so handle it gracefully */
+		goto exit;
+	}
 	if (!port->open_count) {
 		dbg (__FUNCTION__ " - port not opened");
-		return;
+		goto exit_no_mod_dec;
 	}
 
 	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->close) {
+	if (serial->type->close)
 		serial->type->close(port, filp);
-		if (serial->type->owner)
-			__MOD_DEC_USE_COUNT(serial->type->owner);
-	} else {
+	else
 		generic_close(port, filp);
-	}
-}	
 
+exit:
+	if (serial->type->owner)
+		__MOD_DEC_USE_COUNT(serial->type->owner);
+
+exit_no_mod_dec:
+	up (&port->sem);
+}
 
 static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
-	
-	if (!serial) {
+	int retval = -EINVAL;
+
+	if (!serial)
 		return -ENODEV;
-	}
-	
+
+	down (&port->sem);
+
 	dbg(__FUNCTION__ " - port %d, %d byte(s)", port->number, count);
 
 	if (!port->open_count) {
 		dbg (__FUNCTION__ " - port not opened");
-		return -EINVAL;
+		goto exit;
 	}
-	
+
 	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->write) {
-		return (serial->type->write(port, from_user, buf, count));
-	} else {
-		return (generic_write(port, from_user, buf, count));
-	}
-}
+	if (serial->type->write)
+		retval = serial->type->write(port, from_user, buf, count);
+	else
+		retval = generic_write(port, from_user, buf, count);
 
+exit:
+	up (&port->sem);
+	return retval;
+}
 
 static int serial_write_room (struct tty_struct *tty) 
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+	int retval = -EINVAL;
 
-	if (!serial) {
+	if (!serial)
 		return -ENODEV;
-	}
+
+	down (&port->sem);
 
 	dbg(__FUNCTION__ " - port %d", port->number);
-	
+
 	if (!port->open_count) {
 		dbg (__FUNCTION__ " - port not open");
-		return -EINVAL;
+		goto exit;
 	}
 
 	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->write_room) {
-		return (serial->type->write_room(port));
-	} else {
-		return (generic_write_room(port));
-	}
-}
+	if (serial->type->write_room)
+		retval = serial->type->write_room(port);
+	else
+		retval = generic_write_room(port);
 
+exit:
+	up (&port->sem);
+	return retval;
+}
 
 static int serial_chars_in_buffer (struct tty_struct *tty) 
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+	int retval = -EINVAL;
 
-	if (!serial) {
+	if (!serial)
 		return -ENODEV;
-	}
+
+	down (&port->sem);
+
+	dbg(__FUNCTION__ " - port %d", port->number);
 
 	if (!port->open_count) {
 		dbg (__FUNCTION__ " - port not open");
-		return -EINVAL;
+		goto exit;
 	}
 
 	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->chars_in_buffer) {
-		return (serial->type->chars_in_buffer(port));
-	} else {
-		return (generic_chars_in_buffer(port));
-	}
-}
+	if (serial->type->chars_in_buffer)
+		retval = serial->type->chars_in_buffer(port);
+	else
+		retval = generic_chars_in_buffer(port);
 
+exit:
+	up (&port->sem);
+	return retval;
+}
 
 static void serial_throttle (struct tty_struct * tty)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
-	if (!serial) {
+	if (!serial)
 		return;
-	}
+
+	down (&port->sem);
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
 	if (!port->open_count) {
 		dbg (__FUNCTION__ " - port not open");
-		return;
+		goto exit;
 	}
 
 	/* pass on to the driver specific version of this function */
-	if (serial->type->throttle) {
+	if (serial->type->throttle)
 		serial->type->throttle(port);
-	}
 
-	return;
+exit:
+	up (&port->sem);
 }
 
-
 static void serial_unthrottle (struct tty_struct * tty)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
-	if (!serial) {
+	if (!serial)
 		return;
-	}
+
+	down (&port->sem);
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
 	if (!port->open_count) {
 		dbg (__FUNCTION__ " - port not open");
-		return;
+		goto exit;
 	}
 
 	/* pass on to the driver specific version of this function */
-	if (serial->type->unthrottle) {
+	if (serial->type->unthrottle)
 		serial->type->unthrottle(port);
-	}
 
-	return;
+exit:
+	up (&port->sem);
 }
 
-
 static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+	int retval = -ENODEV;
 
-	if (!serial) {
+	if (!serial)
 		return -ENODEV;
-	}
+
+	down (&port->sem);
 
 	dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
 
 	if (!port->open_count) {
 		dbg (__FUNCTION__ " - port not open");
-		return -ENODEV;
+		goto exit;
 	}
 
 	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->ioctl) {
-		return (serial->type->ioctl(port, file, cmd, arg));
-	} else {
-		return -ENOIOCTLCMD;
-	}
-}
+	if (serial->type->ioctl)
+		retval = serial->type->ioctl(port, file, cmd, arg);
+	else
+		retval = -ENOIOCTLCMD;
 
+exit:
+	up (&port->sem);
+	return retval;
+}
 
 static void serial_set_termios (struct tty_struct *tty, struct termios * old)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
-	if (!serial) {
+	if (!serial)
 		return;
-	}
+
+	down (&port->sem);
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
 	if (!port->open_count) {
 		dbg (__FUNCTION__ " - port not open");
-		return;
+		goto exit;
 	}
 
 	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->set_termios) {
+	if (serial->type->set_termios)
 		serial->type->set_termios(port, old);
-	}
-	
-	return;
-}
 
+exit:
+	up (&port->sem);
+}
 
 static void serial_break (struct tty_struct *tty, int break_state)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
-	if (!serial) {
+	if (!serial)
 		return;
-	}
+
+	down (&port->sem);
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
 	if (!port->open_count) {
 		dbg (__FUNCTION__ " - port not open");
-		return;
+		goto exit;
 	}
 
-	/* pass on to the driver specific version of this function if it is
-           available */
-	if (serial->type->break_ctl) {
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->break_ctl)
 		serial->type->break_ctl(port, break_state);
-	}
-}
 
+exit:
+	up (&port->sem);
+}
 
 static void serial_shutdown (struct usb_serial *serial)
 {
-	if (serial->type->shutdown) {
+	if (serial->type->shutdown)
 		serial->type->shutdown(serial);
-	} else {
+	else
 		generic_shutdown(serial);
-	}
 }
 
-
-
 /*****************************************************************************
  * generic devices specific driver functions
  *****************************************************************************/
@@ -787,21 +808,16 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
 
-	/* only increment our usage count, if this device is _really_ a generic device */
-	if_generic_do(MOD_INC_USE_COUNT);
-
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	down (&port->sem);
-	
 	++port->open_count;
-	
+
 	if (port->open_count == 1) {
 		/* force low_latency on so that our tty_push actually forces the data through, 
 		   otherwise it is scheduled, and with high data rates (like with OHCI) data
 		   can get lost. */
 		port->tty->low_latency = 1;
-		
+
 		/* if we have a bulk interrupt, start reading from it */
 		if (serial->num_bulk_in) {
 			/* Start reading from the device */
@@ -818,21 +834,16 @@
 				err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 		}
 	}
-	
-	up (&port->sem);
-	
+
 	return result;
 }
 
-
 static void generic_close (struct usb_serial_port *port, struct file * filp)
 {
 	struct usb_serial *serial = port->serial;
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	down (&port->sem);
-
 	--port->open_count;
 
 	if (port->open_count <= 0) {
@@ -845,14 +856,8 @@
 		}
 		port->open_count = 0;
 	}
-
-	up (&port->sem);
-
-	/* only decrement our usage count, if this device is _really_ a generic device */
-	if_generic_do(MOD_DEC_USE_COUNT);
 }
 
-
 static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
 {
 	struct usb_serial *serial = port->serial;
@@ -880,14 +885,14 @@
 		}
 		else {
 			memcpy (port->write_urb->transfer_buffer, buf, count);
-		}  
+		}
 
 		usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer);
 
 		/* set up our urb */
 		usb_fill_bulk_urb (port->write_urb, serial->dev,
 				   usb_sndbulkpipe (serial->dev,
-					   	    port->bulk_out_endpointAddress),
+						    port->bulk_out_endpointAddress),
 				   port->write_urb->transfer_buffer, count,
 				   ((serial->type->write_bulk_callback) ? 
 				     serial->type->write_bulk_callback :
@@ -902,11 +907,10 @@
 
 		return result;
 	}
-	
+
 	/* no bulk out, so return 0 bytes written */
 	return (0);
-} 
-
+}
 
 static int generic_write_room (struct usb_serial_port *port)
 {
@@ -919,19 +923,18 @@
 		if (port->write_urb->status != -EINPROGRESS)
 			room = port->bulk_out_size;
 	}
-	
+
 	dbg(__FUNCTION__ " - returns %d", room);
 	return (room);
 }
 
-
 static int generic_chars_in_buffer (struct usb_serial_port *port)
 {
 	struct usb_serial *serial = port->serial;
 	int chars = 0;
 
 	dbg(__FUNCTION__ " - port %d", port->number);
-	
+
 	if (serial->num_bulk_out) {
 		if (port->write_urb->status == -EINPROGRESS)
 			chars = port->write_urb->transfer_buffer_length;
@@ -941,7 +944,6 @@
 	return (chars);
 }
 
-
 static void generic_read_bulk_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -952,7 +954,7 @@
 	int result;
 
 	dbg(__FUNCTION__ " - port %d", port->number);
-	
+
 	if (!serial) {
 		dbg(__FUNCTION__ " - bad serial pointer, exiting");
 		return;
@@ -992,14 +994,13 @@
 		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 }
 
-
 static void generic_write_bulk_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
 	dbg(__FUNCTION__ " - port %d", port->number);
-	
+
 	if (!serial) {
 		dbg(__FUNCTION__ " - bad serial pointer, exiting");
 		return;
@@ -1012,11 +1013,10 @@
 
 	queue_task(&port->tqueue, &tq_immediate);
 	mark_bh(IMMEDIATE_BH);
-	
+
 	return;
 }
 
-
 static void generic_shutdown (struct usb_serial *serial)
 {
 	int i;
@@ -1025,13 +1025,13 @@
 
 	/* stop reads and writes on all ports */
 	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
+		down (&serial->port[i].sem);
+		while (serial->port[i].open_count > 0)
 			generic_close (&serial->port[i], NULL);
-		}
+		up (&serial->port[i].sem);
 	}
 }
 
-
 static void port_softint(void *private)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)private;
@@ -1043,7 +1043,7 @@
 	if (!serial) {
 		return;
 	}
- 	
+
 	tty = port->tty;
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
 		dbg(__FUNCTION__ " - write wakeup call.");
@@ -1053,8 +1053,6 @@
 	wake_up_interruptible(&tty->write_wait);
 }
 
-
-
 static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
 			       const struct usb_device_id *id)
 {
@@ -1080,7 +1078,6 @@
 	int max_endpoints;
 	const struct usb_device_id *id_pattern = NULL;
 
-	
 	/* loop through our list of known serial converters, and see if this
 	   device matches. */
 	found = 0;
@@ -1130,7 +1127,7 @@
 			++num_interrupt_in;
 		}
 	}
-	
+
 #if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
 	/* BEGIN HORRIBLE HACK FOR PL2303 */ 
 	/* this is needed due to the looney way its endpoints are set up */
@@ -1156,7 +1153,7 @@
 	}
 	/* END HORRIBLE HACK FOR PL2303 */
 #endif
-	
+
 	/* found all that we need */
 	info("%s converter detected", type->name);
 
@@ -1176,7 +1173,7 @@
 		err("No more free serial devices");
 		return NULL;
 	}
-	
+
 	serial->dev = dev;
 	serial->type = type;
 	serial->interface = interface;
@@ -1289,14 +1286,14 @@
 		port->tqueue.data = port;
 		init_MUTEX (&port->sem);
 	}
-	
+
 	/* initialize the devfs nodes for this device and let the user know what ports we are bound to */
 	for (i = 0; i < serial->num_ports; ++i) {
 		tty_register_devfs (&serial_tty_driver, 0, serial->port[i].number);
 		info("%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)", 
 		     type->name, serial->port[i].number, serial->port[i].number);
 	}
-	
+
 	return serial; /* success */
 
 
@@ -1322,7 +1319,7 @@
 		if (port->interrupt_in_buffer)
 			kfree (port->interrupt_in_buffer);
 	}
-		
+
 	/* return the minor range that this device had */
 	return_serial (serial);
 
@@ -1331,7 +1328,6 @@
 	return NULL;
 }
 
-
 static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct usb_serial *serial = (struct usb_serial *) ptr;
@@ -1341,8 +1337,10 @@
 	if (serial) {
 		/* fail all future close/read/write/ioctl/etc calls */
 		for (i = 0; i < serial->num_ports; ++i) {
+			down (&serial->port[i].sem);
 			if (serial->port[i].tty != NULL)
 				serial->port[i].tty->driver_data = NULL;
+			up (&serial->port[i].sem);
 		}
 
 		serial->dev = NULL;
@@ -1393,7 +1391,7 @@
 	} else {
 		info("device disconnected");
 	}
-	
+
 }
 
 
@@ -1407,12 +1405,12 @@
 	type:			TTY_DRIVER_TYPE_SERIAL,
 	subtype:		SERIAL_TYPE_NORMAL,
 	flags:			TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
-	
+
 	refcount:		&serial_refcount,
 	table:			serial_tty,
 	termios:		serial_termios,
 	termios_locked:		serial_termios_locked,
-	
+
 	open:			serial_open,
 	close:			serial_close,
 	write:			serial_write,
diff -urN linux-2.5.6-pre1/drivers/usb/serial/visor.c linux-2.5.6-pre2/drivers/usb/serial/visor.c
--- linux-2.5.6-pre1/drivers/usb/serial/visor.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/visor.c	Thu Feb 28 13:34:22 2002
@@ -12,6 +12,15 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (02/27/2002) gkh
+ *	Reworked the urb handling logic.  We have no more pool, but dynamically
+ *	allocate the urb and the transfer buffer on the fly.  In testing this
+ *	does not incure any measurable overhead.  This also relies on the fact
+ *	that we have proper reference counting logic for urbs.
+ *
+ * (02/21/2002) SilaS
+ *  Added initial support for the Palm m515 devices.
+ *
  * (02/14/2002) gkh
  *	Added support for the Clie S-360 device.
  *
@@ -134,7 +143,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.9"
+#define DRIVER_VERSION "v2.0"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC "USB HandSpring Visor, Palm m50x, Sony Clié driver"
 
@@ -158,6 +167,7 @@
 static __devinitdata struct usb_device_id combined_id_table [] = {
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
@@ -174,6 +184,7 @@
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
@@ -233,12 +244,8 @@
 };
 
 
-#define NUM_URBS			24
-#define URB_TRANSFER_BUFFER_SIZE	768
-static struct urb	*write_urb_pool[NUM_URBS];
-static spinlock_t	write_urb_pool_lock;
-static int		bytes_in;
-static int		bytes_out;
+static int bytes_in;
+static int bytes_out;
 
 
 /******************************************************************************
@@ -259,8 +266,6 @@
 		return -ENODEV;
 	}
 
-	down (&port->sem);
-	
 	++port->open_count;
 	
 	if (port->open_count == 1) {
@@ -284,8 +289,6 @@
 			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 	}
 	
-	up (&port->sem);
-	
 	return result;
 }
 
@@ -304,8 +307,6 @@
 	if (!serial)
 		return;
 	
-	down (&port->sem);
-
 	--port->open_count;
 
 	if (port->open_count <= 0) {
@@ -329,8 +330,6 @@
 		}
 		port->open_count = 0;
 	}
-	up (&port->sem);
-
 	/* Uncomment the following line if you want to see some statistics in your syslog */
 	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
 }
@@ -340,120 +339,84 @@
 {
 	struct usb_serial *serial = port->serial;
 	struct urb *urb;
-	const unsigned char *current_position = buf;
-	unsigned long flags;
+	unsigned char *buffer;
 	int status;
-	int i;
-	int bytes_sent = 0;
-	int transfer_size;
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	while (count > 0) {
-		/* try to find a free urb in our list of them */
-		urb = NULL;
-		spin_lock_irqsave (&write_urb_pool_lock, flags);
-		for (i = 0; i < NUM_URBS; ++i) {
-			if (write_urb_pool[i]->status != -EINPROGRESS) {
-				urb = write_urb_pool[i];
-				break;
-			}
-		}
-		spin_unlock_irqrestore (&write_urb_pool_lock, flags);
-		if (urb == NULL) {
-			dbg (__FUNCTION__ " - no more free urbs");
-			goto exit;
-		}
-		if (urb->transfer_buffer == NULL) {
-			urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
-			if (urb->transfer_buffer == NULL) {
-				err(__FUNCTION__" no more kernel memory...");
-				goto exit;
-			}
-		}
-		
-		transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE);
-		if (from_user) {
-			if (copy_from_user (urb->transfer_buffer, current_position, transfer_size)) {
-				bytes_sent = -EFAULT;
-				break;
-			}
-		} else {
-			memcpy (urb->transfer_buffer, current_position, transfer_size);
-		}
+	buffer = kmalloc (count, GFP_KERNEL);
+	if (!buffer) {
+		err ("out of memory");
+		return -ENOMEM;
+	}
 
-		usb_serial_debug_data (__FILE__, __FUNCTION__, transfer_size, urb->transfer_buffer);
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb) {
+		err ("no more free urbs");
+		kfree (buffer);
+		return -ENOMEM;
+	}
 
-		/* build up our urb */
-		usb_fill_bulk_urb (urb, serial->dev,
-				   usb_sndbulkpipe (serial->dev,
-						    port->bulk_out_endpointAddress),
-				   urb->transfer_buffer, transfer_size, 
-				   visor_write_bulk_callback, port);
-		urb->transfer_flags |= USB_QUEUE_BULK;
-
-		/* send it down the pipe */
-		status = usb_submit_urb(urb, GFP_KERNEL);
-		if (status) {
-			err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
-			bytes_sent = status;
-			break;
+	if (from_user) {
+		if (copy_from_user (buffer, buf, count)) {
+			kfree (buffer);
+			usb_free_urb (urb);
+			return -EFAULT;
 		}
+	} else {
+		memcpy (buffer, buf, count);
+	}
+
+	usb_serial_debug_data (__FILE__, __FUNCTION__, count, buffer);
 
-		current_position += transfer_size;
-		bytes_sent += transfer_size;
-		count -= transfer_size;
-		bytes_out += transfer_size;
+	usb_fill_bulk_urb (urb, serial->dev,
+			   usb_sndbulkpipe (serial->dev,
+					    port->bulk_out_endpointAddress),
+			   buffer, count, 
+			   visor_write_bulk_callback, port);
+	urb->transfer_flags |= USB_QUEUE_BULK;
+
+	/* send it down the pipe */
+	status = usb_submit_urb(urb, GFP_KERNEL);
+	if (status) {
+		err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+		count = status;
+	} else {
+		bytes_out += count;
 	}
 
-exit:
-	return bytes_sent;
+	/* we are done with this urb, so let the host driver
+	 * really free it when it is finished with it */
+	usb_free_urb (urb);
+
+	return count;
 } 
 
 
 static int visor_write_room (struct usb_serial_port *port)
 {
-	unsigned long flags;
-	int i;
-	int room = 0;
-
 	dbg(__FUNCTION__ " - port %d", port->number);
-	
-	spin_lock_irqsave (&write_urb_pool_lock, flags);
 
-	for (i = 0; i < NUM_URBS; ++i) {
-		if (write_urb_pool[i]->status != -EINPROGRESS) {
-			room += URB_TRANSFER_BUFFER_SIZE;
-		}
-	}
-	
-	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
-	
-	dbg(__FUNCTION__ " - returns %d", room);
-	return (room);
+	/*
+	 * We really can take anything the user throws at us
+	 * but let's pick a nice big number to tell the tty
+	 * layer that we have lots of free space
+	 */
+	return 2048;
 }
 
 
 static int visor_chars_in_buffer (struct usb_serial_port *port)
 {
-	unsigned long flags;
-	int i;
-	int chars = 0;
-
 	dbg(__FUNCTION__ " - port %d", port->number);
-	
-	spin_lock_irqsave (&write_urb_pool_lock, flags);
-
-	for (i = 0; i < NUM_URBS; ++i) {
-		if (write_urb_pool[i]->status == -EINPROGRESS) {
-			chars += URB_TRANSFER_BUFFER_SIZE;
-		}
-	}
-	
-	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
 
-	dbg (__FUNCTION__ " - returns %d", chars);
-	return (chars);
+	/* 
+	 * We can't really account for how much data we
+	 * have sent out, but hasn't made it through to the
+	 * device, so just tell the tty layer that everything
+	 * is flushed.
+	 */
+	return 0;
 }
 
 
@@ -471,9 +434,12 @@
 		return;
 	}
 
+	/* free up the transfer buffer, as usb_free_urb() does not do this */
+	kfree (urb->transfer_buffer);
+
 	queue_task(&port->tqueue, &tq_immediate);
 	mark_bh(IMMEDIATE_BH);
-	
+
 	return;
 }
 
@@ -534,16 +500,8 @@
 
 static void visor_throttle (struct usb_serial_port *port)
 {
-
 	dbg(__FUNCTION__ " - port %d", port->number);
-
-	down (&port->sem);
-
 	usb_unlink_urb (port->read_urb);
-
-	up (&port->sem);
-
-	return;
 }
 
 
@@ -553,16 +511,10 @@
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	down (&port->sem);
-
 	port->read_urb->dev = port->serial->dev;
 	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 	if (result)
 		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
-
-	up (&port->sem);
-
-	return;
 }
 
 
@@ -783,30 +735,8 @@
 
 static int __init visor_init (void)
 {
-	struct urb *urb;
-	int i;
-
 	usb_serial_register (&handspring_device);
 	usb_serial_register (&clie_3_5_device);
-	
-	/* create our write urb pool and transfer buffers */ 
-	spin_lock_init (&write_urb_pool_lock);
-	for (i = 0; i < NUM_URBS; ++i) {
-		urb = usb_alloc_urb(0, GFP_KERNEL);
-		write_urb_pool[i] = urb;
-		if (urb == NULL) {
-			err("No more urbs???");
-			continue;
-		}
-
-		urb->transfer_buffer = NULL;
-		urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
-		if (!urb->transfer_buffer) {
-			err (__FUNCTION__ " - out of memory for urb buffers.");
-			continue;
-		}
-	}
-
 	info(DRIVER_DESC " " DRIVER_VERSION);
 
 	return 0;
@@ -815,27 +745,8 @@
 
 static void __exit visor_exit (void)
 {
-	int i;
-	unsigned long flags;
-
 	usb_serial_deregister (&handspring_device);
 	usb_serial_deregister (&clie_3_5_device);
-
-	spin_lock_irqsave (&write_urb_pool_lock, flags);
-
-	for (i = 0; i < NUM_URBS; ++i) {
-		if (write_urb_pool[i]) {
-			/* FIXME - uncomment the following usb_unlink_urb call when
-			 * the host controllers get fixed to set urb->dev = NULL after
-			 * the urb is finished.  Otherwise this call oopses. */
-			/* usb_unlink_urb(write_urb_pool[i]); */
-			if (write_urb_pool[i]->transfer_buffer)
-				kfree(write_urb_pool[i]->transfer_buffer);
-			usb_free_urb (write_urb_pool[i]);
-		}
-	}
-
-	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
 }
 
 
diff -urN linux-2.5.6-pre1/drivers/usb/serial/visor.h linux-2.5.6-pre2/drivers/usb/serial/visor.h
--- linux-2.5.6-pre1/drivers/usb/serial/visor.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/visor.h	Thu Feb 28 13:34:22 2002
@@ -23,6 +23,7 @@
 #define PALM_VENDOR_ID			0x0830
 #define PALM_M500_ID			0x0001
 #define PALM_M505_ID			0x0002
+#define PALM_M515_ID			0x0003
 #define PALM_M125_ID			0x0040
 
 #define SONY_VENDOR_ID			0x054C
diff -urN linux-2.5.6-pre1/drivers/usb/serial/whiteheat.c linux-2.5.6-pre2/drivers/usb/serial/whiteheat.c
--- linux-2.5.6-pre1/drivers/usb/serial/whiteheat.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/drivers/usb/serial/whiteheat.c	Thu Feb 28 13:34:22 2002
@@ -306,8 +306,6 @@
 
 	dbg(__FUNCTION__" - port %d", port->number);
 
-	down (&port->sem);
-
 	++port->open_count;
 	
 	if (port->open_count == 1) {
@@ -354,16 +352,12 @@
 	}
 
 	dbg(__FUNCTION__ " - exit");
-	up (&port->sem);
-	
 	return retval;
 
 error_exit:
 	--port->open_count;
 
 	dbg(__FUNCTION__ " - error_exit");
-	up (&port->sem);
-	
 	return retval;
 }
 
@@ -374,7 +368,6 @@
 	
 	dbg(__FUNCTION__ " - port %d", port->number);
 	
-	down (&port->sem);
 	--port->open_count;
 
 	if (port->open_count <= 0) {
@@ -391,7 +384,6 @@
 		usb_unlink_urb (port->read_urb);
 		port->open_count = 0;
 	}
-	up (&port->sem);
 }
 
 
@@ -410,8 +402,6 @@
 
 	dbg(__FUNCTION__ " -port %d", port->number);
 
-	down (&port->sem);
-
 	if ((!port->tty) || (!port->tty->termios)) {
 		dbg(__FUNCTION__" - no tty structures");
 		goto exit;
@@ -492,7 +482,6 @@
 	whiteheat_send_cmd (port->serial, WHITEHEAT_SETUP_PORT, (__u8 *)&port_settings, sizeof(port_settings));
 	
 exit:
-	up (&port->sem);
 	return;
 }
 
diff -urN linux-2.5.6-pre1/drivers/usb/uhci.c linux-2.5.6-pre2/drivers/usb/uhci.c
--- linux-2.5.6-pre1/drivers/usb/uhci.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/drivers/usb/uhci.c	Thu Feb 28 13:34:22 2002
@@ -53,11 +53,11 @@
 #include <asm/irq.h>
 #include <asm/system.h>
 
+#include "hcd.h"
 #include "uhci.h"
 
 #include <linux/pm.h>
 
-
 /*
  * Version Information
  */
@@ -65,7 +65,6 @@
 #define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
 #define DRIVER_DESC "USB Universal Host Controller Interface driver"
 
-
 /*
  * debug = 0, no debugging messages
  * debug = 1, dump failed URB's except for stalls
@@ -100,6 +99,7 @@
 
 /* If a transfer is still active after this much time, turn off FSBR */
 #define IDLE_TIMEOUT	(HZ / 20)	/* 50 ms */
+#define FSBR_DELAY	(HZ / 20)	/* 50 ms */
 
 #define MAX_URB_LOOP	2048		/* Maximum number of linked URB's */
 
@@ -766,7 +766,7 @@
 	if ((!(urb->transfer_flags & USB_NO_FSBR)) && urbp->fsbr) {
 		urbp->fsbr = 0;
 		if (!--uhci->fsbr)
-			uhci->skel_term_qh->link = UHCI_PTR_TERM;
+			uhci->fsbrtimeout = jiffies + FSBR_DELAY;
 	}
 
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
@@ -2031,6 +2031,12 @@
 		uhci_unlink_urb(u);
 	}
 
+	/* Really disable FSBR */
+	if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
+		uhci->fsbrtimeout = 0;
+		uhci->skel_term_qh->link = UHCI_PTR_TERM;
+	}
+
 	/* enter global suspend if nothing connected */
 	if (!uhci->is_suspended && !ports_active(uhci))
 		suspend_hc(uhci);
diff -urN linux-2.5.6-pre1/drivers/usb/uhci.h linux-2.5.6-pre2/drivers/usb/uhci.h
--- linux-2.5.6-pre1/drivers/usb/uhci.h	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/drivers/usb/uhci.h	Thu Feb 28 13:34:22 2002
@@ -309,6 +309,7 @@
 	spinlock_t frame_list_lock;
 	struct uhci_frame_list *fl;		/* P: uhci->frame_list_lock */
 	int fsbr;				/* Full speed bandwidth reclamation */
+	unsigned long fsbrtimeout;		/* FSBR delay */
 	int is_suspended;
 
 	/* Main list of URB's currently controlled by this HC */
diff -urN linux-2.5.6-pre1/drivers/usb/usb-ohci.c linux-2.5.6-pre2/drivers/usb/usb-ohci.c
--- linux-2.5.6-pre1/drivers/usb/usb-ohci.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/drivers/usb/usb-ohci.c	Thu Feb 28 13:34:22 2002
@@ -73,6 +73,7 @@
 #define OHCI_USE_NPS		// force NoPowerSwitching mode
 // #define OHCI_VERBOSE_DEBUG	/* not always helpful */
 
+#include "hcd.h"
 #include "usb-ohci.h"
 
 
diff -urN linux-2.5.6-pre1/drivers/usb/usb-uhci.c linux-2.5.6-pre2/drivers/usb/usb-uhci.c
--- linux-2.5.6-pre1/drivers/usb/usb-uhci.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/drivers/usb/usb-uhci.c	Thu Feb 28 13:34:22 2002
@@ -57,6 +57,7 @@
 #define VERSTR "$Revision: 1.275 $ time " __TIME__ " " __DATE__
 
 #include <linux/usb.h>
+#include "hcd.h"
 #include "usb-uhci.h"
 #include "usb-uhci-debug.h"
 
diff -urN linux-2.5.6-pre1/drivers/usb/usb.c linux-2.5.6-pre2/drivers/usb/usb.c
--- linux-2.5.6-pre1/drivers/usb/usb.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/drivers/usb/usb.c	Thu Feb 28 13:34:22 2002
@@ -40,12 +40,7 @@
 #endif
 #include <linux/usb.h>
 
-static const int usb_bandwidth_option =
-#ifdef CONFIG_USB_BANDWIDTH
-				1;
-#else
-				0;
-#endif
+#include "hcd.h"
 
 extern int  usb_hub_init(void);
 extern void usb_hub_cleanup(void);
@@ -61,13 +56,9 @@
  * We have a per-interface "registered driver" list.
  */
 LIST_HEAD(usb_driver_list);
-LIST_HEAD(usb_bus_list);
-struct semaphore usb_bus_list_lock;
 
 devfs_handle_t usb_devfs_handle;	/* /dev/usb dir. */
 
-static struct usb_busmap busmap;
-
 static struct usb_driver *usb_minors[16];
 
 /**
@@ -105,6 +96,7 @@
 
 /**
  *	usb_scan_devices - scans all unclaimed USB interfaces
+ *	Context: !in_interrupt ()
  *
  *	Goes through all unclaimed USB interfaces, and offers them to all
  *	registered USB drivers through the 'probe' function.
@@ -173,6 +165,7 @@
 /**
  *	usb_deregister - unregister a USB driver
  *	@driver: USB operations of the driver to unregister
+ *	Context: !in_interrupt ()
  *
  *	Unlinks the specified driver from the internal USB driver list.
  */
@@ -258,259 +251,6 @@
 }
 
 /*
- * usb_calc_bus_time:
- *
- * returns (approximate) USB bus time in nanoseconds for a USB transaction.
- */
-static long usb_calc_bus_time (int low_speed, int input_dir, int isoc, int bytecount)
-{
-	unsigned long	tmp;
-
-	if (low_speed)		/* no isoc. here */
-	{
-		if (input_dir)
-		{
-			tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L;
-			return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
-		}
-		else
-		{
-			tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L;
-			return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
-		}
-	}
-
-	/* for full-speed: */
-
-	if (!isoc)		/* Input or Output */
-	{
-		tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
-		return (9107L + BW_HOST_DELAY + tmp);
-	} /* end not Isoc */
-
-	/* for isoc: */
-
-	tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
-	return (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);
-}
-
-/*
- * usb_check_bandwidth():
- *
- * old_alloc is from host_controller->bandwidth_allocated in microseconds;
- * bustime is from calc_bus_time(), but converted to microseconds.
- *
- * returns <bustime in us> if successful,
- * or -ENOSPC if bandwidth request fails.
- *
- * FIXME:
- * This initial implementation does not use Endpoint.bInterval
- * in managing bandwidth allocation.
- * It probably needs to be expanded to use Endpoint.bInterval.
- * This can be done as a later enhancement (correction).
- * This will also probably require some kind of
- * frame allocation tracking...meaning, for example,
- * that if multiple drivers request interrupts every 10 USB frames,
- * they don't all have to be allocated at
- * frame numbers N, N+10, N+20, etc.  Some of them could be at
- * N+11, N+21, N+31, etc., and others at
- * N+12, N+22, N+32, etc.
- * However, this first cut at USB bandwidth allocation does not
- * contain any frame allocation tracking.
- */
-int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
-{
-	int		new_alloc;
-	int		old_alloc = dev->bus->bandwidth_allocated;
-	unsigned int	pipe = urb->pipe;
-	long		bustime;
-
-	bustime = usb_calc_bus_time (dev->speed == USB_SPEED_LOW,
-			usb_pipein(pipe), usb_pipeisoc(pipe),
-			usb_maxpacket(dev, pipe, usb_pipeout(pipe)));
-	if (usb_pipeisoc(pipe))
-		bustime = NS_TO_US(bustime) / urb->number_of_packets;
-	else
-		bustime = NS_TO_US(bustime);
-
-	new_alloc = old_alloc + (int)bustime;
-		/* what new total allocated bus time would be */
-
-	if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC)
-		dbg("usb-check-bandwidth %sFAILED: was %u, would be %u, bustime = %ld us",
-			usb_bandwidth_option ? "" : "would have ",
-			old_alloc, new_alloc, bustime);
-
-	if (!usb_bandwidth_option)	/* don't enforce it */
-		return (bustime);
-	return (new_alloc <= FRAME_TIME_MAX_USECS_ALLOC) ? bustime : -ENOSPC;
-}
-
-void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
-{
-	dev->bus->bandwidth_allocated += bustime;
-	if (isoc)
-		dev->bus->bandwidth_isoc_reqs++;
-	else
-		dev->bus->bandwidth_int_reqs++;
-	urb->bandwidth = bustime;
-
-#ifdef USB_BANDWIDTH_MESSAGES
-	dbg("bandwidth alloc increased by %d to %d for %d requesters",
-		bustime,
-		dev->bus->bandwidth_allocated,
-		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-}
-
-/*
- * usb_release_bandwidth():
- *
- * called to release a pipe's bandwidth (in microseconds)
- */
-void usb_release_bandwidth(struct usb_device *dev, struct urb *urb, int isoc)
-{
-	dev->bus->bandwidth_allocated -= urb->bandwidth;
-	if (isoc)
-		dev->bus->bandwidth_isoc_reqs--;
-	else
-		dev->bus->bandwidth_int_reqs--;
-
-#ifdef USB_BANDWIDTH_MESSAGES
-	dbg("bandwidth alloc reduced by %d to %d for %d requesters",
-		urb->bandwidth,
-		dev->bus->bandwidth_allocated,
-		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-	urb->bandwidth = 0;
-}
-
-static void usb_bus_get(struct usb_bus *bus)
-{
-	atomic_inc(&bus->refcnt);
-}
-
-static void usb_bus_put(struct usb_bus *bus)
-{
-	if (atomic_dec_and_test(&bus->refcnt))
-		kfree(bus);
-}
-
-/**
- *	usb_alloc_bus - creates a new USB host controller structure (usbcore-internal)
- *	@op: pointer to a struct usb_operations that this bus structure should use
- *
- *	Creates a USB host controller bus structure with the specified 
- *	usb_operations and initializes all the necessary internal objects.
- *	(For use only by USB Host Controller Drivers.)
- *
- *	If no memory is available, NULL is returned.
- *
- *	The caller should call usb_free_bus() when it is finished with the structure.
- */
-struct usb_bus *usb_alloc_bus(struct usb_operations *op)
-{
-	struct usb_bus *bus;
-
-	bus = kmalloc(sizeof(*bus), GFP_KERNEL);
-	if (!bus)
-		return NULL;
-
-	memset(&bus->devmap, 0, sizeof(struct usb_devmap));
-
-#ifdef DEVNUM_ROUND_ROBIN
-	bus->devnum_next = 1;
-#endif /* DEVNUM_ROUND_ROBIN */
-
-	bus->op = op;
-	bus->root_hub = NULL;
-	bus->hcpriv = NULL;
-	bus->busnum = -1;
-	bus->bandwidth_allocated = 0;
-	bus->bandwidth_int_reqs  = 0;
-	bus->bandwidth_isoc_reqs = 0;
-
-	INIT_LIST_HEAD(&bus->bus_list);
-
-	atomic_set(&bus->refcnt, 1);
-
-	return bus;
-}
-
-/**
- *	usb_free_bus - frees the memory used by a bus structure (usbcore-internal)
- *	@bus: pointer to the bus to free
- *
- *	(For use only by USB Host Controller Drivers.)
- */
-void usb_free_bus(struct usb_bus *bus)
-{
-	if (!bus)
-		return;
-
-	usb_bus_put(bus);
-}
-
-/**
- *	usb_register_bus - registers the USB host controller with the usb core (usbcore-internal)
- *	@bus: pointer to the bus to register
- *
- *	(For use only by USB Host Controller Drivers.)
- *
- * This call is synchronous, and may not be used in an interrupt context.
- */
-void usb_register_bus(struct usb_bus *bus)
-{
-	int busnum;
-
-	down (&usb_bus_list_lock);
-	busnum = find_next_zero_bit(busmap.busmap, USB_MAXBUS, 1);
-	if (busnum < USB_MAXBUS) {
-		set_bit(busnum, busmap.busmap);
-		bus->busnum = busnum;
-	} else
-		warn("too many buses");
-
-	usb_bus_get(bus);
-
-	/* Add it to the list of buses */
-	list_add(&bus->bus_list, &usb_bus_list);
-	up (&usb_bus_list_lock);
-
-	usbfs_add_bus(bus);
-
-	info("new USB bus registered, assigned bus number %d", bus->busnum);
-}
-
-/**
- *	usb_deregister_bus - deregisters the USB host controller (usbcore-internal)
- *	@bus: pointer to the bus to deregister
- *
- *	(For use only by USB Host Controller Drivers.)
- *
- * This call is synchronous, and may not be used in an interrupt context.
- */
-void usb_deregister_bus(struct usb_bus *bus)
-{
-	info("USB bus %d deregistered", bus->busnum);
-
-	/*
-	 * NOTE: make sure that all the devices are removed by the
-	 * controller code, as well as having it call this when cleaning
-	 * itself up
-	 */
-	down (&usb_bus_list_lock);
-	list_del(&bus->bus_list);
-	up (&usb_bus_list_lock);
-
-	usbfs_remove_bus(bus);
-
-	clear_bit(bus->busnum, busmap.busmap);
-
-	usb_bus_put(bus);
-}
-
-/*
  * This function is for doing a depth-first search for devices which
  * have support, for dynamic loading of driver modules.
  */
@@ -1016,6 +756,7 @@
  * usb_alloc_dev - allocate a usb device structure (usbcore-internal)
  * @parent: hub to which device is connected
  * @bus: bus used to access the device
+ * Context: !in_interrupt ()
  *
  * Only hub drivers (including virtual root hub drivers for host
  * controllers) should ever call this.
@@ -1078,14 +819,12 @@
 	atomic_inc(&dev->refcnt);
 }
 
-/* ---------------------------------------------------------------------- 
- * New USB Core Functions
- * ----------------------------------------------------------------------*/
 
 /**
  * usb_alloc_urb - creates a new urb for a USB driver to use
  * @iso_packets: number of iso packets for this urb
- * @mem_flags: the type of memory to allocate, see kmalloc() for a list of valid options for this.
+ * @mem_flags: the type of memory to allocate, see kmalloc() for a list of
+ *	valid options for this.
  *
  * Creates an urb for the USB driver to use, initializes a few internal
  * structures, incrementes the usage counter, and returns a pointer to it.
@@ -1158,7 +897,8 @@
 /**
  * usb_submit_urb - asynchronously issue a transfer request for an endpoint
  * @urb: pointer to the urb describing the request
- * @mem_flags: the type of memory to allocate, see kmalloc() for a list of valid options for this.
+ * @mem_flags: the type of memory to allocate, see kmalloc() for a list
+ *	of valid options for this.
  *
  * This submits a transfer request, and transfers control of the URB
  * describing that request to the USB subsystem.  Request completion will
@@ -1393,7 +1133,9 @@
  *	@index: USB message index value
  *	@data: pointer to the data to send
  *	@size: length in bytes of the data to send
- *	@timeout: time to wait for the message to complete before timing out (if 0 the wait is forever)
+ *	@timeout: time in jiffies to wait for the message to complete before
+ *		timing out (if 0 the wait is forever)
+ *	Context: !in_interrupt ()
  *
  *	This function sends a simple control message to a specified endpoint
  *	and waits for the message to complete, or timeout.
@@ -1401,7 +1143,7 @@
  *	If successful, it returns 0, otherwise a negative error number.
  *
  *	Don't use this function from within an interrupt context, like a
- *	bottom half handler.  If you need a asyncronous message, or need to send
+ *	bottom half handler.  If you need an asynchronous message, or need to send
  *	a message from within interrupt context, use usb_submit_urb()
  */
 int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
@@ -1436,7 +1178,9 @@
  *	@data: pointer to the data to send
  *	@len: length in bytes of the data to send
  *	@actual_length: pointer to a location to put the actual length transferred in bytes
- *	@timeout: time to wait for the message to complete before timing out (if 0 the wait is forever)
+ *	@timeout: time in jiffies to wait for the message to complete before
+ *		timing out (if 0 the wait is forever)
+ *	Context: !in_interrupt ()
  *
  *	This function sends a simple bulk message to a specified endpoint
  *	and waits for the message to complete, or timeout.
@@ -1446,7 +1190,7 @@
  *	actual_length paramater.
  *
  *	Don't use this function from within an interrupt context, like a
- *	bottom half handler.  If you need a asyncronous message, or need to
+ *	bottom half handler.  If you need an asynchronous message, or need to
  *	send a message from within interrupt context, use usb_submit_urb()
  */
 int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, 
@@ -1474,6 +1218,11 @@
  * Returns the current frame number for the USB host controller
  * used with the given USB device.  This can be used when scheduling
  * isochronous requests.
+ *
+ * Note that different kinds of host controller have different
+ * "scheduling horizons".  While one type might support scheduling only
+ * 32 frames into the future, others could support scheduling up to
+ * 1024 frames into the future.
  */
 int usb_get_current_frame_number(struct usb_device *dev)
 {
@@ -1946,6 +1695,7 @@
 /**
  * usb_disconnect - disconnect a device (usbcore-internal)
  * @pdev: pointer to device being disconnected
+ * Context: !in_interrupt ()
  *
  * Something got disconnected. Get rid of it, and all of its children.
  *
@@ -2069,6 +1819,7 @@
  * @index: the number of the descriptor
  * @buf: where to put the descriptor
  * @size: how big is "buf"?
+ * Context: !in_interrupt ()
  *
  * Gets a USB descriptor.  Convenience functions exist to simplify
  * getting some types of descriptors.  Use
@@ -2110,6 +1861,7 @@
  * @index: the number of the descriptor
  * @buf: where to put the string
  * @size: how big is "buf"?
+ * Context: !in_interrupt ()
  *
  * Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character,
  * in little-endian byte order).
@@ -2135,6 +1887,7 @@
 /**
  * usb_get_device_descriptor - (re)reads the device descriptor
  * @dev: the device whose device descriptor is being updated
+ * Context: !in_interrupt ()
  *
  * Updates the copy of the device descriptor stored in the device structure,
  * which dedicates space for this purpose.  Note that several fields are
@@ -2169,6 +1922,7 @@
  * @type: USB_RECIP_*; for device, interface, or endpoint
  * @target: zero (for device), else interface or endpoint number
  * @data: pointer to two bytes of bitmap data
+ * Context: !in_interrupt ()
  *
  * Returns device, interface, or endpoint status.  Normally only of
  * interest to see if the device is self powered, or has enabled the
@@ -2227,6 +1981,7 @@
  * usb_clear_halt - tells device to clear endpoint halt/stall condition
  * @dev: device whose endpoint is halted
  * @pipe: endpoint "pipe" being cleared
+ * Context: !in_interrupt ()
  *
  * This is used to clear halt conditions for bulk and interrupt endpoints,
  * as reported by URB completion status.  Endpoints that are halted are
@@ -2298,6 +2053,7 @@
  * @dev: the device whose interface is being updated
  * @interface: the interface being updated
  * @alternate: the setting being chosen.
+ * Context: !in_interrupt ()
  *
  * This is used to enable data transfers on interfaces that may not
  * be enabled by default.  Not all devices support such configurability.
@@ -2378,6 +2134,7 @@
  * usb_set_configuration - Makes a particular device setting be current
  * @dev: the device whose configuration is being updated
  * @configuration: the configuration being chosen.
+ * Context: !in_interrupt ()
  *
  * This is used to enable non-default device modes.  Not all devices
  * support this kind of configurability.  By default, configuration
@@ -2540,6 +2297,7 @@
  * @index: the number of the descriptor
  * @buf: where to put the string
  * @size: how big is "buf"?
+ * Context: !in_interrupt ()
  * 
  * This converts the UTF-16LE encoded strings returned by devices, from
  * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones
@@ -2619,8 +2377,11 @@
  * @dev: the device whose path is being constructed
  * @buf: where to put the string
  * @size: how big is "buf"?
+ * Context: !in_interrupt ()
  *
  * Returns length of the string (>= 0) or out of memory status (< 0).
+ *
+ * NOTE:  prefer to use use dev->devpath directly.
  */
 int usb_make_path(struct usb_device *dev, char *buf, size_t size)
 {
@@ -2768,29 +2529,6 @@
 	return 0;
 }
 
-/**
- * usb_register_root_hub - called by a usb host controller to register the root hub device in the system
- * @usb_dev: the usb root hub device to be registered.
- * @parent_dev: the parent device of this root hub.
- *
- * The USB host controller calls this function to register the root hub
- * properly with the USB subsystem.  It sets up the device properly in
- * the driverfs tree, and then calls usb_new_device() to register the
- * usb device.
- */
-int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev)
-{
-	int retval;
-
-	usb_dev->dev.parent = parent_dev;
-	strcpy (&usb_dev->dev.name[0], "usb_name");
-	strcpy (&usb_dev->dev.bus_id[0], "usb_bus");
-	retval = usb_new_device (usb_dev);
-	if (retval)
-		put_device (&usb_dev->dev);
-	return retval;
-}
-
 static int usb_open(struct inode * inode, struct file * file)
 {
 	int minor = minor(inode->i_rdev);
@@ -2859,7 +2597,6 @@
  */
 static int __init usb_init(void)
 {
-	init_MUTEX(&usb_bus_list_lock);
 	usb_major_init();
 	usbfs_init();
 	usb_hub_init();
@@ -2892,11 +2629,7 @@
 EXPORT_SYMBOL(usb_register);
 EXPORT_SYMBOL(usb_deregister);
 EXPORT_SYMBOL(usb_scan_devices);
-EXPORT_SYMBOL(usb_alloc_bus);
-EXPORT_SYMBOL(usb_free_bus);
-EXPORT_SYMBOL(usb_register_bus);
-EXPORT_SYMBOL(usb_deregister_bus);
-EXPORT_SYMBOL(usb_register_root_hub);
+
 EXPORT_SYMBOL(usb_alloc_dev);
 EXPORT_SYMBOL(usb_free_dev);
 EXPORT_SYMBOL(usb_inc_dev_use);
@@ -2912,10 +2645,6 @@
 EXPORT_SYMBOL(usb_connect);
 EXPORT_SYMBOL(usb_disconnect);
 
-EXPORT_SYMBOL(usb_check_bandwidth);
-EXPORT_SYMBOL(usb_claim_bandwidth);
-EXPORT_SYMBOL(usb_release_bandwidth);
-
 EXPORT_SYMBOL(__usb_get_extra_descriptor);
 
 EXPORT_SYMBOL(usb_get_current_frame_number);
diff -urN linux-2.5.6-pre1/drivers/video/Config.help linux-2.5.6-pre2/drivers/video/Config.help
--- linux-2.5.6-pre1/drivers/video/Config.help	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/drivers/video/Config.help	Thu Feb 28 13:34:22 2002
@@ -516,6 +516,19 @@
   Please read the file Documentation/fb/README-sstfb.txt for supported
   options and other important info  support.
 
+CONFIG_FB_TRIDENT
+  This driver is supposed to support graphics boards with the
+  Trident CyberXXXX/Image/CyberBlade chips mostly found in laptops
+  but also on some motherboards. For more information, read
+  <file:Documentation/fb/tridentfb.txt>
+
+  Say Y if you have such a graphics board.
+
+  The driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want). The
+  module will be called rivafb.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
 CONFIG_FB_SBUS
   Say Y if you want support for SBUS or UPA based frame buffer device.
 
diff -urN linux-2.5.6-pre1/drivers/video/sis/sis_main.c linux-2.5.6-pre2/drivers/video/sis/sis_main.c
--- linux-2.5.6-pre1/drivers/video/sis/sis_main.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/drivers/video/sis/sis_main.c	Thu Feb 28 13:34:22 2002
@@ -2766,7 +2766,7 @@
 	sisfb_crtc_to_var (&default_var);
 
 	fb_info.changevar = NULL;
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &sisfb_ops;
 	fb_info.disp = &disp;
 	fb_info.switch_con = &sisfb_switch;
diff -urN linux-2.5.6-pre1/fs/Config.help linux-2.5.6-pre2/fs/Config.help
--- linux-2.5.6-pre1/fs/Config.help	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/fs/Config.help	Thu Feb 28 13:34:22 2002
@@ -859,6 +859,25 @@
   hard drives and ADFS-formatted floppy disks. This is experimental
   codes, so if you're unsure, say N.
 
+JFS filesystem support
+CONFIG_JFS_FS
+  This is a port of IBM's Journaled Filesystem .  More information is
+  available in the file Documentation/filesystems/jfs.txt.
+
+  If you do not intend to use the JFS filesystem, say N.
+
+JFS Debugging
+CONFIG_JFS_DEBUG
+  If you are experiencing any problems with the JFS filesystem, say
+  Y here.  This will result in additional debugging messages to be
+  written to the system log.  Under normal circumstances, this
+  results in very little overhead.
+
+JFS Statistics
+CONFIG_JFS_STATISTICS
+  Enabling this option will cause statistics from the JFS file system
+  to be made available to the user in the /proc/fs/jfs/ directory.
+
 CONFIG_DEVPTS_FS
   You should say Y here if you said Y to "Unix98 PTY support" above.
   You'll then get a virtual file system which can be mounted on
diff -urN linux-2.5.6-pre1/fs/Config.in linux-2.5.6-pre2/fs/Config.in
--- linux-2.5.6-pre1/fs/Config.in	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/fs/Config.in	Thu Feb 28 13:34:22 2002
@@ -54,6 +54,10 @@
 dep_mbool '  Microsoft Joliet CDROM extensions' CONFIG_JOLIET $CONFIG_ISO9660_FS
 dep_mbool '  Transparent decompression extension' CONFIG_ZISOFS $CONFIG_ISO9660_FS
 
+tristate 'JFS filesystem support' CONFIG_JFS_FS
+dep_mbool '  JFS debugging' CONFIG_JFS_DEBUG $CONFIG_JFS_FS
+dep_mbool '  JFS statistics' CONFIG_JFS_STATISTICS $CONFIG_JFS_FS
+
 tristate 'Minix fs support' CONFIG_MINIX_FS
 
 tristate 'FreeVxFS file system support (VERITAS VxFS(TM) compatible)' CONFIG_VXFS_FS
@@ -102,6 +106,7 @@
 
    dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET
    dep_mbool '  Provide NFSv3 server support' CONFIG_NFSD_V3 $CONFIG_NFSD
+   dep_mbool '  Provide NFS server over TCP support (EXPERIMENTAL)' CONFIG_NFSD_TCP $CONFIG_NFSD $CONFIG_EXPERIMENTAL
 
    if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
       define_tristate CONFIG_SUNRPC y
diff -urN linux-2.5.6-pre1/fs/Makefile linux-2.5.6-pre2/fs/Makefile
--- linux-2.5.6-pre1/fs/Makefile	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/fs/Makefile	Thu Feb 28 13:34:22 2002
@@ -67,6 +67,7 @@
 subdir-$(CONFIG_REISERFS_FS)	+= reiserfs
 subdir-$(CONFIG_DEVPTS_FS)	+= devpts
 subdir-$(CONFIG_SUN_OPENPROMFS)	+= openpromfs
+subdir-$(CONFIG_JFS_FS)		+= jfs
 
 
 obj-$(CONFIG_BINFMT_AOUT)	+= binfmt_aout.o
diff -urN linux-2.5.6-pre1/fs/block_dev.c linux-2.5.6-pre2/fs/block_dev.c
--- linux-2.5.6-pre1/fs/block_dev.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/fs/block_dev.c	Thu Feb 28 13:34:22 2002
@@ -94,7 +94,7 @@
 
 	/* Ok, we're actually changing the blocksize.. */
 	bdev = bdget(kdev_t_to_nr(dev));
-	sync_buffers(dev, 2);
+	sync_buffers(bdev, 2);
 	blksize_size[major(dev)][minor(dev)] = size;
 	bdev->bd_inode->i_blkbits = blksize_bits(size);
 	kill_bdev(bdev);
@@ -198,7 +198,7 @@
 	int ret, err;
 
 	ret = filemap_fdatasync(inode->i_mapping);
-	err = sync_buffers(inode->i_rdev, 1);
+	err = sync_buffers(inode->i_bdev, 1);
 	if (err && !ret)
 		ret = err;
 	err = filemap_fdatawait(inode->i_mapping);
diff -urN linux-2.5.6-pre1/fs/buffer.c linux-2.5.6-pre2/fs/buffer.c
--- linux-2.5.6-pre1/fs/buffer.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/fs/buffer.c	Thu Feb 28 13:34:22 2002
@@ -189,7 +189,7 @@
  * return without it!
  */
 #define NRSYNC (32)
-static int write_some_buffers(kdev_t dev)
+static int write_some_buffers(struct block_device *bdev)
 {
 	struct buffer_head *next;
 	struct buffer_head *array[NRSYNC];
@@ -203,7 +203,7 @@
 		struct buffer_head * bh = next;
 		next = bh->b_next_free;
 
-		if (!kdev_none(dev) && !kdev_same(bh->b_dev, dev))
+		if (bdev && bh->b_bdev != bdev)
 			continue;
 		if (test_and_set_bit(BH_Lock, &bh->b_state))
 			continue;
@@ -231,11 +231,11 @@
 /*
  * Write out all buffers on the dirty list.
  */
-static void write_unlocked_buffers(kdev_t dev)
+static void write_unlocked_buffers(struct block_device *bdev)
 {
 	do {
 		spin_lock(&lru_list_lock);
-	} while (write_some_buffers(dev));
+	} while (write_some_buffers(bdev));
 	run_task_queue(&tq_disk);
 }
 
@@ -245,7 +245,7 @@
  * This must be called with the LRU lock held, and
  * will return with it released.
  */
-static int wait_for_buffers(kdev_t dev, int index, int refile)
+static int wait_for_buffers(struct block_device *bdev, int index, int refile)
 {
 	struct buffer_head * next;
 	int nr;
@@ -261,7 +261,7 @@
 				__refile_buffer(bh);
 			continue;
 		}
-		if (!kdev_none(dev) && !kdev_same(bh->b_dev, dev))
+		if (bdev && bh->b_bdev !=  bdev)
 			continue;
 
 		get_bh(bh);
@@ -274,17 +274,17 @@
 	return 0;
 }
 
-static inline void wait_for_some_buffers(kdev_t dev)
+static inline void wait_for_some_buffers(struct block_device *bdev)
 {
 	spin_lock(&lru_list_lock);
-	wait_for_buffers(dev, BUF_LOCKED, 1);
+	wait_for_buffers(bdev, BUF_LOCKED, 1);
 }
 
-static int wait_for_locked_buffers(kdev_t dev, int index, int refile)
+static int wait_for_locked_buffers(struct block_device *bdev, int index, int refile)
 {
 	do {
 		spin_lock(&lru_list_lock);
-	} while (wait_for_buffers(dev, index, refile));
+	} while (wait_for_buffers(bdev, index, refile));
 	return 0;
 }
 
@@ -298,7 +298,29 @@
  * We will ultimately want to put these in a separate list, but for
  * now we search all of the lists for dirty buffers.
  */
-int sync_buffers(kdev_t dev, int wait)
+int sync_buffers(struct block_device *bdev, int wait)
+{
+	int err = 0;
+
+	if (!bdev)
+		return 0;
+
+	/* One pass for no-wait, three for wait:
+	 * 0) write out all dirty, unlocked buffers;
+	 * 1) wait for all dirty locked buffers;
+	 * 2) write out all dirty, unlocked buffers;
+	 * 2) wait for completion by waiting for all buffers to unlock.
+	 */
+	write_unlocked_buffers(bdev);
+	if (wait) {
+		err = wait_for_locked_buffers(bdev, BUF_DIRTY, 0);
+		write_unlocked_buffers(bdev);
+		err |= wait_for_locked_buffers(bdev, BUF_LOCKED, 1);
+	}
+	return err;
+}
+
+int sync_all_buffers(int wait)
 {
 	int err = 0;
 
@@ -308,19 +330,18 @@
 	 * 2) write out all dirty, unlocked buffers;
 	 * 2) wait for completion by waiting for all buffers to unlock.
 	 */
-	write_unlocked_buffers(dev);
+	write_unlocked_buffers(NULL);
 	if (wait) {
-		err = wait_for_locked_buffers(dev, BUF_DIRTY, 0);
-		write_unlocked_buffers(dev);
-		err |= wait_for_locked_buffers(dev, BUF_LOCKED, 1);
+		err = wait_for_locked_buffers(NULL, BUF_DIRTY, 0);
+		write_unlocked_buffers(NULL);
+		err |= wait_for_locked_buffers(NULL, BUF_LOCKED, 1);
 	}
 	return err;
 }
 
 int fsync_super(struct super_block *sb)
 {
-	kdev_t dev = sb->s_dev;
-	sync_buffers(dev, 0);
+	sync_buffers(sb->s_bdev, 0);
 
 	lock_kernel();
 	sync_inodes_sb(sb);
@@ -331,48 +352,48 @@
 	unlock_super(sb);
 	unlock_kernel();
 
-	return sync_buffers(dev, 1);
+	return sync_buffers(sb->s_bdev, 1);
 }
 
 int fsync_no_super(struct block_device *bdev)
 {
-	kdev_t dev = to_kdev_t(bdev->bd_dev);
-	sync_buffers(dev, 0);
-	return sync_buffers(dev, 1);
+	sync_buffers(bdev, 0);
+	return sync_buffers(bdev, 1);
 }
 
 int fsync_dev(kdev_t dev)
 {
-	sync_buffers(dev, 0);
-
-	lock_kernel();
-	sync_inodes(dev);
-	if (!kdev_none(dev)) {
-		struct super_block *sb = get_super(dev);
-		if (sb) {
-			DQUOT_SYNC(sb);
-			drop_super(sb);
-		}
-	} else
-			DQUOT_SYNC(NULL);
-	sync_supers(dev);
-	unlock_kernel();
-
-	return sync_buffers(dev, 1);
+	struct block_device *bdev = bdget(kdev_t_to_nr(dev));
+	if (bdev) {
+		int res = fsync_bdev(bdev);
+		bdput(bdev);
+		return res;
+	}
+	return 0;
 }
 
-/*
- * There's no real reason to pretend we should
- * ever do anything differently
- */
-void sync_dev(kdev_t dev)
+int fsync_bdev(struct block_device *bdev)
 {
-	fsync_dev(dev);
+	struct super_block *sb = get_super(to_kdev_t(bdev->bd_dev));
+	if (sb) {
+		int res = fsync_super(sb);
+		drop_super(sb);
+		return res;
+	}
+	return fsync_no_super(bdev);
 }
 
 asmlinkage long sys_sync(void)
 {
-	fsync_dev(NODEV);
+	sync_all_buffers(0);
+
+	lock_kernel();
+	sync_inodes();
+	DQUOT_SYNC(NULL);
+	sync_supers();
+	unlock_kernel();
+
+	sync_all_buffers(1);
 	return 0;
 }
 
@@ -384,7 +405,6 @@
 {
 	struct inode * inode = dentry->d_inode;
 	struct super_block * sb;
-	kdev_t dev;
 	int ret;
 
 	lock_kernel();
@@ -399,8 +419,7 @@
 	unlock_super(sb);
 
 	/* .. finally sync the buffers to disk */
-	dev = inode->i_dev;
-	ret = sync_buffers(dev, 1);
+	ret = sync_buffers(sb->s_bdev, 1);
 	unlock_kernel();
 	return ret;
 }
@@ -663,7 +682,6 @@
 {
 	int i, nlist, slept;
 	struct buffer_head * bh, * bh_next;
-	kdev_t dev = to_kdev_t(bdev->bd_dev);	/* will become bdev */
 
  retry:
 	slept = 0;
@@ -676,7 +694,7 @@
 			bh_next = bh->b_next_free;
 
 			/* Another device? */
-			if (!kdev_same(bh->b_dev, dev))
+			if (bh->b_bdev != bdev)
 				continue;
 			/* Not hashed? */
 			if (!bh->b_pprev)
@@ -998,7 +1016,7 @@
 
 	/* If we're getting into imbalance, start write-out */
 	spin_lock(&lru_list_lock);
-	write_some_buffers(NODEV);
+	write_some_buffers(NULL);
 
 	/*
 	 * And if we're _really_ out of balance, wait for
@@ -1007,7 +1025,7 @@
 	 * This will throttle heavy writers.
 	 */
 	if (state > 0) {
-		wait_for_some_buffers(NODEV);
+		wait_for_some_buffers(NULL);
 		wakeup_bdflush();
 	}
 }
@@ -2616,7 +2634,7 @@
 {
 	lock_kernel();
 	sync_unlocked_inodes();
-	sync_supers(NODEV);
+	sync_supers();
 	unlock_kernel();
 
 	for (;;) {
@@ -2626,7 +2644,7 @@
 		bh = lru_list[BUF_DIRTY];
 		if (!bh || time_before(jiffies, bh->b_flushtime))
 			break;
-		if (write_some_buffers(NODEV))
+		if (write_some_buffers(NULL))
 			continue;
 		return 0;
 	}
@@ -2725,8 +2743,8 @@
 		CHECK_EMERGENCY_SYNC
 
 		spin_lock(&lru_list_lock);
-		if (!write_some_buffers(NODEV) || balance_dirty_state() < 0) {
-			wait_for_some_buffers(NODEV);
+		if (!write_some_buffers(NULL) || balance_dirty_state() < 0) {
+			wait_for_some_buffers(NULL);
 			interruptible_sleep_on(&bdflush_wait);
 		}
 	}
@@ -2757,7 +2775,7 @@
 	complete((struct completion *)startup);
 
 	for (;;) {
-		wait_for_some_buffers(NODEV);
+		wait_for_some_buffers(NULL);
 
 		/* update interval */
 		interval = bdf_prm.b_un.interval;
diff -urN linux-2.5.6-pre1/fs/inode.c linux-2.5.6-pre2/fs/inode.c
--- linux-2.5.6-pre1/fs/inode.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/fs/inode.c	Thu Feb 28 13:34:22 2002
@@ -419,23 +419,15 @@
  *	writes them out, and puts them back on the normal list.
  */
 
-void sync_inodes(kdev_t dev)
+void sync_inodes(void)
 {
 	struct super_block * s;
-
 	/*
 	 * Search the super_blocks array for the device(s) to sync.
 	 */
-	if (!kdev_none(dev)) {
-		if ((s = get_super(dev)) != NULL) {
-			sync_inodes_sb(s);
-			drop_super(s);
-		}
-	} else {
-		while ((s = get_super_to_sync()) != NULL) {
-			sync_inodes_sb(s);
-			drop_super(s);
-		}
+	while ((s = get_super_to_sync()) != NULL) {
+		sync_inodes_sb(s);
+		drop_super(s);
 	}
 }
 
diff -urN linux-2.5.6-pre1/fs/intermezzo/cache.c linux-2.5.6-pre2/fs/intermezzo/cache.c
--- linux-2.5.6-pre1/fs/intermezzo/cache.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/fs/intermezzo/cache.c	Thu Feb 28 13:34:22 2002
@@ -44,16 +44,15 @@
 #define CACHES_MASK CACHES_SIZE - 1
 static struct list_head presto_caches[CACHES_SIZE];
 
-static inline int presto_cache_hash(kdev_t dev)
+static inline int presto_cache_hash(struct super_block *sb)
 {
-        return (CACHES_MASK) & ((0x000F & (kdev_val(dev))) + ((0x0F00 & (kdev_val(dev))) >>8));
+        return (CACHES_MASK) & ((unsigned long)sb / L1_CACHE_BYTES);
 }
 
-inline void presto_cache_add(struct presto_cache *cache, kdev_t dev)
+inline void presto_cache_add(struct presto_cache *cache, struct super_block *sb)
 {
         list_add(&cache->cache_chain,
-                 &presto_caches[presto_cache_hash(dev)]);
-        cache->cache_dev = dev;
+                 &presto_caches[presto_cache_hash(sb)]);
 }
 
 inline void presto_init_cache_hash(void)
@@ -65,17 +64,16 @@
 }
 
 /* map a device to a cache */
-struct presto_cache *presto_find_cache(kdev_t dev)
+struct presto_cache *presto_find_cache(struct super_block *sb)
 {
         struct presto_cache *cache;
         struct list_head *lh, *tmp;
 
-        lh = tmp = &(presto_caches[presto_cache_hash(dev)]);
+        lh = tmp = &(presto_caches[presto_cache_hash(sb)]);
         while ( (tmp = lh->next) != lh ) {
                 cache = list_entry(tmp, struct presto_cache, cache_chain);
-                if ( kdev_same(cache->cache_dev, dev) ) {
+                if (cache->cache_sb == sb)
                         return cache;
-                }
         }
         return NULL;
 }
@@ -87,10 +85,10 @@
         struct presto_cache *cache;
 
         /* find the correct presto_cache here, based on the device */
-        cache = presto_find_cache(inode->i_dev);
+        cache = presto_find_cache(inode->i_sb);
         if ( !cache ) {
-                printk("WARNING: no presto cache for dev %x, ino %ld\n",
-                       kdev_val(inode->i_dev), inode->i_ino);
+                printk("WARNING: no presto cache for dev %s, ino %ld\n",
+                       inode->i_sb->s_id, inode->i_ino);
                 EXIT;
                 return NULL;
         }
@@ -174,7 +172,7 @@
         cache = presto_get_cache(inode);
         if ( !cache )
                 return 0;
-        return (kdev_same(inode->i_dev, cache->cache_dev));
+        return (inode->i_sb == cache->cache_sb);
 }
 
 /* setup a cache structure when we need one */
diff -urN linux-2.5.6-pre1/fs/intermezzo/inode.c linux-2.5.6-pre2/fs/intermezzo/inode.c
--- linux-2.5.6-pre1/fs/intermezzo/inode.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/fs/intermezzo/inode.c	Thu Feb 28 13:34:22 2002
@@ -113,7 +113,7 @@
         struct list_head *lh;
 
 	ENTRY;
-        cache = presto_find_cache(sb->s_dev);
+        cache = presto_find_cache(sb);
         if (!cache) {
 		EXIT;
                 goto exit;
diff -urN linux-2.5.6-pre1/fs/intermezzo/presto.c linux-2.5.6-pre2/fs/intermezzo/presto.c
--- linux-2.5.6-pre1/fs/intermezzo/presto.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/fs/intermezzo/presto.c	Thu Feb 28 13:34:22 2002
@@ -71,8 +71,8 @@
         cache = presto_get_cache(inode);
         CDEBUG(D_PSDEV, "\n");
         if ( !cache ) {
-                printk("PRESTO: BAD: cannot find cache for dev %x, ino %ld\n",
-                       kdev_val(inode->i_dev), inode->i_ino);
+                printk("PRESTO: BAD: cannot find cache for dev %s, ino %ld\n",
+                       inode->i_sb->s_id, inode->i_ino);
                 EXIT;
                 return -1;
         }
diff -urN linux-2.5.6-pre1/fs/intermezzo/super.c linux-2.5.6-pre2/fs/intermezzo/super.c
--- linux-2.5.6-pre1/fs/intermezzo/super.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre2/fs/intermezzo/super.c	Thu Feb 28 13:34:22 2002
@@ -39,7 +39,7 @@
 #endif
 
 extern struct presto_cache *presto_init_cache(void);
-extern inline void presto_cache_add(struct presto_cache *cache, kdev_t dev);
+extern inline void presto_cache_add(struct presto_cache *cache, struct super_block *sb);
 extern inline void presto_init_cache_hash(void);
 
 int presto_remount(struct super_block *, int *, char *);
@@ -325,7 +325,7 @@
         filter_setup_journal_ops(cache->cache_filter, cache->cache_type); 
 
         /* we now know the dev of the cache: hash the cache */
-        presto_cache_add(cache, mysb->s_dev);
+        presto_cache_add(cache, mysb);
 
         /* make sure we have our own super operations: mysb
            still contains the cache operations */
@@ -402,7 +402,7 @@
                 }
         }
 
-        cache = presto_find_cache(sb->s_dev);
+        cache = presto_find_cache(sb);
         if (!cache) {
                 printk(__FUNCTION__ ": cannot find cache on remount\n");
                 err = -ENODEV;
diff -urN linux-2.5.6-pre1/fs/intermezzo/vfs.c linux-2.5.6-pre2/fs/intermezzo/vfs.c
--- linux-2.5.6-pre1/fs/intermezzo/vfs.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/fs/intermezzo/vfs.c	Thu Feb 28 13:34:22 2002
@@ -602,7 +602,7 @@
                 goto exit_lock;
 
         error = -EXDEV;
-        if (!kdev_same(dir->d_inode->i_dev, inode->i_dev))
+        if (dir->d_inode->i_sb != inode->i_sb)
                 goto exit_lock;
 
         /*
@@ -1609,7 +1609,7 @@
         if (error)
                 return error;
 
-        if (!kdev_same(new_dir->i_dev, old_dir->i_dev))
+        if (new_dir->i_sb != old_dir->i_sb)
                 return -EXDEV;
 
         if (!new_dentry->d_inode)
@@ -1690,7 +1690,7 @@
         if (error)
                 return error;
 
-        if (!kdev_same(new_dir->i_dev, old_dir->i_dev))
+        if (new_dir->i_sb != old_dir->i_sb)
                 return -EXDEV;
 
         if (!new_dentry->d_inode)
diff -urN linux-2.5.6-pre1/fs/jffs/intrep.c linux-2.5.6-pre2/fs/jffs/intrep.c
--- linux-2.5.6-pre1/fs/jffs/intrep.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/fs/jffs/intrep.c	Thu Feb 28 13:34:22 2002
@@ -428,7 +428,7 @@
 
 /* Build a control block for the file system.  */
 static struct jffs_control *
-jffs_create_control(kdev_t dev)
+jffs_create_control(struct super_block *sb)
 {
 	struct jffs_control *c;
 	register int s = sizeof(struct jffs_control);
@@ -451,7 +451,7 @@
 	DJM(no_hash++);
 	for (i = 0; i < c->hash_len; i++)
 		INIT_LIST_HEAD(&c->hash[i]);
-	if (!(c->fmc = jffs_build_begin(c, dev))) {
+	if (!(c->fmc = jffs_build_begin(c, sb->s_dev))) {
 		goto fail_fminit;
 	}
 	c->next_ino = JFFS_MIN_INO + 1;
@@ -549,7 +549,7 @@
 
 	D2(printk("jffs_build_fs()\n"));
 
-	if (!(c = jffs_create_control(sb->s_dev))) {
+	if (!(c = jffs_create_control(sb))) {
 		return -ENOMEM;
 	}
 	c->building_fs = 1;
@@ -563,7 +563,7 @@
 			D1(printk("jffs_build_fs: Cleaning up all control structures,"
 				  " reallocating them and trying mount again.\n"));
 			jffs_cleanup_control(c);
-			if (!(c = jffs_create_control(sb->s_dev))) {
+			if (!(c = jffs_create_control(sb))) {
 				return -ENOMEM;
 			}
 			c->building_fs = 1;
@@ -1932,8 +1932,7 @@
    the buffer.  */
 static int
 jffs_get_node_data(struct jffs_file *f, struct jffs_node *node, 
-		   unsigned char *buf,__u32 node_offset, __u32 max_size,
-		   kdev_t dev)
+		   unsigned char *buf,__u32 node_offset, __u32 max_size)
 {
 	struct jffs_fmcontrol *fmc = f->c->fmc;
 	__u32 pos = node->fm->offset + node->fm_offset + node_offset;
@@ -2003,8 +2002,7 @@
 		}
 		else if ((r = jffs_get_node_data(f, node, &buf[read_data],
 						 node_offset,
-						 size - read_data,
-						 f->c->sb->s_dev)) < 0) {
+						 size - read_data)) < 0) {
 			return r;
 		}
 		read_data += r;
@@ -2643,7 +2641,7 @@
 void
 jffs_print_memory_allocation_statistics(void)
 {
-	static long printout = 0;
+	static long printout;
 	printk("________ Memory printout #%ld ________\n", ++printout);
 	printk("no_jffs_file = %ld\n", no_jffs_file);
 	printk("no_jffs_node = %ld\n", no_jffs_node);
diff -urN linux-2.5.6-pre1/fs/jffs2/dir.c linux-2.5.6-pre2/fs/jffs2/dir.c
--- linux-2.5.6-pre1/fs/jffs2/dir.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/fs/jffs2/dir.c	Thu Feb 28 13:34:22 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: dir.c,v 1.42 2001/05/24 22:24:39 dwmw2 Exp $
+ * $Id: dir.c,v 1.45.2.5 2002/02/23 14:31:09 dwmw2 Exp $
  *
  */
 
@@ -39,6 +39,7 @@
 #include <linux/slab.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>
@@ -181,11 +182,11 @@
 		}
 		D2(printk(KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d\n", offset, fd->name, fd->ino, fd->type));
 		if (filldir(dirent, fd->name, strlen(fd->name), offset, fd->ino, fd->type) < 0)
-			goto out;
+			break;
 		offset++;
 	}
- out:
 	up(&f->sem);
+ out:
 	filp->f_pos = offset;
 	return 0;
 }
@@ -305,7 +306,7 @@
 	rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
 
 	rd->pino = dir_i->i_ino;
-	rd->version = dir_f->highest_version++;
+	rd->version = ++dir_f->highest_version;
 	rd->ino = inode->i_ino;
 	rd->mctime = CURRENT_TIME;
 	rd->nsize = namelen;
@@ -316,17 +317,21 @@
 	fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
 
 	jffs2_complete_reservation(c);
-	jffs2_free_raw_dirent(rd);
-	
+
 	if (IS_ERR(fd)) {
 		/* dirent failed to write. Delete the inode normally 
 		   as if it were the final unlink() */
+		jffs2_free_raw_dirent(rd);
 		up(&dir_f->sem);
 		jffs2_clear_inode(inode);
 		unlock_kernel();
 		return PTR_ERR(fd);
 	}
 
+	dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
+
+	jffs2_free_raw_dirent(rd);
+
 	/* Link the fd into the inode's list, obsoleting an old
 	   one if necessary. */
 	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
@@ -373,7 +378,7 @@
 	rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
 
 	rd->pino = dir_i->i_ino;
-	rd->version = dir_f->highest_version++;
+	rd->version = ++dir_f->highest_version;
 	rd->ino = 0;
 	rd->mctime = CURRENT_TIME;
 	rd->nsize = dentry->d_name.len;
@@ -464,7 +469,7 @@
 	rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
 
 	rd->pino = dir_i->i_ino;
-	rd->version = dir_f->highest_version++;
+	rd->version = ++dir_f->highest_version;
 	rd->ino = old_dentry->d_inode->i_ino;
 	rd->mctime = CURRENT_TIME;
 	rd->nsize = dentry->d_name.len;
@@ -503,6 +508,9 @@
 {
 	int ret;
 
+	if (S_ISDIR(old_dentry->d_inode->i_mode))
+		return -EPERM;
+
 	lock_kernel();
 	ret = jffs2_do_link(old_dentry, dir_i, dentry, 0);
 	if (!ret) {
@@ -567,7 +575,7 @@
 
 	f = JFFS2_INODE_INFO(inode);
 
-	ri->dsize = ri->csize = strlen(target);
+	inode->i_size = ri->isize = ri->dsize = ri->csize = strlen(target);
 	ri->totlen = sizeof(*ri) + ri->dsize;
 	ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4);
 
@@ -628,7 +636,7 @@
 	rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
 
 	rd->pino = dir_i->i_ino;
-	rd->version = dir_f->highest_version++;
+	rd->version = ++dir_f->highest_version;
 	rd->ino = inode->i_ino;
 	rd->mctime = CURRENT_TIME;
 	rd->nsize = namelen;
@@ -639,16 +647,19 @@
 	fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
 	
 	jffs2_complete_reservation(c);
-	jffs2_free_raw_dirent(rd);
 	
 	if (IS_ERR(fd)) {
 		/* dirent failed to write. Delete the inode normally 
 		   as if it were the final unlink() */
+		jffs2_free_raw_dirent(rd);
 		up(&dir_f->sem);
 		jffs2_clear_inode(inode);
 		unlock_kernel();
 		return PTR_ERR(fd);
 	}
+	dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
+
+	jffs2_free_raw_dirent(rd);
 
 	/* Link the fd into the inode's list, obsoleting an old
 	   one if necessary. */
@@ -768,7 +779,7 @@
 	rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
 
 	rd->pino = dir_i->i_ino;
-	rd->version = dir_f->highest_version++;
+	rd->version = ++dir_f->highest_version;
 	rd->ino = inode->i_ino;
 	rd->mctime = CURRENT_TIME;
 	rd->nsize = namelen;
@@ -779,17 +790,21 @@
 	fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
 	
 	jffs2_complete_reservation(c);
-	jffs2_free_raw_dirent(rd);
 	
 	if (IS_ERR(fd)) {
 		/* dirent failed to write. Delete the inode normally 
 		   as if it were the final unlink() */
+		jffs2_free_raw_dirent(rd);
 		up(&dir_f->sem);
 		jffs2_clear_inode(inode);
 		unlock_kernel();
 		return PTR_ERR(fd);
 	}
 
+	dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
+
+	jffs2_free_raw_dirent(rd);
+
 	/* Link the fd into the inode's list, obsoleting an old
 	   one if necessary. */
 	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
@@ -841,8 +856,7 @@
 	
 	c = JFFS2_SB_INFO(dir_i->i_sb);
 	
-	if ((mode & S_IFMT) == S_IFBLK ||
-	    (mode & S_IFMT) == S_IFCHR) {
+	if (S_ISBLK(mode) || S_ISCHR(mode)) {
 		dev = (MAJOR(rdev) << 8) | MINOR(rdev);
 		devlen = sizeof(dev);
 	}
@@ -933,7 +947,7 @@
 	rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
 
 	rd->pino = dir_i->i_ino;
-	rd->version = dir_f->highest_version++;
+	rd->version = ++dir_f->highest_version;
 	rd->ino = inode->i_ino;
 	rd->mctime = CURRENT_TIME;
 	rd->nsize = namelen;
@@ -947,17 +961,21 @@
 	fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
 	
 	jffs2_complete_reservation(c);
-	jffs2_free_raw_dirent(rd);
 	
 	if (IS_ERR(fd)) {
 		/* dirent failed to write. Delete the inode normally 
 		   as if it were the final unlink() */
+		jffs2_free_raw_dirent(rd);
 		up(&dir_f->sem);
 		jffs2_clear_inode(inode);
 		unlock_kernel();
 		return PTR_ERR(fd);
 	}
 
+	dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
+
+	jffs2_free_raw_dirent(rd);
+
 	/* Link the fd into the inode's list, obsoleting an old
 	   one if necessary. */
 	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
@@ -965,6 +983,7 @@
 	unlock_kernel();
 
 	d_instantiate(dentry, inode);
+
 	return 0;
 }
 
@@ -989,20 +1008,16 @@
 	ret = jffs2_do_unlink(old_dir_i, old_dentry, 1);
 	
 	if (ret) {
-		/* Try to delete the _new_ link to return a clean failure */
-		int ret2 = jffs2_do_unlink(new_dir_i, new_dentry, 1);
-		if (ret2) {
-			struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
-			down(&f->sem);
-			old_dentry->d_inode->i_nlink = f->inocache->nlink++;
-			up(&f->sem);
+		/* Oh shit. We really ought to make a single node which can do both atomically */
+		struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
+		down(&f->sem);
+		old_dentry->d_inode->i_nlink = f->inocache->nlink++;
+		up(&f->sem);
 		       
-			printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (old err %d, new err %d). You now have a hard link\n", ret, ret2);
-			/* Might as well let the VFS know */
-			d_instantiate(new_dentry, old_dentry->d_inode);
-			atomic_inc(&old_dentry->d_inode->i_count);
-		}
-		
+		printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
+		/* Might as well let the VFS know */
+		d_instantiate(new_dentry, old_dentry->d_inode);
+		atomic_inc(&old_dentry->d_inode->i_count);
 	}
 	unlock_kernel();
 	return ret;
diff -urN linux-2.5.6-pre1/fs/jffs2/erase.c linux-2.5.6-pre2/fs/jffs2/erase.c
--- linux-2.5.6-pre1/fs/jffs2/erase.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/fs/jffs2/erase.c	Thu Feb 28 13:34:22 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: erase.c,v 1.23 2001/09/19 21:51:11 dwmw2 Exp $
+ * $Id: erase.c,v 1.24 2001/12/06 16:38:38 dwmw2 Exp $
  *
  */
 #include <linux/kernel.h>
@@ -214,8 +214,8 @@
 
 	D2({
 		int i=0;
-        struct jffs2_raw_node_ref *this;		
-        printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG);
+		struct jffs2_raw_node_ref *this;
+		printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG);
 
 		this = ic->nodes;
 	   
@@ -262,7 +262,11 @@
 
 void jffs2_mark_erased_blocks(struct jffs2_sb_info *c)
 {
-	static struct jffs2_unknown_node marker = {JFFS2_MAGIC_BITMASK, JFFS2_NODETYPE_CLEANMARKER, sizeof(struct jffs2_unknown_node)};
+	static struct jffs2_unknown_node marker = {
+			magic:		JFFS2_MAGIC_BITMASK,
+			nodetype:	JFFS2_NODETYPE_CLEANMARKER,
+			totlen:		sizeof(struct jffs2_unknown_node)
+	};
 	struct jffs2_eraseblock *jeb;
 	struct jffs2_raw_node_ref *marker_ref;
 	unsigned char *ebuf;
diff -urN linux-2.5.6-pre1/fs/jffs2/file.c linux-2.5.6-pre2/fs/jffs2/file.c
--- linux-2.5.6-pre1/fs/jffs2/file.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/fs/jffs2/file.c	Thu Feb 28 13:34:22 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: file.c,v 1.58 2001/09/20 15:28:31 dwmw2 Exp $
+ * $Id: file.c,v 1.58.2.1 2002/02/23 14:25:36 dwmw2 Exp $
  *
  */
 
@@ -102,15 +102,14 @@
 	   must read the original data associated with the node
 	   (i.e. the device numbers or the target name) and write
 	   it out again with the appropriate data attached */
-	if ((inode->i_mode & S_IFMT) == S_IFBLK ||
-	    (inode->i_mode & S_IFMT) == S_IFCHR) {
+	if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
 		/* For these, we don't actually need to read the old node */
 		dev =  (major(dentry->d_inode->i_rdev) << 8) | 
 			minor(dentry->d_inode->i_rdev);
 		mdata = (char *)&dev;
 		mdatalen = sizeof(dev);
 		D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
-	} else if ((inode->i_mode & S_IFMT) == S_IFLNK) {
+	} else if (S_ISLNK(inode->i_mode)) {
 		mdatalen = f->metadata->size;
 		mdata = kmalloc(f->metadata->size, GFP_USER);
 		if (!mdata)
@@ -125,7 +124,7 @@
 
 	ri = jffs2_alloc_raw_inode();
 	if (!ri) {
-		if ((inode->i_mode & S_IFMT) == S_IFLNK)
+		if (S_ISLNK(inode->i_mode))
 			kfree(mdata);
 		return -ENOMEM;
 	}
@@ -133,7 +132,7 @@
 	ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL);
 	if (ret) {
 		jffs2_free_raw_inode(ri);
-		if ((inode->i_mode & S_IFMT) == S_IFLNK)
+		if (S_ISLNK(inode->i_mode))
 			 kfree(mdata);
 		return ret;
 	}
@@ -177,7 +176,7 @@
 		ri->data_crc = 0;
 
 	new_metadata = jffs2_write_dnode(inode, ri, mdata, mdatalen, phys_ofs, NULL);
-	if ((inode->i_mode & S_IFMT) == S_IFLNK)
+	if (S_ISLNK(inode->i_mode))
 		kfree(mdata);
 
 	jffs2_complete_reservation(c);
diff -urN linux-2.5.6-pre1/fs/jffs2/gc.c linux-2.5.6-pre2/fs/jffs2/gc.c
--- linux-2.5.6-pre1/fs/jffs2/gc.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/fs/jffs2/gc.c	Thu Feb 28 13:34:22 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: gc.c,v 1.52 2001/09/19 21:53:47 dwmw2 Exp $
+ * $Id: gc.c,v 1.52.2.2 2002/02/23 14:25:36 dwmw2 Exp $
  *
  */
 
@@ -266,15 +266,14 @@
 	__u32 alloclen, phys_ofs;
 	int ret;
 
-	if ((inode->i_mode & S_IFMT) == S_IFBLK ||
-	    (inode->i_mode & S_IFMT) == S_IFCHR) {
+	if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
 		/* For these, we don't actually need to read the old node */
 		dev =  (major(inode->i_rdev) << 8) | 
 			minor(inode->i_rdev);
 		mdata = (char *)&dev;
 		mdatalen = sizeof(dev);
 		D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen));
-	} else if ((inode->i_mode & S_IFMT) == S_IFLNK) {
+	} else if (S_ISLNK(inode->i_mode)) {
 		mdatalen = fn->size;
 		mdata = kmalloc(fn->size, GFP_KERNEL);
 		if (!mdata) {
@@ -331,7 +330,7 @@
 	jffs2_free_full_dnode(fn);
 	f->metadata = new_fn;
  out:
-	if ((inode->i_mode & S_IFMT) == S_IFLNK)
+	if (S_ISLNK(inode->i_mode))
 		kfree(mdata);
 	return ret;
 }
@@ -466,8 +465,8 @@
 		ri.ino = inode->i_ino;
 		ri.version = ++f->highest_version;
 		ri.offset = start;
-		ri.csize = end - start;
-		ri.dsize = 0;
+		ri.dsize = end - start;
+		ri.csize = 0;
 		ri.compr = JFFS2_COMPR_ZERO;
 	}
 	ri.mode = inode->i_mode;
diff -urN linux-2.5.6-pre1/fs/jffs2/malloc.c linux-2.5.6-pre2/fs/jffs2/malloc.c
--- linux-2.5.6-pre1/fs/jffs2/malloc.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/fs/jffs2/malloc.c	Thu Feb 28 13:34:22 2002
@@ -139,7 +139,7 @@
 	if (!jffs2_inode_cachep)
 		goto err;
 
-	inode_cache_slab = kmem_cache_create("jffs2_inode_cache", sizeof(struct jffs2_inode_cache), 0, JFFS2_SLAB_POISON, NULL, NULL);
+	inode_cache_slab = kmem_cache_create("jffs2_inode", sizeof(struct jffs2_inode_cache), 0, JFFS2_SLAB_POISON, NULL, NULL);
 
 	if (inode_cache_slab)
 		return 0;
diff -urN linux-2.5.6-pre1/fs/jffs2/nodelist.c linux-2.5.6-pre2/fs/jffs2/nodelist.c
--- linux-2.5.6-pre1/fs/jffs2/nodelist.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/fs/jffs2/nodelist.c	Thu Feb 28 13:34:22 2002
@@ -1,7 +1,7 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001 Red Hat, Inc.
+ * Copyright (C) 2001, 2002 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
  *
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: nodelist.c,v 1.30 2001/11/14 10:35:21 dwmw2 Exp $
+ * $Id: nodelist.c,v 1.30.2.3 2002/02/23 14:04:44 dwmw2 Exp $
  *
  */
 
@@ -94,7 +94,8 @@
 
 int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f,
 			  struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
-			  __u32 *highest_version)
+			  __u32 *highest_version, __u32 *latest_mctime,
+			  __u32 *mctime_ver)
 {
 	struct jffs2_raw_node_ref *ref = f->inocache->nodes;
 	struct jffs2_tmp_dnode_info *tn, *ret_tn = NULL;
@@ -104,6 +105,8 @@
 	size_t retlen;
 	int err;
 
+	*mctime_ver = 0;
+
 	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);
@@ -115,7 +118,7 @@
 			D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref->flash_offset &~3));
 			continue;
 		}
-		err = c->mtd->read(c->mtd, (ref->flash_offset & ~3), sizeof(node), &retlen, (void *)&node);
+		err = c->mtd->read(c->mtd, (ref->flash_offset & ~3), min(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->flash_offset) & ~3);
 			goto free_out;
@@ -123,7 +126,7 @@
 			
 
 			/* Check we've managed to read at least the common node header */
-		if (retlen < sizeof(node.u)) {
+		if (retlen < min(ref->totlen, sizeof(node.u))) {
 			printk(KERN_WARNING "short read in get_inode_nodes()\n");
 			err = -EIO;
 			goto free_out;
@@ -153,15 +156,22 @@
 			fd->version = node.d.version;
 			fd->ino = node.d.ino;
 			fd->type = node.d.type;
-				/* memcpy as much of the name as possible from the raw
-				   dirent we've already read from the flash
-				*/
+
+			/* Pick out the mctime of the latest dirent */
+			if(fd->version > *mctime_ver) {
+				*mctime_ver = fd->version;
+				*latest_mctime = node.d.mctime;
+			}
+
+			/* memcpy as much of the name as possible from the raw
+			   dirent we've already read from the flash
+			*/
 			if (retlen > sizeof(struct jffs2_raw_dirent))
 				memcpy(&fd->name[0], &node.d.name[0], min((__u32)node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent))));
 				
-				/* Do we need to copy any more of the name directly
-				   from the flash?
-				*/
+			/* Do we need to copy any more of the name directly
+			   from the flash?
+			*/
 			if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) {
 				int already = retlen - sizeof(struct jffs2_raw_dirent);
 					
@@ -217,7 +227,12 @@
 			}
 			tn->version = node.i.version;
 			tn->fn->ofs = node.i.offset;
-			tn->fn->size = node.i.dsize;
+			/* There was a bug where we wrote hole nodes out with
+			   csize/dsize swapped. Deal with it */
+			if (node.i.compr == JFFS2_COMPR_ZERO && !node.i.dsize && node.i.csize)
+				tn->fn->size = node.i.csize;
+			else // normal case...
+				tn->fn->size = node.i.dsize;
 			tn->fn->raw = ref;
 			D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n", ref->flash_offset &~3, node.i.version, node.i.offset, node.i.dsize));
 			jffs2_add_tn_to_list(tn, &ret_tn);
@@ -242,6 +257,7 @@
 	}
 	*tnp = ret_tn;
 	*fdp = ret_fd;
+
 	return 0;
 
  free_out:
diff -urN linux-2.5.6-pre1/fs/jffs2/nodelist.h linux-2.5.6-pre2/fs/jffs2/nodelist.h
--- linux-2.5.6-pre1/fs/jffs2/nodelist.h	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/fs/jffs2/nodelist.h	Thu Feb 28 13:34:22 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: nodelist.h,v 1.46 2001/09/18 23:43:05 dwmw2 Exp $
+ * $Id: nodelist.h,v 1.46.2.1 2002/02/23 14:04:44 dwmw2 Exp $
  *
  */
 
@@ -248,7 +248,8 @@
 void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list);
 int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f,
 			  struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
-			  __u32 *highest_version);
+			  __u32 *highest_version, __u32 *latest_mctime,
+			  __u32 *mctime_ver);
 struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, int 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);
diff -urN linux-2.5.6-pre1/fs/jffs2/nodemgmt.c linux-2.5.6-pre2/fs/jffs2/nodemgmt.c
--- linux-2.5.6-pre1/fs/jffs2/nodemgmt.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/fs/jffs2/nodemgmt.c	Thu Feb 28 13:34:22 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: nodemgmt.c,v 1.45 2001/09/20 08:05:05 dwmw2 Exp $
+ * $Id: nodemgmt.c,v 1.45.2.1 2002/02/23 14:13:34 dwmw2 Exp $
  *
  */
 
@@ -318,6 +318,15 @@
 
 	ACCT_PARANOIA_CHECK(jeb);
 
+	if (c->flags & JFFS2_SB_FLAG_MOUNTING) {
+		/* Mount in progress. Don't muck about with the block
+		   lists because they're not ready yet, and don't actually
+		   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);
+		return;
+	}
 	if (jeb == c->nextblock) {
 		D2(printk(KERN_DEBUG "Not moving nextblock 0x%08x to dirty/erase_pending list\n", jeb->offset));
 	} else if (jeb == c->gcblock) {
diff -urN linux-2.5.6-pre1/fs/jffs2/read.c linux-2.5.6-pre2/fs/jffs2/read.c
--- linux-2.5.6-pre1/fs/jffs2/read.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/fs/jffs2/read.c	Thu Feb 28 13:34:22 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: read.c,v 1.13 2001/05/01 16:24:44 dwmw2 Exp $
+ * $Id: read.c,v 1.13.2.1 2002/02/01 23:32:33 dwmw2 Exp $
  *
  */
 
@@ -75,6 +75,12 @@
 		ret = -EIO;
 		goto out_ri;
 	}
+	/* There was a bug where we wrote hole nodes out with csize/dsize
+	   swapped. Deal with it */
+	if (ri->compr == JFFS2_COMPR_ZERO && !ri->dsize && ri->csize) {
+		ri->dsize = ri->csize;
+		ri->csize = 0;
+	}
 
 	D1(if(ofs + len > ri->dsize) {
 		printk(KERN_WARNING "jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n", len, ofs, ri->dsize);
diff -urN linux-2.5.6-pre1/fs/jffs2/readinode.c linux-2.5.6-pre2/fs/jffs2/readinode.c
--- linux-2.5.6-pre1/fs/jffs2/readinode.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/fs/jffs2/readinode.c	Thu Feb 28 13:34:22 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: readinode.c,v 1.56 2001/07/26 20:32:39 dwmw2 Exp $
+ * $Id: readinode.c,v 1.58.2.2 2002/02/23 14:25:37 dwmw2 Exp $
  *
  */
 
@@ -173,12 +173,12 @@
 				jffs2_free_node_frag(newfrag);
 				return -ENOMEM;
 			}
-			printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size);
+			D1(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size);
 			if (this->node)
 				printk("phys 0x%08x\n", this->node->raw->flash_offset &~3);
 			else 
 				printk("hole\n");
-
+			   )
 			newfrag2->ofs = fn->ofs + fn->size;
 			newfrag2->size = (this->ofs+this->size) - newfrag2->ofs;
 			newfrag2->next = this->next;
@@ -251,6 +251,7 @@
 	struct jffs2_full_dnode *fn = NULL;
 	struct jffs2_sb_info *c;
 	struct jffs2_raw_inode latest_node;
+	__u32 latest_mctime, mctime_ver;
 	int ret;
 	ssize_t retlen;
 
@@ -292,7 +293,7 @@
 	inode->i_nlink = f->inocache->nlink;
 
 	/* Grab all nodes relevant to this ino */
-	ret = jffs2_get_inode_nodes(c, inode->i_ino, f, &tn_list, &fd_list, &f->highest_version);
+	ret = jffs2_get_inode_nodes(c, inode->i_ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver);
 
 	if (ret) {
 		printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %lu returned %d\n", inode->i_ino, ret);
@@ -302,7 +303,7 @@
 	f->dents = fd_list;
 
 	while (tn_list) {
-		static __u32 mdata_ver = 0;
+		static __u32 mdata_ver;
 
 		tn = tn_list;
 
@@ -339,6 +340,7 @@
 			printk(KERN_WARNING "jffs2_read_inode(): But it has children so we fake some modes for it\n");
 		}
 		inode->i_mode = S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO;
+		latest_node.version = 0;
 		inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 		inode->i_nlink = f->inocache->nlink;
 		inode->i_size = 0;
@@ -366,7 +368,7 @@
 		inode->i_uid = latest_node.uid;
 		inode->i_gid = latest_node.gid;
 		inode->i_size = latest_node.isize;
-		if ((inode->i_mode & S_IFMT) == S_IFREG)
+		if (S_ISREG(inode->i_mode))
 			jffs2_truncate_fraglist(c, &f->fraglist, latest_node.isize);
 		inode->i_atime = latest_node.atime;
 		inode->i_mtime = latest_node.mtime;
@@ -376,9 +378,8 @@
 	/* OK, now the special cases. Certain inode types should
 	   have only one data node, and it's kept as the metadata
 	   node */
-	if ((inode->i_mode & S_IFMT) == S_IFBLK ||
-	    (inode->i_mode & S_IFMT) == S_IFCHR ||
-	    (inode->i_mode & S_IFMT) == S_IFLNK) {
+	if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode) ||
+	    S_ISLNK(inode->i_mode)) {
 		if (f->metadata) {
 			printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o had metadata node\n", inode->i_ino, inode->i_mode);
 			jffs2_clear_inode(inode);
@@ -393,7 +394,8 @@
 		}
 		/* ASSERT: f->fraglist != NULL */
 		if (f->fraglist->next) {
-			printk(KERN_WARNING "Argh. Special inode #%lu had more than one node\n", inode->i_ino);
+			printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o had more than one node\n", inode->i_ino, inode->i_mode);
+			/* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
 			jffs2_clear_inode(inode);
 			make_bad_inode(inode);
 			return;
@@ -412,9 +414,21 @@
 
 	case S_IFLNK:
 		inode->i_op = &jffs2_symlink_inode_operations;
+		/* Hack to work around broken isize in old symlink code.
+		   Remove this when dwmw2 comes to his senses and stops
+		   symlinks from being an entirely gratuitous special
+		   case. */
+		if (!inode->i_size)
+			inode->i_size = latest_node.dsize;
 		break;
 		
 	case S_IFDIR:
+		if (mctime_ver > latest_node.version) {
+			/* The times in the latest_node are actually older than
+			   mctime in the latest dirent. Cheat. */
+			inode->i_mtime = inode->i_ctime = inode->i_atime = 
+				latest_mctime;
+		}
 		inode->i_op = &jffs2_dir_inode_operations;
 		inode->i_fop = &jffs2_dir_operations;
 		break;
diff -urN linux-2.5.6-pre1/fs/jffs2/scan.c linux-2.5.6-pre2/fs/jffs2/scan.c
--- linux-2.5.6-pre1/fs/jffs2/scan.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/fs/jffs2/scan.c	Thu Feb 28 13:34:22 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: scan.c,v 1.51 2001/09/19 00:06:35 dwmw2 Exp $
+ * $Id: scan.c,v 1.51.2.2 2002/02/23 13:34:31 dwmw2 Exp $
  *
  */
 #include <linux/kernel.h>
@@ -62,6 +62,9 @@
 	} \
 } while(0)
 
+static uint32_t pseudo_random;
+static void jffs2_rotate_lists(struct jffs2_sb_info *c);
+
 static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 
 /* These helper functions _must_ increase ofs and also do the dirty/used space accounting. 
@@ -142,6 +145,9 @@
 			c->nr_erasing_blocks++;
 		}
 	}
+	/* Rotate the lists by some number to ensure wear levelling */
+	jffs2_rotate_lists(c);
+
 	if (c->nr_erasing_blocks) {
 		if (!c->used_size && empty_blocks != c->nr_blocks) {
 			printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n");
@@ -444,6 +450,12 @@
 		*ofs += 4;
 		return 0;
 	}
+	/* There was a bug where we wrote hole nodes out with csize/dsize
+	   swapped. Deal with it */
+	if (ri.compr == JFFS2_COMPR_ZERO && !ri.dsize && ri.csize) {
+		ri.dsize = ri.csize;
+		ri.csize = 0;
+	}
 
 	if (ri.csize) {
 		/* Check data CRC too */
@@ -474,7 +486,7 @@
 			       *ofs, ri.data_crc, crc);
 			DIRTY_SPACE(PAD(ri.totlen));
 			*ofs += PAD(ri.totlen);
-			return -0;
+			return 0;
 		}
 	}
 
@@ -518,6 +530,8 @@
 	D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n", 
 		  ri.ino, ri.version, ri.offset, ri.offset+ri.dsize));
 
+	pseudo_random += ri.version;
+
 	for (tn_list = &ic->scan->tmpnodes; *tn_list; tn_list = &((*tn_list)->next)) {
 		if ((*tn_list)->version < ri.version)
 			continue;
@@ -613,6 +627,8 @@
 		return 0;
 	}
 
+	pseudo_random += rd.version;
+
 	fd = jffs2_alloc_full_dirent(rd.nsize+1);
 	if (!fd) {
 		return -ENOMEM;
@@ -686,3 +702,45 @@
 	*ofs += PAD(rd.totlen);
 	return 0;
 }
+
+static int count_list(struct list_head *l)
+{
+	uint32_t count = 0;
+	struct list_head *tmp;
+
+	list_for_each(tmp, l) {
+		count++;
+	}
+	return count;
+}
+
+/* Note: This breaks if list_empty(head). I don't care. You
+   might, if you copy this code and use it elsewhere :) */
+static void rotate_list(struct list_head *head, uint32_t count)
+{
+	struct list_head *n = head->next;
+
+	list_del(head);
+	while(count--)
+		n = n->next;
+	list_add(head, n);
+}
+
+static void jffs2_rotate_lists(struct jffs2_sb_info *c)
+{
+	uint32_t x;
+
+	x = count_list(&c->clean_list);
+	if (x)
+		rotate_list((&c->clean_list), pseudo_random % x);
+
+	x = count_list(&c->dirty_list);
+	if (x)
+		rotate_list((&c->dirty_list), pseudo_random % x);
+
+	if (c->nr_erasing_blocks)
+		rotate_list((&c->erase_pending_list), pseudo_random % c->nr_erasing_blocks);
+
+	if (c->nr_free_blocks) /* Not that it should ever be zero */
+		rotate_list((&c->free_list), pseudo_random % c->nr_free_blocks);
+}
diff -urN linux-2.5.6-pre1/fs/jffs2/super.c linux-2.5.6-pre2/fs/jffs2/super.c
--- linux-2.5.6-pre1/fs/jffs2/super.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/fs/jffs2/super.c	Thu Feb 28 13:34:22 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: super.c,v 1.48 2001/10/02 09:16:23 dwmw2 Exp $
+ * $Id: super.c,v 1.48.2.1 2002/02/23 14:13:34 dwmw2 Exp $
  *
  */
 
@@ -214,7 +214,7 @@
 	
 	c->mtd = get_mtd_device(NULL, minor(sb->s_dev));
 	if (!c->mtd) {
-		D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", MINOR(sb->s_dev)));
+		D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", minor(sb->s_dev)));
 		return -EINVAL;
 	}
 	c->sector_size = c->mtd->erasesize;
@@ -249,10 +249,15 @@
 	INIT_LIST_HEAD(&c->bad_used_list);
 	c->highest_ino = 1;
 
+	c->flags |= JFFS2_SB_FLAG_MOUNTING;
+
 	if (jffs2_build_filesystem(c)) {
 		D1(printk(KERN_DEBUG "build_fs failed\n"));
 		goto out_nodes;
 	}
+
+	c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
+
 	sb->s_op = &jffs2_super_operations;
 
 	D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n"));
diff -urN linux-2.5.6-pre1/fs/jffs2/symlink.c linux-2.5.6-pre2/fs/jffs2/symlink.c
--- linux-2.5.6-pre1/fs/jffs2/symlink.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/fs/jffs2/symlink.c	Thu Feb 28 13:34:22 2002
@@ -1,7 +1,7 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001 Red Hat, Inc.
+ * Copyright (C) 2001, 2002 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
  *
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: symlink.c,v 1.5 2001/03/15 15:38:24 dwmw2 Exp $
+ * $Id: symlink.c,v 1.5.2.1 2002/01/15 10:39:06 dwmw2 Exp $
  *
  */
 
@@ -58,16 +58,21 @@
 	char *buf;
 	int ret;
 
+	down(&f->sem);
 	if (!f->metadata) {
+		up(&f->sem);
 		printk(KERN_NOTICE "No metadata for symlink inode #%lu\n", dentry->d_inode->i_ino);
 		return ERR_PTR(-EINVAL);
 	}
 	buf = kmalloc(f->metadata->size+1, GFP_USER);
-	if (!buf)
+	if (!buf) {
+		up(&f->sem);
 		return ERR_PTR(-ENOMEM);
+	}
 	buf[f->metadata->size]=0;
 
 	ret = jffs2_read_dnode(JFFS2_SB_INFO(dentry->d_inode->i_sb), f->metadata, buf, 0, f->metadata->size);
+	up(&f->sem);
 	if (ret) {
 		kfree(buf);
 		return ERR_PTR(ret);
diff -urN linux-2.5.6-pre1/fs/jfs/Makefile linux-2.5.6-pre2/fs/jfs/Makefile
--- linux-2.5.6-pre1/fs/jfs/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/Makefile	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,20 @@
+#
+# Makefile for the Linux JFS filesystem routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile.
+
+O_TARGET := jfs.o
+obj-y   := super.o file.o inode.o namei.o jfs_mount.o jfs_umount.o \
+	    jfs_xtree.o jfs_imap.o jfs_debug.o jfs_dmap.o \
+	    jfs_unicode.o jfs_dtree.o jfs_inode.o \
+	    jfs_extent.o symlink.o jfs_metapage.o \
+	    jfs_logmgr.o jfs_txnmgr.o jfs_uniupr.o
+obj-m   := $(O_TARGET)
+
+EXTRA_CFLAGS += -D_JFS_4K
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.5.6-pre1/fs/jfs/endian24.h linux-2.5.6-pre2/fs/jfs/endian24.h
--- linux-2.5.6-pre1/fs/jfs/endian24.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/endian24.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,50 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _H_ENDIAN24
+#define	_H_ENDIAN24
+
+/*
+ *	fs/jfs/endian24.h:
+ *
+ * Endian conversion for 24-byte data
+ *
+ */
+#define __swab24(x) \
+({ \
+	__u32 __x = (x); \
+	((__u32)( \
+		((__x & (__u32)0x000000ffUL) << 16) | \
+		 (__x & (__u32)0x0000ff00UL)        | \
+		((__x & (__u32)0x00ff0000UL) >> 16) )); \
+})
+
+#if (defined(__KERNEL__) && defined(__LITTLE_ENDIAN)) || (defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN))
+	#define __cpu_to_le24(x) ((__u32)(x))
+	#define __le24_to_cpu(x) ((__u32)(x))
+#else
+	#define __cpu_to_le24(x) __swab24(x)
+	#define __le24_to_cpu(x) __swab24(x)
+#endif
+
+#ifdef __KERNEL__
+	#define cpu_to_le24 __cpu_to_le24
+	#define le24_to_cpu __le24_to_cpu
+#endif
+
+#endif				/* !_H_ENDIAN24 */
diff -urN linux-2.5.6-pre1/fs/jfs/file.c linux-2.5.6-pre2/fs/jfs/file.c
--- linux-2.5.6-pre1/fs/jfs/file.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/file.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,105 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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/fs.h>
+#include <linux/locks.h>
+#include "jfs_incore.h"
+#include "jfs_txnmgr.h"
+#include "jfs_debug.h"
+
+
+extern int generic_file_open(struct inode *, struct file *);
+extern loff_t generic_file_llseek(struct file *, loff_t, int origin);
+
+extern int jfs_commit_inode(struct inode *, int);
+
+int jfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+	struct inode *inode = dentry->d_inode;
+	int rc = 0;
+
+	rc = fsync_inode_data_buffers(inode);
+
+	if (!(inode->i_state & I_DIRTY))
+		return rc;
+	if (datasync || !(inode->i_state & I_DIRTY_DATASYNC))
+		return rc;
+
+	IWRITE_LOCK(inode);
+	rc |= jfs_commit_inode(inode, 1);
+	IWRITE_UNLOCK(inode);
+
+	return rc ? -EIO : 0;
+}
+
+struct file_operations jfs_file_operations = {
+	open:		generic_file_open,
+	llseek:		generic_file_llseek,
+	write:		generic_file_write,
+	read:		generic_file_read,
+	mmap:		generic_file_mmap,
+	fsync:		jfs_fsync,
+};
+
+/*
+ * Guts of jfs_truncate.  Called with locks already held.  Can be called
+ * with directory for truncating directory index table.
+ */
+void jfs_truncate_nolock(struct inode *ip, loff_t length)
+{
+	loff_t newsize;
+	tid_t tid;
+
+	ASSERT(length >= 0);
+
+	if (test_cflag(COMMIT_Nolink, ip)) {
+		xtTruncate(0, ip, length, COMMIT_WMAP);
+		return;
+	}
+
+	do {
+		tid = txBegin(ip->i_sb, 0);
+
+		newsize = xtTruncate(tid, ip, length,
+				     COMMIT_TRUNCATE | COMMIT_PWMAP);
+		if (newsize < 0) {
+			txEnd(tid);
+			break;
+		}
+
+		ip->i_mtime = ip->i_ctime = CURRENT_TIME;
+		mark_inode_dirty(ip);
+
+		txCommit(tid, 1, &ip, 0);
+		txEnd(tid);
+	} while (newsize > length);	/* Truncate isn't always atomic */
+}
+
+static void jfs_truncate(struct inode *ip)
+{
+	jFYI(1, ("jfs_truncate: size = 0x%lx\n", (ulong) ip->i_size));
+
+	IWRITE_LOCK(ip);
+	jfs_truncate_nolock(ip, ip->i_size);
+	IWRITE_UNLOCK(ip);
+}
+
+struct inode_operations jfs_file_inode_operations = {
+	truncate:	jfs_truncate,
+};
diff -urN linux-2.5.6-pre1/fs/jfs/inode.c linux-2.5.6-pre2/fs/jfs/inode.c
--- linux-2.5.6-pre1/fs/jfs/inode.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/inode.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,314 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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/fs.h>
+#include <linux/locks.h>
+#include <linux/slab.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_imap.h"
+#include "jfs_extent.h"
+#include "jfs_unicode.h"
+#include "jfs_debug.h"
+
+
+extern struct inode_operations jfs_dir_inode_operations;
+extern struct inode_operations jfs_file_inode_operations;
+extern struct inode_operations jfs_symlink_inode_operations;
+extern struct file_operations jfs_dir_operations;
+extern struct file_operations jfs_file_operations;
+struct address_space_operations jfs_aops;
+extern int freeZeroLink(struct inode *);
+
+void jfs_put_inode(struct inode *inode)
+{
+	jFYI(1, ("In jfs_put_inode, inode = 0x%p\n", inode));
+}
+
+void jfs_read_inode(struct inode *inode)
+{
+	jFYI(1, ("In jfs_read_inode, inode = 0x%p\n", inode));
+
+	if (diRead(inode))
+		goto bad_inode;
+
+	if (S_ISREG(inode->i_mode)) {
+		inode->i_op = &jfs_file_inode_operations;
+		inode->i_fop = &jfs_file_operations;
+		inode->i_mapping->a_ops = &jfs_aops;
+	} else if (S_ISDIR(inode->i_mode)) {
+		inode->i_op = &jfs_dir_inode_operations;
+		inode->i_fop = &jfs_dir_operations;
+		inode->i_mapping->a_ops = &jfs_aops;
+		inode->i_mapping->gfp_mask = GFP_NOFS;
+	} else if (S_ISLNK(inode->i_mode)) {
+		if (inode->i_size > IDATASIZE) {
+			inode->i_op = &page_symlink_inode_operations;
+			inode->i_mapping->a_ops = &jfs_aops;
+		} else
+			inode->i_op = &jfs_symlink_inode_operations;
+	} else {
+		init_special_inode(inode, inode->i_mode,
+				   kdev_t_to_nr(inode->i_rdev));
+	}
+
+	return;
+
+      bad_inode:
+	make_bad_inode(inode);
+}
+
+/* This define is from fs/open.c */
+#define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
+
+/*
+ * Workhorse of both fsync & write_inode
+ */
+int jfs_commit_inode(struct inode *inode, int wait)
+{
+	int rc = 0;
+	tid_t tid;
+	static int noisy = 5;
+
+	jFYI(1, ("In jfs_commit_inode, inode = 0x%p\n", inode));
+
+	/*
+	 * Don't commit if inode has been committed since last being
+	 * marked dirty, or if it has been deleted.
+	 */
+	if (test_cflag(COMMIT_Nolink, inode) ||
+	    !test_cflag(COMMIT_Dirty, inode))
+		return 0;
+
+	if (isReadOnly(inode)) {
+		/* kernel allows writes to devices on read-only
+		 * partitions and may think inode is dirty
+		 */
+		if (!special_file(inode->i_mode) && noisy) {
+			jERROR(1, ("jfs_commit_inode(0x%p) called on "
+				   "read-only volume\n", inode));
+			jERROR(1, ("Is remount racy?\n"));
+			noisy--;
+		}
+		return 0;
+	}
+
+	tid = txBegin(inode->i_sb, COMMIT_INODE);
+	rc = txCommit(tid, 1, &inode, wait ? COMMIT_SYNC : 0);
+	txEnd(tid);
+	return -rc;
+}
+
+void jfs_write_inode(struct inode *inode, int wait)
+{
+	/*
+	 * If COMMIT_DIRTY is not set, the inode isn't really dirty.
+	 * It has been committed since the last change, but was still
+	 * on the dirty inode list
+	 */
+	if (test_cflag(COMMIT_Nolink, inode) ||
+	    !test_cflag(COMMIT_Dirty, inode))
+		return;
+
+	IWRITE_LOCK(inode);
+
+	if (jfs_commit_inode(inode, wait)) {
+		jERROR(1, ("jfs_write_inode: jfs_commit_inode failed!\n"));
+	}
+
+	IWRITE_UNLOCK(inode);
+}
+
+void jfs_delete_inode(struct inode *inode)
+{
+	jFYI(1, ("In jfs_delete_inode, inode = 0x%p\n", inode));
+
+	IWRITE_LOCK(inode);
+	if (test_cflag(COMMIT_Freewmap, inode))
+		freeZeroLink(inode);
+
+	diFree(inode);
+	IWRITE_UNLOCK(inode);
+
+	clear_inode(inode);
+}
+
+void jfs_dirty_inode(struct inode *inode)
+{
+	static int noisy = 5;
+
+	if (isReadOnly(inode)) {
+		if (!special_file(inode->i_mode) && noisy) {
+			/* kernel allows writes to devices on read-only
+			 * partitions and may try to mark inode dirty
+			 */
+			jERROR(1, ("jfs_dirty_inode called on "
+				   "read-only volume\n"));
+			jERROR(1, ("Is remount racy?\n"));
+			noisy--;
+		}
+		return;
+	}
+
+	set_cflag(COMMIT_Dirty, inode);
+}
+
+static int jfs_get_block(struct inode *ip, sector_t lblock,
+			 struct buffer_head *bh_result, int create)
+{
+	s64 lblock64 = lblock;
+	int no_size_check = 0;
+	int rc = 0;
+	int take_locks;
+	xad_t xad;
+	s64 xaddr;
+	int xflag;
+	s32 xlen;
+
+	/*
+	 * If this is a special inode (imap, dmap) or directory,
+	 * the lock should already be taken
+	 */
+	take_locks = ((JFS_IP(ip)->fileset != AGGREGATE_I) &&
+		      !S_ISDIR(ip->i_mode));
+	/*
+	 * Take appropriate lock on inode
+	 */
+	if (take_locks) {
+		if (create)
+			IWRITE_LOCK(ip);
+		else
+			IREAD_LOCK(ip);
+	}
+
+	/*
+	 * A directory's "data" is the inode index table, but i_size is the
+	 * size of the d-tree, so don't check the offset against i_size
+	 */
+	if (S_ISDIR(ip->i_mode))
+		no_size_check = 1;
+
+	if ((no_size_check ||
+	     ((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size)) &&
+	    (xtLookup
+	     (ip, lblock64, 1, &xflag, &xaddr, &xlen, no_size_check)
+	     == 0) && xlen) {
+		if (xflag & XAD_NOTRECORDED) {
+			if (!create)
+				/*
+				 * Allocated but not recorded, read treats
+				 * this as a hole
+				 */
+				goto unlock;
+#ifdef _JFS_4K
+			XADoffset(&xad, lblock64);
+			XADlength(&xad, xlen);
+			XADaddress(&xad, xaddr);
+#else				/* _JFS_4K */
+			/*
+			 * As long as block size = 4K, this isn't a problem.
+			 * We should mark the whole page not ABNR, but how
+			 * will we know to mark the other blocks BH_New?
+			 */
+			BUG();
+#endif				/* _JFS_4K */
+			rc = extRecord(ip, &xad);
+			if (rc)
+				goto unlock;
+			bh_result->b_state |= (1UL << BH_New);
+		}
+
+		map_bh(bh_result, ip->i_sb, xaddr);
+		goto unlock;
+	}
+	if (!create)
+		goto unlock;
+
+	/*
+	 * Allocate a new block
+	 */
+#ifdef _JFS_4K
+	if ((rc =
+	     extHint(ip, lblock64 << ip->i_sb->s_blocksize_bits, &xad)))
+		goto unlock;
+	rc = extAlloc(ip, 1, lblock64, &xad, FALSE);
+	if (rc)
+		goto unlock;
+
+	bh_result->b_state |= (1UL << BH_New);
+	map_bh(bh_result, ip->i_sb, addressXAD(&xad));
+
+#else				/* _JFS_4K */
+	/*
+	 * We need to do whatever it takes to keep all but the last buffers
+	 * in 4K pages - see jfs_write.c
+	 */
+	BUG();
+#endif				/* _JFS_4K */
+
+      unlock:
+	/*
+	 * Release lock on inode
+	 */
+	if (take_locks) {
+		if (create)
+			IWRITE_UNLOCK(ip);
+		else
+			IREAD_UNLOCK(ip);
+	}
+	return -rc;
+}
+
+static int jfs_writepage(struct page *page)
+{
+	return block_write_full_page(page, jfs_get_block);
+}
+
+static int jfs_readpage(struct file *file, struct page *page)
+{
+	return block_read_full_page(page, jfs_get_block);
+}
+
+static int jfs_prepare_write(struct file *file,
+			     struct page *page, unsigned from, unsigned to)
+{
+	return block_prepare_write(page, from, to, jfs_get_block);
+}
+
+static int jfs_bmap(struct address_space *mapping, long block)
+{
+	return generic_block_bmap(mapping, block, jfs_get_block);
+}
+
+static int jfs_direct_IO(int rw, struct inode *inode, struct kiobuf *iobuf,
+			 unsigned long blocknr, int blocksize)
+{
+	return generic_direct_IO(rw, inode, iobuf, blocknr,
+				 blocksize, jfs_get_block);
+}
+
+struct address_space_operations jfs_aops = {
+	readpage:	jfs_readpage,
+	writepage:	jfs_writepage,
+	sync_page:	block_sync_page,
+	prepare_write:	jfs_prepare_write,
+	commit_write:	generic_commit_write,
+	bmap:		jfs_bmap,
+	direct_IO:	jfs_direct_IO,
+};
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_btree.h linux-2.5.6-pre2/fs/jfs/jfs_btree.h
--- linux-2.5.6-pre1/fs/jfs/jfs_btree.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_btree.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,163 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef	_H_JFS_BTREE
+#define _H_JFS_BTREE
+/*
+ *	jfs_btree.h: B+-tree
+ *
+ * JFS B+-tree (dtree and xtree) common definitions
+ */
+
+/*
+ *	basic btree page - btpage_t
+ */
+typedef struct {
+	s64 next;		/* 8: right sibling bn */
+	s64 prev;		/* 8: left sibling bn */
+
+	u8 flag;		/* 1: */
+	u8 rsrvd[7];		/* 7: type specific */
+	s64 self;		/* 8: self address */
+
+	u8 entry[4064];		/* 4064: */
+} btpage_t;			/* (4096) */
+
+/* btpaget_t flag */
+#define BT_TYPE		0x07	/* B+-tree index */
+#define	BT_ROOT		0x01	/* root page */
+#define	BT_LEAF		0x02	/* leaf page */
+#define	BT_INTERNAL	0x04	/* internal page */
+#define	BT_RIGHTMOST	0x10	/* rightmost page */
+#define	BT_LEFTMOST	0x20	/* leftmost page */
+#define	BT_SWAPPED	0x80	/* used by fsck for endian swapping */
+
+/* btorder (in inode) */
+#define	BT_RANDOM		0x0000
+#define	BT_SEQUENTIAL		0x0001
+#define	BT_LOOKUP		0x0010
+#define	BT_INSERT		0x0020
+#define	BT_DELETE		0x0040
+
+/*
+ *	btree page buffer cache access
+ */
+#define BT_IS_ROOT(MP) (((MP)->xflag & COMMIT_PAGE) == 0)
+
+/* get page from buffer page */
+#define BT_PAGE(IP, MP, TYPE, ROOT)\
+	(BT_IS_ROOT(MP) ? (TYPE *)&JFS_IP(IP)->ROOT : (TYPE *)(MP)->data)
+
+/* get the page buffer and the page for specified block address */
+#define BT_GETPAGE(IP, BN, MP, TYPE, SIZE, P, RC, ROOT)\
+{\
+	if ((BN) == 0)\
+	{\
+		MP = (metapage_t *)&JFS_IP(IP)->bxflag;\
+		P = (TYPE *)&JFS_IP(IP)->ROOT;\
+		RC = 0;\
+		jEVENT(0,("%d BT_GETPAGE returning root\n", __LINE__));\
+	}\
+	else\
+	{\
+		jEVENT(0,("%d BT_GETPAGE reading block %d\n", __LINE__,\
+			 (int)BN));\
+		MP = read_metapage((IP), BN, SIZE, 1);\
+		if (MP) {\
+			RC = 0;\
+			P = (MP)->data;\
+		} else {\
+			P = NULL;\
+			jERROR(1,("bread failed!\n"));\
+			RC = EIO;\
+		}\
+	}\
+}
+
+#define BT_MARK_DIRTY(MP, IP)\
+{\
+	if (BT_IS_ROOT(MP))\
+		mark_inode_dirty(IP);\
+	else\
+		mark_metapage_dirty(MP);\
+}
+
+/* put the page buffer */
+#define BT_PUTPAGE(MP)\
+{\
+	if (! BT_IS_ROOT(MP)) \
+		release_metapage(MP); \
+}
+
+
+/*
+ *	btree traversal stack
+ *
+ * record the path traversed during the search;
+ * top frame record the leaf page/entry selected.
+ */
+#define	MAXTREEHEIGHT		8
+typedef struct btframe {	/* stack frame */
+	s64 bn;			/* 8: */
+	s16 index;		/* 2: */
+	s16 lastindex;		/* 2: */
+	struct metapage *mp;	/* 4: */
+} btframe_t;			/* (16) */
+
+typedef struct btstack {
+	btframe_t *top;		/* 4: */
+	int nsplit;		/* 4: */
+	btframe_t stack[MAXTREEHEIGHT];
+} btstack_t;
+
+#define BT_CLR(btstack)\
+	(btstack)->top = (btstack)->stack
+
+#define BT_PUSH(BTSTACK, BN, INDEX)\
+{\
+	(BTSTACK)->top->bn = BN;\
+	(BTSTACK)->top->index = INDEX;\
+	++(BTSTACK)->top;\
+	assert((BTSTACK)->top != &((BTSTACK)->stack[MAXTREEHEIGHT]));\
+}
+
+#define BT_POP(btstack)\
+	( (btstack)->top == (btstack)->stack ? NULL : --(btstack)->top )
+
+#define BT_STACK(btstack)\
+	( (btstack)->top == (btstack)->stack ? NULL : (btstack)->top )
+
+/* retrieve search results */
+#define BT_GETSEARCH(IP, LEAF, BN, MP, TYPE, P, INDEX, ROOT)\
+{\
+	BN = (LEAF)->bn;\
+	MP = (LEAF)->mp;\
+	if (BN)\
+		P = (TYPE *)MP->data;\
+	else\
+		P = (TYPE *)&JFS_IP(IP)->ROOT;\
+	INDEX = (LEAF)->index;\
+}
+
+/* put the page buffer of search */
+#define BT_PUTSEARCH(BTSTACK)\
+{\
+	if (! BT_IS_ROOT((BTSTACK)->top->mp))\
+		release_metapage((BTSTACK)->top->mp);\
+}
+#endif				/* _H_JFS_BTREE */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_debug.c linux-2.5.6-pre2/fs/jfs/jfs_debug.c
--- linux-2.5.6-pre1/fs/jfs/jfs_debug.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_debug.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,145 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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/fs.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_debug.h"
+
+#ifdef CONFIG_JFS_DEBUG
+void dump_mem(char *label, void *data, int length)
+{
+	int i, j;
+	int *intptr = data;
+	char *charptr = data;
+	char buf[10], line[80];
+
+	printk("%s: dump of %d bytes of data at 0x%p\n\n", label, length,
+	       data);
+	for (i = 0; i < length; i += 16) {
+		line[0] = 0;
+		for (j = 0; (j < 4) && (i + j * 4 < length); j++) {
+			sprintf(buf, " %08x", intptr[i / 4 + j]);
+			strcat(line, buf);
+		}
+		buf[0] = ' ';
+		buf[2] = 0;
+		for (j = 0; (j < 16) && (i + j < length); j++) {
+			buf[1] =
+			    isprint(charptr[i + j]) ? charptr[i + j] : '.';
+			strcat(line, buf);
+		}
+		printk("%s\n", line);
+	}
+}
+
+#ifdef CONFIG_PROC_FS
+static int loglevel_read(char *page, char **start, off_t off,
+			 int count, int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "%d\n", jfsloglevel);
+
+	len -= off;
+	*start = page + off;
+
+	if (len > count)
+		len = count;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+static int loglevel_write(struct file *file, const char *buffer,
+			unsigned long count, void *data)
+{
+	char c;
+
+	if (get_user(c, buffer))
+		return -EFAULT;
+
+	/* yes, I know this is an ASCIIism.  --hch */
+	if (c < '0' || c > '9')
+		return -EINVAL;
+	jfsloglevel = c - '0';
+	return count;
+}
+
+
+extern read_proc_t jfs_txanchor_read;
+#ifdef CONFIG_JFS_STATISTICS
+extern read_proc_t jfs_lmstats_read;
+extern read_proc_t jfs_xtstat_read;
+extern read_proc_t jfs_mpstat_read;
+#endif
+static struct proc_dir_entry *base;
+
+static struct {
+	const char	*name;
+	read_proc_t	*read_fn;
+	write_proc_t	*write_fn;
+} Entries[] = {
+	{ "TxAnchor",	jfs_txanchor_read, },
+#ifdef CONFIG_JFS_STATISTICS
+	{ "lmstats",	jfs_lmstats_read, },
+	{ "xtstat",	jfs_xtstat_read, },
+	{ "mpstat",	jfs_mpstat_read, },
+#endif
+	{ "loglevel",	loglevel_read, loglevel_write }
+};
+#define NPROCENT	(sizeof(Entries)/sizeof(Entries[0]))
+
+void jfs_proc_init(void)
+{
+	int i;
+
+	if (!(base = proc_mkdir("jfs", proc_root_fs)))
+		return;
+	base->owner = THIS_MODULE;
+
+	for (i = 0; i < NPROCENT; i++) {
+		struct proc_dir_entry *p;
+		if ((p = create_proc_entry(Entries[i].name, 0, base))) {
+			p->read_proc = Entries[i].read_fn;
+			p->write_proc = Entries[i].write_fn;
+		}
+	}
+}
+
+void jfs_proc_clean(void)
+{
+	int i;
+
+	if (base) {
+		for (i = 0; i < NPROCENT; i++)
+			remove_proc_entry(Entries[i].name, base);
+		remove_proc_entry("jfs", base);
+	}
+}
+
+#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_JFS_DEBUG */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_debug.h linux-2.5.6-pre2/fs/jfs/jfs_debug.h
--- linux-2.5.6-pre1/fs/jfs/jfs_debug.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_debug.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,96 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+#ifndef _H_JFS_DEBUG
+#define _H_JFS_DEBUG
+
+/*
+ *	jfs_debug.h
+ *
+ * global debug message, data structure/macro definitions
+ * under control of CONFIG_JFS_DEBUG, CONFIG_JFS_STATISTICS;
+ */
+
+/*
+ *	assert with traditional printf/panic
+ */
+#ifdef CONFIG_KERNEL_ASSERTS
+/* kgdb stuff */
+#define assert(p) KERNEL_ASSERT(#p, p)
+#else
+#define assert(p) {\
+if (!(p))\
+	{\
+		printk("assert(%s)\n",#p);\
+		BUG();\
+	}\
+}
+#endif
+
+/*
+ *	debug ON
+ *	--------
+ */
+#ifdef CONFIG_JFS_DEBUG
+#define ASSERT(p) assert(p)
+
+/* dump memory contents */
+extern void dump_mem(char *label, void *data, int length);
+extern int jfsloglevel;
+
+/* information message: e.g., configuration, major event */
+#define jFYI(button, prspec) \
+	do { if (button && jfsloglevel > 1) printk prspec; } while (0)
+
+/* error event message: e.g., i/o error */
+extern int jfsERROR;
+#define jERROR(button, prspec) \
+	do { if (button && jfsloglevel > 0) { printk prspec; } } while (0)
+
+/* debug event message: */
+#define jEVENT(button,prspec) \
+	do { if (button) printk prspec; } while (0)
+
+/*
+ *	debug OFF
+ *	---------
+ */
+#else				/* CONFIG_JFS_DEBUG */
+#define dump_mem(label,data,length)
+#define ASSERT(p)
+#define jEVENT(button,prspec)
+#define jERROR(button,prspec)
+#define jFYI(button,prspec)
+#endif				/* CONFIG_JFS_DEBUG */
+
+/*
+ *	statistics
+ *	----------
+ */
+#ifdef	CONFIG_JFS_STATISTICS
+#define	INCREMENT(x)		((x)++)
+#define	DECREMENT(x)		((x)--)
+#define	HIGHWATERMARK(x,y)	((x) = max((x), (y)))
+#else
+#define	INCREMENT(x)
+#define	DECREMENT(x)
+#define	HIGHWATERMARK(x,y)
+#endif				/* CONFIG_JFS_STATISTICS */
+
+#endif				/* _H_JFS_DEBUG */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_defragfs.h linux-2.5.6-pre2/fs/jfs/jfs_defragfs.h
--- linux-2.5.6-pre1/fs/jfs/jfs_defragfs.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_defragfs.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,55 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef	_H_JFS_DEFRAGFS
+#define _H_JFS_DEFRAGFS
+
+/*
+ *	jfs_defragfs.h
+ */
+/*
+ *	defragfs parameter list
+ */
+typedef struct {
+	uint flag;		/* 4: */
+	u8 dev;			/* 1: */
+	u8 pad[3];		/* 3: */
+	s32 fileset;		/* 4: */
+	u32 inostamp;		/* 4: */
+	u32 ino;		/* 4: */
+	u32 gen;		/* 4: */
+	s64 xoff;		/* 8: */
+	s64 old_xaddr;		/* 8: */
+	s64 new_xaddr;		/* 8: */
+	s32 xlen;		/* 4: */
+} defragfs_t;			/* (52) */
+
+/* plist flag */
+#define DEFRAGFS_SYNC		0x80000000
+#define DEFRAGFS_COMMIT		0x40000000
+#define DEFRAGFS_RELOCATE	0x10000000
+
+#define	INODE_TYPE		0x0000F000	/* IFREG or IFDIR */
+
+#define EXTENT_TYPE		0x000000ff
+#define DTPAGE			0x00000001
+#define XTPAGE			0x00000002
+#define DATAEXT			0x00000004
+#define EAEXT			0x00000008
+
+#endif				/* _H_JFS_DEFRAGFS */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_dinode.h linux-2.5.6-pre2/fs/jfs/jfs_dinode.h
--- linux-2.5.6-pre1/fs/jfs/jfs_dinode.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_dinode.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,157 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _H_JFS_DINODE
+#define _H_JFS_DINODE
+
+/*
+ *      jfs_dinode.h: on-disk inode manager
+ *
+ */
+
+#define INODESLOTSIZE           128
+#define L2INODESLOTSIZE         7
+#define log2INODESIZE           9	/* log2(bytes per dinode) */
+
+
+/*
+ *      on-disk inode (dinode_t): 512 bytes
+ *
+ * note: align 64-bit fields on 8-byte boundary.
+ */
+struct dinode {
+	/*
+	 *      I. base area (128 bytes)
+	 *      ------------------------
+	 *
+	 * define generic/POSIX attributes
+	 */
+	u32 di_inostamp;	/* 4: stamp to show inode belongs to fileset */
+	s32 di_fileset;		/* 4: fileset number */
+	u32 di_number;		/* 4: inode number, aka file serial number */
+	u32 di_gen;		/* 4: inode generation number */
+
+	pxd_t di_ixpxd;		/* 8: inode extent descriptor */
+
+	s64 di_size;		/* 8: size */
+	s64 di_nblocks;		/* 8: number of blocks allocated */
+
+	u32 di_nlink;		/* 4: number of links to the object */
+
+	u32 di_uid;		/* 4: user id of owner */
+	u32 di_gid;		/* 4: group id of owner */
+
+	u32 di_mode;		/* 4: attribute, format and permission */
+
+	struct timestruc_t di_atime;	/* 8: time last data accessed */
+	struct timestruc_t di_ctime;	/* 8: time last status changed */
+	struct timestruc_t di_mtime;	/* 8: time last data modified */
+	struct timestruc_t di_otime;	/* 8: time created */
+
+	dxd_t di_acl;		/* 16: acl descriptor */
+
+	dxd_t di_ea;		/* 16: ea descriptor */
+
+	u32 di_next_index;	/* 4: Next available dir_table index */
+
+	s32 di_acltype;		/* 4: Type of ACL */
+
+	/*
+	 *      Extension Areas.
+	 *
+	 *      Historically, the inode was partitioned into 4 128-byte areas,
+	 *      the last 3 being defined as unions which could have multiple
+	 *      uses.  The first 96 bytes had been completely unused until
+	 *      an index table was added to the directory.  It is now more
+	 *      useful to describe the last 3/4 of the inode as a single
+	 *      union.  We would probably be better off redesigning the
+	 *      entire structure from scratch, but we don't want to break
+	 *      commonality with OS/2's JFS at this time.
+	 */
+	union {
+		struct {
+			/*
+			 * This table contains the information needed to
+			 * find a directory entry from a 32-bit index.
+			 * If the index is small enough, the table is inline,
+			 * otherwise, an x-tree root overlays this table
+			 */
+			dir_table_slot_t _table[12];	/* 96: inline */
+
+			dtroot_t _dtroot;		/* 288: dtree root */
+		} _dir;					/* (384) */
+#define di_dirtable	u._dir._table
+#define di_dtroot	u._dir._dtroot
+#define di_parent       di_dtroot.header.idotdot
+#define di_DASD		di_dtroot.header.DASD
+
+		struct {
+			union {
+				u8 _data[96];		/* 96: unused */
+				struct {
+					void *_imap;	/* 4: unused */
+					u32 _gengen;	/* 4: generator */
+				} _imap;
+			} _u1;				/* 96: */
+#define di_gengen	u._file._u1._imap._gengen
+
+			union {
+				xtpage_t _xtroot;
+				struct {
+					u8 unused[16];	/* 16: */
+					dxd_t _dxd;	/* 16: */
+					union {
+						u32 _rdev;	/* 4: */
+						u8 _fastsymlink[128];
+					} _u;
+					u8 _inlineea[128];
+				} _special;
+			} _u2;
+		} _file;
+#define di_xtroot	u._file._u2._xtroot
+#define di_dxd		u._file._u2._special._dxd
+#define di_btroot	di_xtroot
+#define di_inlinedata	u._file._u2._special._u
+#define di_rdev		u._file._u2._special._u._rdev
+#define di_fastsymlink	u._file._u2._special._u._fastsymlink
+#define di_inlineea     u._file._u2._special._inlineea
+	} u;
+};
+
+typedef struct dinode dinode_t;
+
+
+/* extended mode bits (on-disk inode di_mode) */
+#define IFJOURNAL       0x00010000	/* journalled file */
+#define ISPARSE         0x00020000	/* sparse file enabled */
+#define INLINEEA        0x00040000	/* inline EA area free */
+#define ISWAPFILE	0x00800000	/* file open for pager swap space */
+
+/* more extended mode bits: attributes for OS/2 */
+#define IREADONLY	0x02000000	/* no write access to file */
+#define IARCHIVE	0x40000000	/* file archive bit */
+#define ISYSTEM		0x08000000	/* system file */
+#define IHIDDEN		0x04000000	/* hidden file */
+#define IRASH		0x4E000000	/* mask for changeable attributes */
+#define INEWNAME	0x80000000	/* non-8.3 filename format */
+#define IDIRECTORY	0x20000000	/* directory (shadow of real bit) */
+#define ATTRSHIFT	25	/* bits to shift to move attribute
+				   specification to mode position */
+
+#endif /*_H_JFS_DINODE */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_dmap.c linux-2.5.6-pre2/fs/jfs/jfs_dmap.c
--- linux-2.5.6-pre1/fs/jfs/jfs_dmap.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_dmap.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,4190 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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
+ *
+ *
+ *   MODULE_NAME:		jfs_dmap.c
+ *
+ *   COMPONENT_NAME: 	sysjfs
+ *
+ *   FUNCTION:			block allocation map manager
+ *
+*/
+
+/*
+ * Change History :
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include "jfs_incore.h"
+#include "jfs_dmap.h"
+#include "jfs_imap.h"
+#include "jfs_lock.h"
+#include "jfs_metapage.h"
+#include "jfs_debug.h"
+
+/*
+ *	Debug code for double-checking block map
+ */
+/* #define	_JFS_DEBUG_DMAP	1 */
+
+#ifdef	_JFS_DEBUG_DMAP
+#define DBINITMAP(size,ipbmap,results) \
+	DBinitmap(size,ipbmap,results)
+#define DBALLOC(dbmap,mapsize,blkno,nblocks) \
+	DBAlloc(dbmap,mapsize,blkno,nblocks)
+#define DBFREE(dbmap,mapsize,blkno,nblocks) \
+	DBFree(dbmap,mapsize,blkno,nblocks)
+#define DBALLOCCK(dbmap,mapsize,blkno,nblocks) \
+	DBAllocCK(dbmap,mapsize,blkno,nblocks)
+#define DBFREECK(dbmap,mapsize,blkno,nblocks) \
+	DBFreeCK(dbmap,mapsize,blkno,nblocks)
+
+static void DBinitmap(s64, struct inode *, u32 **);
+static void DBAlloc(uint *, s64, s64, s64);
+static void DBFree(uint *, s64, s64, s64);
+static void DBAllocCK(uint *, s64, s64, s64);
+static void DBFreeCK(uint *, s64, s64, s64);
+#else
+#define DBINITMAP(size,ipbmap,results)
+#define DBALLOC(dbmap, mapsize, blkno, nblocks)
+#define DBFREE(dbmap, mapsize, blkno, nblocks)
+#define DBALLOCCK(dbmap, mapsize, blkno, nblocks)
+#define DBFREECK(dbmap, mapsize, blkno, nblocks)
+#endif				/* _JFS_DEBUG_DMAP */
+
+/*
+ *	SERIALIZATION of the Block Allocation Map.
+ *
+ *	the working state of the block allocation map is accessed in
+ *	two directions:
+ *	
+ *	1) allocation and free requests that start at the dmap
+ *	   level and move up through the dmap control pages (i.e.
+ *	   the vast majority of requests).
+ * 
+ * 	2) allocation requests that start at dmap control page
+ *	   level and work down towards the dmaps.
+ *	
+ *	the serialization scheme used here is as follows. 
+ *
+ *	requests which start at the bottom are serialized against each 
+ *	other through buffers and each requests holds onto its buffers 
+ *	as it works it way up from a single dmap to the required level 
+ *	of dmap control page.
+ *	requests that start at the top are serialized against each other
+ *	and request that start from the bottom by the multiple read/single
+ *	write inode lock of the bmap inode. requests starting at the top
+ *	take this lock in write mode while request starting at the bottom
+ *	take the lock in read mode.  a single top-down request may proceed
+ *	exclusively while multiple bottoms-up requests may proceed 
+ * 	simultaneously (under the protection of busy buffers).
+ *	
+ *	in addition to information found in dmaps and dmap control pages,
+ *	the working state of the block allocation map also includes read/
+ *	write information maintained in the bmap descriptor (i.e. total
+ *	free block count, allocation group level free block counts).
+ *	a single exclusive lock (BMAP_LOCK) is used to guard this information
+ *	in the face of multiple-bottoms up requests.
+ *	(lock ordering: IREAD_LOCK, BMAP_LOCK);
+ *	
+ *	accesses to the persistent state of the block allocation map (limited
+ *	to the persistent bitmaps in dmaps) is guarded by (busy) buffers.
+ */
+
+#define BMAP_LOCK_INIT(bmp)	init_MUTEX(&bmp->db_bmaplock)
+#define BMAP_LOCK(bmp)		down(&bmp->db_bmaplock)
+#define BMAP_UNLOCK(bmp)	up(&bmp->db_bmaplock)
+
+/*
+ * forward references
+ */
+static void dbAllocBits(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks);
+static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval);
+static void dbBackSplit(dmtree_t * tp, int leafno);
+static void dbJoin(dmtree_t * tp, int leafno, int newval);
+static void dbAdjTree(dmtree_t * tp, int leafno, int newval);
+static int dbAdjCtl(bmap_t * bmp, s64 blkno, int newval, int alloc,
+		    int level);
+static int dbAllocAny(bmap_t * bmp, s64 nblocks, int l2nb, s64 * results);
+static int dbAllocNext(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks);
+static int dbAllocNear(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks,
+		       int l2nb, s64 * results);
+static int dbAllocDmap(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks);
+static int dbAllocDmapLev(bmap_t * bmp, dmap_t * dp, int nblocks, int l2nb,
+			  s64 * results);
+static int dbAllocAG(bmap_t * bmp, int agno, s64 nblocks, int l2nb,
+		     s64 * results);
+static int dbAllocCtl(bmap_t * bmp, s64 nblocks, int l2nb, s64 blkno,
+		      s64 * results);
+int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks);
+static int dbFindBits(u32 word, int l2nb);
+static int dbFindCtl(bmap_t * bmp, int l2nb, int level, s64 * blkno);
+static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx);
+static void dbFreeBits(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks);
+static int dbFreeDmap(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks);
+static int dbMaxBud(u8 * cp);
+s64 dbMapFileSizeToMapSize(struct inode *ipbmap);
+int blkstol2(s64 nb);
+void fsDirty(void);
+
+int cntlz(u32 value);
+int cnttz(u32 word);
+
+static int dbAllocDmapBU(bmap_t * bmp, dmap_t * dp, s64 blkno,
+			 int nblocks);
+static int dbInitDmap(dmap_t * dp, s64 blkno, int nblocks);
+static int dbInitDmapTree(dmap_t * dp);
+static int dbInitTree(dmaptree_t * dtp);
+static int dbInitDmapCtl(dmapctl_t * dcp, int level, int i);
+static int dbGetL2AGSize(s64 nblocks);
+
+/*
+ *	buddy table
+ *
+ * table used for determining buddy sizes within characters of 
+ * dmap bitmap words.  the characters themselves serve as indexes
+ * into the table, with the table elements yielding the maximum
+ * binary buddy of free bits within the character.
+ */
+signed char budtab[256] = {
+	3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+	2, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1
+};
+
+
+/*
+ * NAME:    	dbMount()
+ *
+ * FUNCTION:	initializate the block allocation map.
+ *
+ *		memory is allocated for the in-core bmap descriptor and
+ *		the in-core descriptor is initialized from disk.
+ *
+ * PARAMETERS:
+ *      ipbmap	-  pointer to in-core inode for the block map.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOMEM	- insufficient memory
+ *      EIO	- i/o error
+ */
+int dbMount(struct inode *ipbmap)
+{
+	bmap_t *bmp;
+	dbmap_t *dbmp_le;
+	metapage_t *mp;
+	int i;
+
+	/*
+	 * allocate/initialize the in-memory bmap descriptor
+	 */
+	/* allocate memory for the in-memory bmap descriptor */
+	bmp = kmalloc(sizeof(bmap_t), GFP_KERNEL);
+	if (bmp == NULL)
+		return (ENOMEM);
+
+	/* read the on-disk bmap descriptor. */
+	mp = read_metapage(ipbmap,
+			   BMAPBLKNO << JFS_SBI(ipbmap->i_sb)->l2nbperpage,
+			   PSIZE, 0);
+	if (mp == NULL) {
+		kfree(bmp);
+		return (EIO);
+	}
+
+	/* copy the on-disk bmap descriptor to its in-memory version. */
+	dbmp_le = (dbmap_t *) mp->data;
+	bmp->db_mapsize = le64_to_cpu(dbmp_le->dn_mapsize);
+	bmp->db_nfree = le64_to_cpu(dbmp_le->dn_nfree);
+	bmp->db_l2nbperpage = le32_to_cpu(dbmp_le->dn_l2nbperpage);
+	bmp->db_numag = le32_to_cpu(dbmp_le->dn_numag);
+	bmp->db_maxlevel = le32_to_cpu(dbmp_le->dn_maxlevel);
+	bmp->db_maxag = le32_to_cpu(dbmp_le->dn_maxag);
+	bmp->db_agpref = le32_to_cpu(dbmp_le->dn_agpref);
+	bmp->db_aglevel = le32_to_cpu(dbmp_le->dn_aglevel);
+	bmp->db_agheigth = le32_to_cpu(dbmp_le->dn_agheigth);
+	bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth);
+	bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart);
+	bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size);
+	for (i = 0; i < MAXAG; i++)
+		bmp->db_agfree[i] = le64_to_cpu(dbmp_le->dn_agfree[i]);
+	bmp->db_agsize = le64_to_cpu(dbmp_le->dn_agsize);
+	bmp->db_maxfreebud = dbmp_le->dn_maxfreebud;
+
+	/* release the buffer. */
+	release_metapage(mp);
+
+	/* bind the bmap inode and the bmap descriptor to each other. */
+	bmp->db_ipbmap = ipbmap;
+	JFS_SBI(ipbmap->i_sb)->bmap = bmp;
+
+	DBINITMAP(bmp->db_mapsize, ipbmap, &bmp->db_DBmap);
+
+	/*
+	 * allocate/initialize the bmap lock
+	 */
+	BMAP_LOCK_INIT(bmp);
+
+	return (0);
+}
+
+
+/*
+ * NAME:    	dbUnmount()
+ *
+ * FUNCTION:	terminate the block allocation map in preparation for
+ *		file system unmount.
+ *
+ * 		the in-core bmap descriptor is written to disk and
+ *		the memory for this descriptor is freed.
+ *
+ * PARAMETERS:
+ *      ipbmap	-  pointer to in-core inode for the block map.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      EIO	- i/o error
+ */
+int dbUnmount(struct inode *ipbmap, int mounterror)
+{
+	bmap_t *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
+
+	if (!(mounterror || isReadOnly(ipbmap)))
+		dbSync(ipbmap);
+
+	/*
+	 * Invalidate the page cache buffers
+	 */
+	truncate_inode_pages(ipbmap->i_mapping, 0);
+
+	/* free the memory for the in-memory bmap. */
+	kfree(bmp);
+
+	return (0);
+}
+
+/*
+ *	dbSync()
+ */
+int dbSync(struct inode *ipbmap)
+{
+	dbmap_t *dbmp_le;
+	bmap_t *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
+	metapage_t *mp;
+	int i;
+
+	/*
+	 * write bmap global control page
+	 */
+	/* get the buffer for the on-disk bmap descriptor. */
+	mp = read_metapage(ipbmap,
+			   BMAPBLKNO << JFS_SBI(ipbmap->i_sb)->l2nbperpage,
+			   PSIZE, 0);
+	if (mp == NULL) {
+		jERROR(1,("dbSync: read_metapage failed!\n"));
+		return (EIO);
+	}
+	/* copy the in-memory version of the bmap to the on-disk version */
+	dbmp_le = (dbmap_t *) mp->data;
+	dbmp_le->dn_mapsize = cpu_to_le64(bmp->db_mapsize);
+	dbmp_le->dn_nfree = cpu_to_le64(bmp->db_nfree);
+	dbmp_le->dn_l2nbperpage = cpu_to_le32(bmp->db_l2nbperpage);
+	dbmp_le->dn_numag = cpu_to_le32(bmp->db_numag);
+	dbmp_le->dn_maxlevel = cpu_to_le32(bmp->db_maxlevel);
+	dbmp_le->dn_maxag = cpu_to_le32(bmp->db_maxag);
+	dbmp_le->dn_agpref = cpu_to_le32(bmp->db_agpref);
+	dbmp_le->dn_aglevel = cpu_to_le32(bmp->db_aglevel);
+	dbmp_le->dn_agheigth = cpu_to_le32(bmp->db_agheigth);
+	dbmp_le->dn_agwidth = cpu_to_le32(bmp->db_agwidth);
+	dbmp_le->dn_agstart = cpu_to_le32(bmp->db_agstart);
+	dbmp_le->dn_agl2size = cpu_to_le32(bmp->db_agl2size);
+	for (i = 0; i < MAXAG; i++)
+		dbmp_le->dn_agfree[i] = cpu_to_le64(bmp->db_agfree[i]);
+	dbmp_le->dn_agsize = cpu_to_le64(bmp->db_agsize);
+	dbmp_le->dn_maxfreebud = bmp->db_maxfreebud;
+
+	/* write the buffer */
+	write_metapage(mp);
+
+	/*
+	 * write out dirty pages of bmap
+	 */
+	fsync_inode_data_buffers(ipbmap);
+
+	ipbmap->i_state |= I_DIRTY;
+	diWriteSpecial(ipbmap);
+
+	return (0);
+}
+
+
+/*
+ * NAME:    	dbFree()
+ *
+ * FUNCTION:	free the specified block range from the working block
+ *		allocation map.
+ *
+ *		the blocks will be free from the working map one dmap
+ *		at a time.
+ *
+ * PARAMETERS:
+ *      ip	-  pointer to in-core inode;
+ *      blkno	-  starting block number to be freed.
+ *      nblocks	-  number of blocks to be freed.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      EIO	- i/o error
+ */
+int dbFree(struct inode *ip, s64 blkno, s64 nblocks)
+{
+	metapage_t *mp;
+	dmap_t *dp;
+	int nb, rc;
+	s64 lblkno, rem;
+	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+	bmap_t *bmp = JFS_SBI(ip->i_sb)->bmap;
+
+	IREAD_LOCK(ipbmap);
+
+	/* block to be freed better be within the mapsize. */
+	assert(blkno + nblocks <= bmp->db_mapsize);
+
+	/*
+	 * free the blocks a dmap at a time.
+	 */
+	mp = NULL;
+	for (rem = nblocks; rem > 0; rem -= nb, blkno += nb) {
+		/* release previous dmap if any */
+		if (mp) {
+			write_metapage(mp);
+		}
+
+		/* get the buffer for the current dmap. */
+		lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage);
+		mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL) {
+			IREAD_UNLOCK(ipbmap);
+			return (EIO);
+		}
+		dp = (dmap_t *) mp->data;
+
+		/* determine the number of blocks to be freed from
+		 * this dmap.
+		 */
+		nb = min(rem, BPERDMAP - (blkno & (BPERDMAP - 1)));
+
+		DBALLOCCK(bmp->db_DBmap, bmp->db_mapsize, blkno, nb);
+
+		/* free the blocks. */
+		if ((rc = dbFreeDmap(bmp, dp, blkno, nb))) {
+			release_metapage(mp);
+			IREAD_UNLOCK(ipbmap);
+			return (rc);
+		}
+
+		DBFREE(bmp->db_DBmap, bmp->db_mapsize, blkno, nb);
+	}
+
+	/* write the last buffer. */
+	write_metapage(mp);
+
+	IREAD_UNLOCK(ipbmap);
+
+	return (0);
+}
+
+
+/*
+ * NAME:	dbUpdatePMap()
+ *
+ * FUNCTION:    update the allocation state (free or allocate) of the
+ *		specified block range in the persistent block allocation map.
+ *		
+ *		the blocks will be updated in the persistent map one
+ *		dmap at a time.
+ *
+ * PARAMETERS:
+ *      ipbmap	-  pointer to in-core inode for the block map.
+ *      free	- TRUE if block range is to be freed from the persistent
+ *		  map; FALSE if it is to   be allocated.
+ *      blkno	-  starting block number of the range.
+ *      nblocks	-  number of contiguous blocks in the range.
+ *      tblk	-  transaction block;
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      EIO	- i/o error
+ */
+int
+dbUpdatePMap(struct inode *ipbmap,
+	     int free, s64 blkno, s64 nblocks, tblock_t * tblk)
+{
+	int nblks, dbitno, wbitno, rbits;
+	int word, nbits, nwords;
+	bmap_t *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
+	s64 lblkno, rem, lastlblkno;
+	u32 mask;
+	dmap_t *dp;
+	metapage_t *mp;
+	log_t *log;
+	int lsn, difft, diffp;
+
+	/* the blocks better be within the mapsize. */
+	assert(blkno + nblocks <= bmp->db_mapsize);
+
+	/* compute delta of transaction lsn from log syncpt */
+	lsn = tblk->lsn;
+	log = (log_t *) JFS_SBI(tblk->sb)->log;
+	logdiff(difft, lsn, log);
+
+	/*
+	 * update the block state a dmap at a time.
+	 */
+	mp = NULL;
+	lastlblkno = 0;
+	for (rem = nblocks; rem > 0; rem -= nblks, blkno += nblks) {
+		/* get the buffer for the current dmap. */
+		lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage);
+		if (lblkno != lastlblkno) {
+			if (mp) {
+				write_metapage(mp);
+			}
+
+			mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE,
+					   0);
+			if (mp == NULL)
+				return (EIO);
+		}
+		dp = (dmap_t *) mp->data;
+
+		/* determine the bit number and word within the dmap of
+		 * the starting block.  also determine how many blocks
+		 * are to be updated within this dmap.
+		 */
+		dbitno = blkno & (BPERDMAP - 1);
+		word = dbitno >> L2DBWORD;
+		nblks = min(rem, (s64)BPERDMAP - dbitno);
+
+		/* update the bits of the dmap words. the first and last
+		 * words may only have a subset of their bits updated. if
+		 * this is the case, we'll work against that word (i.e.
+		 * partial first and/or last) only in a single pass.  a 
+		 * single pass will also be used to update all words that
+		 * are to have all their bits updated.
+		 */
+		for (rbits = nblks; rbits > 0;
+		     rbits -= nbits, dbitno += nbits) {
+			/* determine the bit number within the word and
+			 * the number of bits within the word.
+			 */
+			wbitno = dbitno & (DBWORD - 1);
+			nbits = min(rbits, DBWORD - wbitno);
+
+			/* check if only part of the word is to be updated. */
+			if (nbits < DBWORD) {
+				/* update (free or allocate) the bits
+				 * in this word.
+				 */
+				mask =
+				    (ONES << (DBWORD - nbits) >> wbitno);
+				if (free)
+					dp->pmap[word] &=
+					    cpu_to_le32(~mask);
+				else
+					dp->pmap[word] |=
+					    cpu_to_le32(mask);
+
+				word += 1;
+			} else {
+				/* one or more words are to have all
+				 * their bits updated.  determine how
+				 * many words and how many bits.
+				 */
+				nwords = rbits >> L2DBWORD;
+				nbits = nwords << L2DBWORD;
+
+				/* update (free or allocate) the bits
+				 * in these words.
+				 */
+				if (free)
+					memset(&dp->pmap[word], 0,
+					       nwords * 4);
+				else
+					memset(&dp->pmap[word], (int) ONES,
+					       nwords * 4);
+
+				word += nwords;
+			}
+		}
+
+		/*
+		 * update dmap lsn
+		 */
+		if (lblkno == lastlblkno)
+			continue;
+
+		lastlblkno = lblkno;
+
+		if (mp->lsn != 0) {
+			/* inherit older/smaller lsn */
+			logdiff(diffp, mp->lsn, log);
+			if (difft < diffp) {
+				mp->lsn = lsn;
+
+				/* move bp after tblock in logsync list */
+				LOGSYNC_LOCK(log);
+				list_del(&mp->synclist);
+				list_add(&mp->synclist, &tblk->synclist);
+				LOGSYNC_UNLOCK(log);
+			}
+
+			/* inherit younger/larger clsn */
+			LOGSYNC_LOCK(log);
+			logdiff(difft, tblk->clsn, log);
+			logdiff(diffp, mp->clsn, log);
+			if (difft > diffp)
+				mp->clsn = tblk->clsn;
+			LOGSYNC_UNLOCK(log);
+		} else {
+			mp->log = log;
+			mp->lsn = lsn;
+
+			/* insert bp after tblock in logsync list */
+			LOGSYNC_LOCK(log);
+
+			log->count++;
+			list_add(&mp->synclist, &tblk->synclist);
+
+			mp->clsn = tblk->clsn;
+			LOGSYNC_UNLOCK(log);
+		}
+	}
+
+	/* write the last buffer. */
+	if (mp) {
+		write_metapage(mp);
+	}
+
+	return (0);
+}
+
+
+/*
+ * NAME:	dbNextAG()
+ *
+ * FUNCTION:    find the preferred allocation group for new allocations.
+ *
+ *		we try to keep the trailing (rightmost) allocation groups
+ *		free for large allocations.  we try to do this by targeting
+ *		new inode allocations towards the leftmost or 'active'
+ *		allocation groups while keeping the rightmost or 'inactive'
+ *		allocation groups free. once the active allocation groups
+ *		have dropped to a certain percentage of free space, we add
+ *		the leftmost inactive allocation group to the active set.
+ *
+ *		within the active allocation groups, we maintain a preferred
+ *		allocation group which consists of a group with at least
+ *		average free space over the active set. it is the preferred
+ *		group that we target new inode allocation towards.  the 
+ *		tie-in between inode allocation and block allocation occurs
+ *		as we allocate the first (data) block of an inode and specify
+ *		the inode (block) as the allocation hint for this block.
+ *
+ * PARAMETERS:
+ *      ipbmap	-  pointer to in-core inode for the block map.
+ *
+ * RETURN VALUES:
+ *      the preferred allocation group number.
+ *
+ * note: only called by dbAlloc();
+ */
+int dbNextAG(struct inode *ipbmap)
+{
+	s64 avgfree, inactfree, actfree, rem;
+	int actags, inactags, l2agsize;
+	bmap_t *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
+
+	BMAP_LOCK(bmp);
+
+	/* determine the number of active allocation groups (i.e.
+	 * the number of allocation groups up to and including
+	 * the rightmost allocation group with blocks allocated
+	 * in it.
+	 */
+	actags = bmp->db_maxag + 1;
+	assert(actags <= bmp->db_numag);
+
+	/* get the number of inactive allocation groups (i.e. the
+	 * number of allocation group following the rightmost group
+	 * with allocation in it.
+	 */
+	inactags = bmp->db_numag - actags;
+
+	/* determine how many blocks are in the inactive allocation
+	 * groups. in doing this, we must account for the fact that
+	 * the rightmost group might be a partial group (i.e. file
+	 * system size is not a multiple of the group size).
+	 */
+	l2agsize = bmp->db_agl2size;
+	rem = bmp->db_mapsize & (bmp->db_agsize - 1);
+	inactfree = (inactags
+		     && rem) ? ((inactags - 1) << l2agsize) +
+	    rem : inactags << l2agsize;
+
+	/* now determine how many free blocks are in the active
+	 * allocation groups plus the average number of free blocks
+	 * within the active ags.
+	 */
+	actfree = bmp->db_nfree - inactfree;
+	avgfree = (u32) actfree / (u32) actags;
+
+	/* check if not all of the allocation groups are active.
+	 */
+	if (actags < bmp->db_numag) {
+		/* not all of the allocation groups are active.  determine
+		 * if we should extend the active set by 1 (i.e. add the
+		 * group following the current active set).  we do so if
+		 * the number of free blocks within the active set is less
+		 * than the allocation group set and average free within
+		 * the active set is less than 60%.  we activate a new group
+		 * by setting the allocation group preference to the new
+		 * group.
+		 */
+		if (actfree < bmp->db_agsize &&
+		    ((avgfree * 100) >> l2agsize) < 60)
+			bmp->db_agpref = actags;
+	} else {
+		/* all allocation groups are in the active set.  check if
+		 * the preferred allocation group has average free space.
+		 * if not, re-establish the preferred group as the leftmost
+		 * group with average free space.
+		 */
+		if (bmp->db_agfree[bmp->db_agpref] < avgfree) {
+			for (bmp->db_agpref = 0; bmp->db_agpref < actags;
+			     bmp->db_agpref++) {
+				if (bmp->db_agfree[bmp->db_agpref] <=
+				    avgfree)
+					break;
+			}
+			assert(bmp->db_agpref < bmp->db_numag);
+		}
+	}
+
+	BMAP_UNLOCK(bmp);
+
+	/* return the preferred group.
+	 */
+	return (bmp->db_agpref);
+}
+
+
+/*
+ * NAME:	dbAlloc()
+ *
+ * FUNCTION:    attempt to allocate a specified number of contiguous free
+ *		blocks from the working allocation block map.
+ *
+ *		the block allocation policy uses hints and a multi-step
+ *		approach.
+ *
+ *	  	for allocation requests smaller than the number of blocks
+ *		per dmap, we first try to allocate the new blocks
+ *		immediately following the hint.  if these blocks are not
+ *		available, we try to allocate blocks near the hint.  if
+ *		no blocks near the hint are available, we next try to 
+ *		allocate within the same dmap as contains the hint.
+ *
+ *		if no blocks are available in the dmap or the allocation
+ *		request is larger than the dmap size, we try to allocate
+ *		within the same allocation group as contains the hint. if
+ *		this does not succeed, we finally try to allocate anywhere
+ *		within the aggregate.
+ *
+ *		we also try to allocate anywhere within the aggregate for
+ *		for allocation requests larger than the allocation group
+ *		size or requests that specify no hint value.
+ *
+ * PARAMETERS:
+ *      ip	-  pointer to in-core inode;
+ *      hint	- allocation hint.
+ *      nblocks	- number of contiguous blocks in the range.
+ *      results	- on successful return, set to the starting block number
+ *		  of the newly allocated contiguous range.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ */
+int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
+{
+	int rc, agno;
+	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+	bmap_t *bmp;
+	metapage_t *mp;
+	s64 lblkno, blkno;
+	dmap_t *dp;
+	int l2nb;
+	s64 mapSize;
+
+	/* assert that nblocks is valid */
+	assert(nblocks > 0);
+
+#ifdef _STILL_TO_PORT
+	/* DASD limit check                                     F226941 */
+	if (OVER_LIMIT(ip, nblocks))
+		return ENOSPC;
+#endif				/* _STILL_TO_PORT */
+
+	/* get the log2 number of blocks to be allocated.
+	 * if the number of blocks is not a log2 multiple, 
+	 * it will be rounded up to the next log2 multiple.
+	 */
+	l2nb = BLKSTOL2(nblocks);
+
+	bmp = JFS_SBI(ip->i_sb)->bmap;
+
+//retry:        /* serialize w.r.t.extendfs() */
+	mapSize = bmp->db_mapsize;
+
+	/* the hint should be within the map */
+	assert(hint < mapSize);
+
+	/* if no hint was specified or the number of blocks to be
+	 * allocated is greater than the allocation group size, try
+	 * to allocate anywhere.
+	 */
+	if (hint == 0 || l2nb > bmp->db_agl2size) {
+		IWRITE_LOCK(ipbmap);
+
+		rc = dbAllocAny(bmp, nblocks, l2nb, results);
+		if (rc == 0) {
+			DBALLOC(bmp->db_DBmap, bmp->db_mapsize, *results,
+				nblocks);
+		}
+
+		IWRITE_UNLOCK(ipbmap);
+		return (rc);
+	}
+
+	/* we would like to allocate close to the hint.  adjust the
+	 * hint to the block following the hint since the allocators
+	 * will start looking for free space starting at this point.
+	 * if the hint was the last block of the file system, try to
+	 * allocate in the same allocation group as the hint.
+	 */
+	blkno = hint + 1;
+	if (blkno >= bmp->db_mapsize) {
+		blkno--;
+		goto tryag;
+	}
+
+	/* check if blkno crosses over into a new allocation group.
+	 * if so, check if we should allow allocations within this
+	 * allocation group.  we try to keep the trailing (rightmost)
+	 * allocation groups of the file system free for large
+	 * allocations and may want to prevent this allocation from
+	 * spilling over into this space.
+	 */
+	if ((blkno & (bmp->db_agsize - 1)) == 0) {
+		/* check if the AG is beyond the rightmost AG with
+		 * allocations in it.  if so, call dbNextAG() to
+		 * determine if the allocation should be allowed
+		 * to proceed within this AG or should be targeted
+		 * to another AG.
+		 */
+		agno = blkno >> bmp->db_agl2size;
+		if (agno > bmp->db_maxag) {
+			agno = dbNextAG(ipbmap);
+			blkno = (s64) agno << bmp->db_agl2size;
+			goto tryag;
+		}
+	}
+
+	/* check if the allocation request size can be satisfied from a
+	 * single dmap.  if so, try to allocate from the dmap containing
+	 * the hint using a tiered strategy.
+	 */
+	if (nblocks <= BPERDMAP) {
+		IREAD_LOCK(ipbmap);
+
+		/* get the buffer for the dmap containing the hint.
+		 */
+		lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage);
+		mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL) {
+			IREAD_UNLOCK(ipbmap);
+			return (EIO);
+		}
+		dp = (dmap_t *) mp->data;
+
+		/* first, try to satisfy the allocation request with the
+		 * blocks beginning at the hint.
+		 */
+		if ((rc =
+		     dbAllocNext(bmp, dp, blkno,
+				 (int) nblocks)) != ENOSPC) {
+			if (rc == 0) {
+				*results = blkno;
+				DBALLOC(bmp->db_DBmap, bmp->db_mapsize,
+					*results, nblocks);
+				write_metapage(mp);
+			} else {
+				assert(rc == EIO);
+				release_metapage(mp);
+			}
+
+			IREAD_UNLOCK(ipbmap);
+			return (rc);
+		}
+
+		/* next, try to satisfy the allocation request with blocks
+		 * near the hint.
+		 */
+		if ((rc =
+		     dbAllocNear(bmp, dp, blkno, (int) nblocks, l2nb,
+				 results))
+		    != ENOSPC) {
+			if (rc == 0) {
+				DBALLOC(bmp->db_DBmap, bmp->db_mapsize,
+					*results, nblocks);
+				mark_metapage_dirty(mp);
+			}
+			release_metapage(mp);
+
+			IREAD_UNLOCK(ipbmap);
+			return (rc);
+		}
+
+		/* try to satisfy the allocation request with blocks within
+		 * the same allocation group as the hint.
+		 */
+		if ((rc =
+		     dbAllocDmapLev(bmp, dp, (int) nblocks, l2nb, results))
+		    != ENOSPC) {
+			if (rc == 0) {
+				DBALLOC(bmp->db_DBmap, bmp->db_mapsize,
+					*results, nblocks);
+				mark_metapage_dirty(mp);
+			}
+			release_metapage(mp);
+
+			IREAD_UNLOCK(ipbmap);
+			return (rc);
+		}
+
+		release_metapage(mp);
+		IREAD_UNLOCK(ipbmap);
+	}
+
+      tryag:
+	IWRITE_LOCK(ipbmap);
+
+	/* determine the allocation group number of the hint and try to
+	 * allocate within this allocation group.  if that fails, try to
+	 * allocate anywhere in the map.
+	 */
+	agno = blkno >> bmp->db_agl2size;
+	if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results)) == ENOSPC)
+		rc = dbAllocAny(bmp, nblocks, l2nb, results);
+	if (rc == 0) {
+		DBALLOC(bmp->db_DBmap, bmp->db_mapsize, *results, nblocks);
+	}
+
+	IWRITE_UNLOCK(ipbmap);
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbAllocExact()
+ *
+ * FUNCTION:    try to allocate the requested extent;
+ *
+ * PARAMETERS:
+ *      ip	- pointer to in-core inode;
+ *      blkno	- extent address;
+ *      nblocks	- extent length;
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ */
+int dbAllocExact(struct inode *ip, s64 blkno, int nblocks)
+{
+	int rc;
+	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+	bmap_t *bmp = JFS_SBI(ip->i_sb)->bmap;
+	dmap_t *dp;
+	s64 lblkno;
+	metapage_t *mp;
+
+	IREAD_LOCK(ipbmap);
+
+	/*
+	 * validate extent request:
+	 *
+	 * note: defragfs policy:
+	 *  max 64 blocks will be moved.  
+	 *  allocation request size must be satisfied from a single dmap.
+	 */
+	if (nblocks <= 0 || nblocks > BPERDMAP || blkno >= bmp->db_mapsize) {
+		IREAD_UNLOCK(ipbmap);
+		return EINVAL;
+	}
+
+	if (nblocks > ((s64) 1 << bmp->db_maxfreebud)) {
+		/* the free space is no longer available */
+		IREAD_UNLOCK(ipbmap);
+		return ENOSPC;
+	}
+
+	/* read in the dmap covering the extent */
+	lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage);
+	mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
+	if (mp == NULL) {
+		IREAD_UNLOCK(ipbmap);
+		return (EIO);
+	}
+	dp = (dmap_t *) mp->data;
+
+	/* try to allocate the requested extent */
+	rc = dbAllocNext(bmp, dp, blkno, nblocks);
+
+	IREAD_UNLOCK(ipbmap);
+
+	if (rc == 0) {
+		DBALLOC(bmp->db_DBmap, bmp->db_mapsize, blkno, nblocks);
+		mark_metapage_dirty(mp);
+	}
+	release_metapage(mp);
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbReAlloc()
+ *
+ * FUNCTION:    attempt to extend a current allocation by a specified
+ *		number of blocks.
+ *
+ *		this routine attempts to satisfy the allocation request
+ *		by first trying to extend the existing allocation in
+ *		place by allocating the additional blocks as the blocks
+ *		immediately following the current allocation.  if these
+ *		blocks are not available, this routine will attempt to
+ *		allocate a new set of contiguous blocks large enough
+ *		to cover the existing allocation plus the additional
+ *		number of blocks required.
+ *
+ * PARAMETERS:
+ *      ip	    -  pointer to in-core inode requiring allocation.
+ *      blkno	    -  starting block of the current allocation.
+ *      nblocks	    -  number of contiguous blocks within the current
+ *		       allocation.
+ *      addnblocks  -  number of blocks to add to the allocation.
+ *      results	-      on successful return, set to the starting block number
+ *		       of the existing allocation if the existing allocation
+ *		       was extended in place or to a newly allocated contiguous
+ *		       range if the existing allocation could not be extended
+ *		       in place.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ */
+int
+dbReAlloc(struct inode *ip,
+	  s64 blkno, s64 nblocks, s64 addnblocks, s64 * results)
+{
+	int rc;
+
+	/* try to extend the allocation in place.
+	 */
+	if ((rc = dbExtend(ip, blkno, nblocks, addnblocks)) == 0) {
+		*results = blkno;
+		return (0);
+	} else {
+		if (rc != ENOSPC)
+			return (rc);
+	}
+
+	/* could not extend the allocation in place, so allocate a
+	 * new set of blocks for the entire request (i.e. try to get
+	 * a range of contiguous blocks large enough to cover the
+	 * existing allocation plus the additional blocks.)
+	 */
+	return (dbAlloc
+		(ip, blkno + nblocks - 1, addnblocks + nblocks, results));
+}
+
+
+/*
+ * NAME:	dbExtend()
+ *
+ * FUNCTION:    attempt to extend a current allocation by a specified
+ *		number of blocks.
+ *
+ *		this routine attempts to satisfy the allocation request
+ *		by first trying to extend the existing allocation in
+ *		place by allocating the additional blocks as the blocks
+ *		immediately following the current allocation.
+ *
+ * PARAMETERS:
+ *      ip	    -  pointer to in-core inode requiring allocation.
+ *      blkno	    -  starting block of the current allocation.
+ *      nblocks	    -  number of contiguous blocks within the current
+ *		       allocation.
+ *      addnblocks  -  number of blocks to add to the allocation.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ */
+int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+	s64 lblkno, lastblkno, extblkno;
+	uint rel_block;
+	metapage_t *mp;
+	dmap_t *dp;
+	int rc;
+	struct inode *ipbmap = sbi->ipbmap;
+	bmap_t *bmp;
+
+	/*
+	 * We don't want a non-aligned extent to cross a page boundary
+	 */
+	if (((rel_block = blkno & (sbi->nbperpage - 1))) &&
+	    (rel_block + nblocks + addnblocks > sbi->nbperpage))
+		return (ENOSPC);
+
+	/* get the last block of the current allocation */
+	lastblkno = blkno + nblocks - 1;
+
+	/* determine the block number of the block following
+	 * the existing allocation.
+	 */
+	extblkno = lastblkno + 1;
+
+	IREAD_LOCK(ipbmap);
+
+	/* better be within the file system */
+	bmp = sbi->bmap;
+	assert(lastblkno >= 0 && lastblkno < bmp->db_mapsize);
+
+	/* we'll attempt to extend the current allocation in place by
+	 * allocating the additional blocks as the blocks immediately
+	 * following the current allocation.  we only try to extend the
+	 * current allocation in place if the number of additional blocks
+	 * can fit into a dmap, the last block of the current allocation
+	 * is not the last block of the file system, and the start of the
+	 * inplace extension is not on an allocation group boundry.
+	 */
+	if (addnblocks > BPERDMAP || extblkno >= bmp->db_mapsize ||
+	    (extblkno & (bmp->db_agsize - 1)) == 0) {
+		IREAD_UNLOCK(ipbmap);
+		return (ENOSPC);
+	}
+
+	/* get the buffer for the dmap containing the first block
+	 * of the extension.
+	 */
+	lblkno = BLKTODMAP(extblkno, bmp->db_l2nbperpage);
+	mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
+	if (mp == NULL) {
+		IREAD_UNLOCK(ipbmap);
+		return (EIO);
+	}
+
+	DBALLOCCK(bmp->db_DBmap, bmp->db_mapsize, blkno, nblocks);
+	dp = (dmap_t *) mp->data;
+
+	/* try to allocate the blocks immediately following the
+	 * current allocation.
+	 */
+	rc = dbAllocNext(bmp, dp, extblkno, (int) addnblocks);
+
+	IREAD_UNLOCK(ipbmap);
+
+	/* were we successful ? */
+	if (rc == 0) {
+		DBALLOC(bmp->db_DBmap, bmp->db_mapsize, extblkno,
+			addnblocks);
+		write_metapage(mp);
+	} else {
+		/* we were not successful */
+		release_metapage(mp);
+		assert(rc == ENOSPC || rc == EIO);
+	}
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbAllocNext()
+ *
+ * FUNCTION:    attempt to allocate the blocks of the specified block
+ *		range within a dmap.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      dp	-  pointer to dmap.
+ *      blkno	-  starting block number of the range.
+ *      nblocks	-  number of contiguous free blocks of the range.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ *
+ * serialization: IREAD_LOCK(ipbmap) held on entry/exit;
+ */
+static int dbAllocNext(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks)
+{
+	int dbitno, word, rembits, nb, nwords, wbitno, nw;
+	int l2size;
+	s8 *leaf;
+	u32 mask;
+
+	/* pick up a pointer to the leaves of the dmap tree.
+	 */
+	leaf = dp->tree.stree + le32_to_cpu(dp->tree.leafidx);
+
+	/* determine the bit number and word within the dmap of the
+	 * starting block.
+	 */
+	dbitno = blkno & (BPERDMAP - 1);
+	word = dbitno >> L2DBWORD;
+
+	/* check if the specified block range is contained within
+	 * this dmap.
+	 */
+	if (dbitno + nblocks > BPERDMAP)
+		return (ENOSPC);
+
+	/* check if the starting leaf indicates that anything
+	 * is free.
+	 */
+	if (leaf[word] == NOFREE)
+		return (ENOSPC);
+
+	/* check the dmaps words corresponding to block range to see
+	 * if the block range is free.  not all bits of the first and
+	 * last words may be contained within the block range.  if this
+	 * is the case, we'll work against those words (i.e. partial first
+	 * and/or last) on an individual basis (a single pass) and examine
+	 * the actual bits to determine if they are free.  a single pass
+	 * will be used for all dmap words fully contained within the
+	 * specified range.  within this pass, the leaves of the dmap
+	 * tree will be examined to determine if the blocks are free. a
+	 * single leaf may describe the free space of multiple dmap
+	 * words, so we may visit only a subset of the actual leaves
+	 * corresponding to the dmap words of the block range.
+	 */
+	for (rembits = nblocks; rembits > 0; rembits -= nb, dbitno += nb) {
+		/* determine the bit number within the word and
+		 * the number of bits within the word.
+		 */
+		wbitno = dbitno & (DBWORD - 1);
+		nb = min(rembits, DBWORD - wbitno);
+
+		/* check if only part of the word is to be examined.
+		 */
+		if (nb < DBWORD) {
+			/* check if the bits are free.
+			 */
+			mask = (ONES << (DBWORD - nb) >> wbitno);
+			if ((mask & ~le32_to_cpu(dp->wmap[word])) != mask)
+				return (ENOSPC);
+
+			word += 1;
+		} else {
+			/* one or more dmap words are fully contained
+			 * within the block range.  determine how many
+			 * words and how many bits.
+			 */
+			nwords = rembits >> L2DBWORD;
+			nb = nwords << L2DBWORD;
+
+			/* now examine the appropriate leaves to determine
+			 * if the blocks are free.
+			 */
+			while (nwords > 0) {
+				/* does the leaf describe any free space ?
+				 */
+				if (leaf[word] < BUDMIN)
+					return (ENOSPC);
+
+				/* determine the l2 number of bits provided
+				 * by this leaf.
+				 */
+				l2size =
+				    min((int)leaf[word], NLSTOL2BSZ(nwords));
+
+				/* determine how many words were handled.
+				 */
+				nw = BUDSIZE(l2size, BUDMIN);
+
+				nwords -= nw;
+				word += nw;
+			}
+		}
+	}
+
+	/* allocate the blocks.
+	 */
+	return (dbAllocDmap(bmp, dp, blkno, nblocks));
+}
+
+
+/*
+ * NAME:	dbAllocNear()
+ *
+ * FUNCTION:    attempt to allocate a number of contiguous free blocks near
+ *		a specified block (hint) within a dmap.
+ *
+ *		starting with the dmap leaf that covers the hint, we'll
+ *		check the next four contiguous leaves for sufficient free
+ *		space.  if sufficient free space is found, we'll allocate
+ *		the desired free space.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      dp	-  pointer to dmap.
+ *      blkno	-  block number to allocate near.
+ *      nblocks	-  actual number of contiguous free blocks desired.
+ *      l2nb	-  log2 number of contiguous free blocks desired.
+ *      results	-  on successful return, set to the starting block number
+ *		   of the newly allocated range.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ *
+ * serialization: IREAD_LOCK(ipbmap) held on entry/exit;
+ */
+static int
+dbAllocNear(bmap_t * bmp,
+	    dmap_t * dp, s64 blkno, int nblocks, int l2nb, s64 * results)
+{
+	int word, lword, rc;
+	s8 *leaf = dp->tree.stree + le32_to_cpu(dp->tree.leafidx);
+
+	/* determine the word within the dmap that holds the hint
+	 * (i.e. blkno).  also, determine the last word in the dmap
+	 * that we'll include in our examination.
+	 */
+	word = (blkno & (BPERDMAP - 1)) >> L2DBWORD;
+	lword = min(word + 4, LPERDMAP);
+
+	/* examine the leaves for sufficient free space.
+	 */
+	for (; word < lword; word++) {
+		/* does the leaf describe sufficient free space ?
+		 */
+		if (leaf[word] < l2nb)
+			continue;
+
+		/* determine the block number within the file system
+		 * of the first block described by this dmap word.
+		 */
+		blkno = le64_to_cpu(dp->start) + (word << L2DBWORD);
+
+		/* if not all bits of the dmap word are free, get the
+		 * starting bit number within the dmap word of the required
+		 * string of free bits and adjust the block number with the
+		 * value.
+		 */
+		if (leaf[word] < BUDMIN)
+			blkno +=
+			    dbFindBits(le32_to_cpu(dp->wmap[word]), l2nb);
+
+		/* allocate the blocks.
+		 */
+		if ((rc = dbAllocDmap(bmp, dp, blkno, nblocks)) == 0)
+			*results = blkno;
+
+		return (rc);
+	}
+
+	return (ENOSPC);
+}
+
+
+/*
+ * NAME:	dbAllocAG()
+ *
+ * FUNCTION:    attempt to allocate the specified number of contiguous
+ *		free blocks within the specified allocation group.
+ *
+ *		unless the allocation group size is equal to the number
+ *		of blocks per dmap, the dmap control pages will be used to
+ *		find the required free space, if available.  we start the
+ *		search at the highest dmap control page level which
+ *		distinctly describes the allocation group's free space
+ *		(i.e. the highest level at which the allocation group's
+ *		free space is not mixed in with that of any other group).
+ *		in addition, we start the search within this level at a
+ *		height of the dmapctl dmtree at which the nodes distinctly
+ *		describe the allocation group's free space.  at this height,
+ *		the allocation group's free space may be represented by 1
+ *		or two sub-trees, depending on the allocation group size.
+ *		we search the top nodes of these subtrees left to right for
+ *		sufficient free space.  if sufficient free space is found,
+ *		the subtree is searched to find the leftmost leaf that 
+ *		has free space.  once we have made it to the leaf, we
+ *		move the search to the next lower level dmap control page
+ *		corresponding to this leaf.  we continue down the dmap control
+ *		pages until we find the dmap that contains or starts the
+ *		sufficient free space and we allocate at this dmap.
+ *
+ *		if the allocation group size is equal to the dmap size,
+ *		we'll start at the dmap corresponding to the allocation
+ *		group and attempt the allocation at this level.
+ *
+ *		the dmap control page search is also not performed if the
+ *		allocation group is completely free and we go to the first
+ *		dmap of the allocation group to do the allocation.  this is
+ *		done because the allocation group may be part (not the first
+ *		part) of a larger binary buddy system, causing the dmap
+ *		control pages to indicate no free space (NOFREE) within
+ *		the allocation group.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *	agno	- allocation group number.
+ *      nblocks	-  actual number of contiguous free blocks desired.
+ *      l2nb	-  log2 number of contiguous free blocks desired.
+ *      results	-  on successful return, set to the starting block number
+ *		   of the newly allocated range.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ *
+ * note: IWRITE_LOCK(ipmap) held on entry/exit;
+ */
+static int
+dbAllocAG(bmap_t * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
+{
+	metapage_t *mp;
+	dmapctl_t *dcp;
+	int rc, ti, i, k, m, n, agperlev;
+	s64 blkno, lblkno;
+	int budmin;
+
+	/* allocation request should not be for more than the
+	 * allocation group size.
+	 */
+	assert(l2nb <= bmp->db_agl2size);
+
+	/* determine the starting block number of the allocation
+	 * group.
+	 */
+	blkno = (s64) agno << bmp->db_agl2size;
+
+	/* check if the allocation group size is the minimum allocation
+	 * group size or if the allocation group is completely free. if
+	 * the allocation group size is the minimum size of BPERDMAP (i.e.
+	 * 1 dmap), there is no need to search the dmap control page (below)
+	 * that fully describes the allocation group since the allocation
+	 * group is already fully described by a dmap.  in this case, we
+	 * just call dbAllocCtl() to search the dmap tree and allocate the
+	 * required space if available.  
+	 *
+	 * if the allocation group is completely free, dbAllocCtl() is
+	 * also called to allocate the required space.  this is done for
+	 * two reasons.  first, it makes no sense searching the dmap control
+	 * pages for free space when we know that free space exists.  second,
+	 * the dmap control pages may indicate that the allocation group
+	 * has no free space if the allocation group is part (not the first
+	 * part) of a larger binary buddy system.
+	 */
+	if (bmp->db_agsize == BPERDMAP
+	    || bmp->db_agfree[agno] == bmp->db_agsize) {
+		rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
+		/* assert(!(rc == ENOSPC && bmp->db_agfree[agno] == bmp->db_agsize)); */
+		if ((rc == ENOSPC) &&
+		    (bmp->db_agfree[agno] == bmp->db_agsize)) {
+			jERROR(1,
+			       ("dbAllocAG: removed assert, but still need to debug here\nblkno = 0x%Lx, nblocks = 0x%Lx\n",
+				(unsigned long long) blkno,
+				(unsigned long long) nblocks));
+		}
+		return (rc);
+	}
+
+	/* the buffer for the dmap control page that fully describes the
+	 * allocation group.
+	 */
+	lblkno = BLKTOCTL(blkno, bmp->db_l2nbperpage, bmp->db_aglevel);
+	mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
+	if (mp == NULL)
+		return (EIO);
+	dcp = (dmapctl_t *) mp->data;
+	budmin = dcp->budmin;
+
+	/* search the subtree(s) of the dmap control page that describes
+	 * the allocation group, looking for sufficient free space.  to begin,
+	 * determine how many allocation groups are represented in a dmap
+	 * control page at the control page level (i.e. L0, L1, L2) that
+	 * fully describes an allocation group. next, determine the starting
+	 * tree index of this allocation group within the control page.
+	 */
+	agperlev =
+	    (1 << (L2LPERCTL - (bmp->db_agheigth << 1))) / bmp->db_agwidth;
+	ti = bmp->db_agstart + bmp->db_agwidth * (agno & (agperlev - 1));
+
+	/* dmap control page trees fan-out by 4 and a single allocation 
+	 * group may be described by 1 or 2 subtrees within the ag level
+	 * dmap control page, depending upon the ag size. examine the ag's
+	 * subtrees for sufficient free space, starting with the leftmost
+	 * subtree.
+	 */
+	for (i = 0; i < bmp->db_agwidth; i++, ti++) {
+		/* is there sufficient free space ?
+		 */
+		if (l2nb > dcp->stree[ti])
+			continue;
+
+		/* sufficient free space found in a subtree. now search down
+		 * the subtree to find the leftmost leaf that describes this
+		 * free space.
+		 */
+		for (k = bmp->db_agheigth; k > 0; k--) {
+			for (n = 0, m = (ti << 2) + 1; n < 4; n++) {
+				if (l2nb <= dcp->stree[m + n]) {
+					ti = m + n;
+					break;
+				}
+			}
+			assert(n < 4);
+		}
+
+		/* determine the block number within the file system
+		 * that corresponds to this leaf.
+		 */
+		if (bmp->db_aglevel == 2)
+			blkno = 0;
+		else if (bmp->db_aglevel == 1)
+			blkno &= ~(MAXL1SIZE - 1);
+		else		/* bmp->db_aglevel == 0 */
+			blkno &= ~(MAXL0SIZE - 1);
+
+		blkno +=
+		    ((s64) (ti - le32_to_cpu(dcp->leafidx))) << budmin;
+
+		/* release the buffer in preparation for going down
+		 * the next level of dmap control pages.
+		 */
+		release_metapage(mp);
+
+		/* check if we need to continue to search down the lower
+		 * level dmap control pages.  we need to if the number of
+		 * blocks required is less than maximum number of blocks
+		 * described at the next lower level.
+		 */
+		if (l2nb < budmin) {
+
+			/* search the lower level dmap control pages to get
+			 * the starting block number of the the dmap that
+			 * contains or starts off the free space.
+			 */
+			if ((rc =
+			     dbFindCtl(bmp, l2nb, bmp->db_aglevel - 1,
+				       &blkno))) {
+				assert(rc != ENOSPC);
+				return (rc);
+			}
+		}
+
+		/* allocate the blocks.
+		 */
+		rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
+		assert(rc != ENOSPC);
+		return (rc);
+	}
+
+	/* no space in the allocation group.  release the buffer and
+	 * return ENOSPC.
+	 */
+	release_metapage(mp);
+
+	return (ENOSPC);
+}
+
+
+/*
+ * NAME:	dbAllocAny()
+ *
+ * FUNCTION:    attempt to allocate the specified number of contiguous
+ *		free blocks anywhere in the file system.
+ *
+ *		dbAllocAny() attempts to find the sufficient free space by
+ *		searching down the dmap control pages, starting with the
+ *		highest level (i.e. L0, L1, L2) control page.  if free space
+ *		large enough to satisfy the desired free space is found, the
+ *		desired free space is allocated.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      nblocks	 -  actual number of contiguous free blocks desired.
+ *      l2nb	 -  log2 number of contiguous free blocks desired.
+ *      results	-  on successful return, set to the starting block number
+ *		   of the newly allocated range.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ *
+ * serialization: IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static int dbAllocAny(bmap_t * bmp, s64 nblocks, int l2nb, s64 * results)
+{
+	int rc;
+	s64 blkno = 0;
+
+	/* starting with the top level dmap control page, search
+	 * down the dmap control levels for sufficient free space.
+	 * if free space is found, dbFindCtl() returns the starting
+	 * block number of the dmap that contains or starts off the
+	 * range of free space.
+	 */
+	if ((rc = dbFindCtl(bmp, l2nb, bmp->db_maxlevel, &blkno)))
+		return (rc);
+
+	/* allocate the blocks.
+	 */
+	rc = dbAllocCtl(bmp, nblocks, l2nb, blkno, results);
+	assert(rc != ENOSPC);
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbFindCtl()
+ *
+ * FUNCTION:    starting at a specified dmap control page level and block
+ *		number, search down the dmap control levels for a range of
+ *	        contiguous free blocks large enough to satisfy an allocation
+ *		request for the specified number of free blocks.
+ *
+ *		if sufficient contiguous free blocks are found, this routine
+ *		returns the starting block number within a dmap page that
+ *		contains or starts a range of contiqious free blocks that
+ *		is sufficient in size.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      level	-  starting dmap control page level.
+ *      l2nb	-  log2 number of contiguous free blocks desired.
+ *      *blkno	-  on entry, starting block number for conducting the search.
+ *		   on successful return, the first block within a dmap page
+ *		   that contains or starts a range of contiguous free blocks.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ *
+ * serialization: IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static int dbFindCtl(bmap_t * bmp, int l2nb, int level, s64 * blkno)
+{
+	int rc, leafidx, lev;
+	s64 b, lblkno;
+	dmapctl_t *dcp;
+	int budmin;
+	metapage_t *mp;
+
+	/* starting at the specified dmap control page level and block
+	 * number, search down the dmap control levels for the starting
+	 * block number of a dmap page that contains or starts off 
+	 * sufficient free blocks.
+	 */
+	for (lev = level, b = *blkno; lev >= 0; lev--) {
+		/* get the buffer of the dmap control page for the block
+		 * number and level (i.e. L0, L1, L2).
+		 */
+		lblkno = BLKTOCTL(b, bmp->db_l2nbperpage, lev);
+		mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL)
+			return (EIO);
+		dcp = (dmapctl_t *) mp->data;
+		budmin = dcp->budmin;
+
+		/* search the tree within the dmap control page for
+		 * sufficent free space.  if sufficient free space is found,
+		 * dbFindLeaf() returns the index of the leaf at which
+		 * free space was found.
+		 */
+		rc = dbFindLeaf((dmtree_t *) dcp, l2nb, &leafidx);
+
+		/* release the buffer.
+		 */
+		release_metapage(mp);
+
+		/* space found ?
+		 */
+		if (rc) {
+			assert(lev == level);
+			return (ENOSPC);
+		}
+
+		/* adjust the block number to reflect the location within
+		 * the dmap control page (i.e. the leaf) at which free 
+		 * space was found.
+		 */
+		b += (((s64) leafidx) << budmin);
+
+		/* we stop the search at this dmap control page level if
+		 * the number of blocks required is greater than or equal
+		 * to the maximum number of blocks described at the next
+		 * (lower) level.
+		 */
+		if (l2nb >= budmin)
+			break;
+	}
+
+	*blkno = b;
+	return (0);
+}
+
+
+/*
+ * NAME:	dbAllocCtl()
+ *
+ * FUNCTION:    attempt to allocate a specified number of contiguous
+ *		blocks starting within a specific dmap.  
+ *		
+ *		this routine is called by higher level routines that search
+ *		the dmap control pages above the actual dmaps for contiguous
+ *		free space.  the result of successful searches by these
+ * 		routines are the starting block numbers within dmaps, with
+ *		the dmaps themselves containing the desired contiguous free
+ *		space or starting a contiguous free space of desired size
+ *		that is made up of the blocks of one or more dmaps. these
+ *		calls should not fail due to insufficent resources.
+ *
+ *		this routine is called in some cases where it is not known
+ *		whether it will fail due to insufficient resources.  more
+ *		specifically, this occurs when allocating from an allocation
+ *		group whose size is equal to the number of blocks per dmap.
+ *		in this case, the dmap control pages are not examined prior
+ *		to calling this routine (to save pathlength) and the call
+ *		might fail.
+ *
+ *		for a request size that fits within a dmap, this routine relies
+ *		upon the dmap's dmtree to find the requested contiguous free
+ *		space.  for request sizes that are larger than a dmap, the
+ *		requested free space will start at the first block of the
+ *		first dmap (i.e. blkno).
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      nblocks	 -  actual number of contiguous free blocks to allocate.
+ *      l2nb	 -  log2 number of contiguous free blocks to allocate.
+ *      blkno	 -  starting block number of the dmap to start the allocation
+ *		    from.
+ *      results	-  on successful return, set to the starting block number
+ *		   of the newly allocated range.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ *
+ * serialization: IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static int
+dbAllocCtl(bmap_t * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results)
+{
+	int rc, nb;
+	s64 b, lblkno, n;
+	metapage_t *mp;
+	dmap_t *dp;
+
+	/* check if the allocation request is confined to a single dmap.
+	 */
+	if (l2nb <= L2BPERDMAP) {
+		/* get the buffer for the dmap.
+		 */
+		lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage);
+		mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL)
+			return (EIO);
+		dp = (dmap_t *) mp->data;
+
+		/* try to allocate the blocks.
+		 */
+		rc = dbAllocDmapLev(bmp, dp, (int) nblocks, l2nb, results);
+		if (rc == 0)
+			mark_metapage_dirty(mp);
+
+		release_metapage(mp);
+
+		return (rc);
+	}
+
+	/* allocation request involving multiple dmaps. it must start on
+	 * a dmap boundary.
+	 */
+	assert((blkno & (BPERDMAP - 1)) == 0);
+
+	/* allocate the blocks dmap by dmap.
+	 */
+	for (n = nblocks, b = blkno; n > 0; n -= nb, b += nb) {
+		/* get the buffer for the dmap.
+		 */
+		lblkno = BLKTODMAP(b, bmp->db_l2nbperpage);
+		mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL) {
+			rc = EIO;
+			goto backout;
+		}
+		dp = (dmap_t *) mp->data;
+
+		/* the dmap better be all free.
+		 */
+		assert(dp->tree.stree[ROOT] == L2BPERDMAP);
+
+		/* determine how many blocks to allocate from this dmap.
+		 */
+		nb = min(n, (s64)BPERDMAP);
+
+		/* allocate the blocks from the dmap.
+		 */
+		if ((rc = dbAllocDmap(bmp, dp, b, nb))) {
+			release_metapage(mp);
+			goto backout;
+		}
+
+		/* write the buffer.
+		 */
+		write_metapage(mp);
+	}
+
+	/* set the results (starting block number) and return.
+	 */
+	*results = blkno;
+	return (0);
+
+	/* something failed in handling an allocation request involving
+	 * multiple dmaps.  we'll try to clean up by backing out any
+	 * allocation that has already happened for this request.  if
+	 * we fail in backing out the allocation, we'll mark the file
+	 * system to indicate that blocks have been leaked.
+	 */
+      backout:
+
+	/* try to backout the allocations dmap by dmap.
+	 */
+	for (n = nblocks - n, b = blkno; n > 0;
+	     n -= BPERDMAP, b += BPERDMAP) {
+		/* get the buffer for this dmap.
+		 */
+		lblkno = BLKTODMAP(b, bmp->db_l2nbperpage);
+		mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL) {
+			/* could not back out.  mark the file system
+			 * to indicate that we have leaked blocks.
+			 */
+			fsDirty();	/* !!! */
+			jERROR(1,
+			       ("dbAllocCtl: I/O Error: Block Leakage.\n"));
+			continue;
+		}
+		dp = (dmap_t *) mp->data;
+
+		/* free the blocks is this dmap.
+		 */
+		if (dbFreeDmap(bmp, dp, b, BPERDMAP)) {
+			/* could not back out.  mark the file system
+			 * to indicate that we have leaked blocks.
+			 */
+			release_metapage(mp);
+			fsDirty();	/* !!! */
+			jERROR(1, ("dbAllocCtl: Block Leakage.\n"));
+			continue;
+		}
+
+		/* write the buffer.
+		 */
+		write_metapage(mp);
+	}
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbAllocDmapLev()
+ *
+ * FUNCTION:    attempt to allocate a specified number of contiguous blocks
+ *		from a specified dmap.
+ *		
+ *		this routine checks if the contiguous blocks are available.
+ *		if so, nblocks of blocks are allocated; otherwise, ENOSPC is
+ *		returned.
+ *
+ * PARAMETERS:
+ *      mp	-  pointer to bmap descriptor
+ *      dp	-  pointer to dmap to attempt to allocate blocks from. 
+ *      l2nb	-  log2 number of contiguous block desired.
+ *      nblocks	-  actual number of contiguous block desired.
+ *      results	-  on successful return, set to the starting block number
+ *		   of the newly allocated range.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient disk resources
+ *      EIO	- i/o error
+ *
+ * serialization: IREAD_LOCK(ipbmap), e.g., from dbAlloc(), or 
+ *	IWRITE_LOCK(ipbmap), e.g., dbAllocCtl(), held on entry/exit;
+ */
+static int
+dbAllocDmapLev(bmap_t * bmp,
+	       dmap_t * dp, int nblocks, int l2nb, s64 * results)
+{
+	s64 blkno;
+	int leafidx, rc;
+
+	/* can't be more than a dmaps worth of blocks */
+	assert(l2nb <= L2BPERDMAP);
+
+	/* search the tree within the dmap page for sufficient
+	 * free space.  if sufficient free space is found, dbFindLeaf()
+	 * returns the index of the leaf at which free space was found.
+	 */
+	if (dbFindLeaf((dmtree_t *) & dp->tree, l2nb, &leafidx))
+		return (ENOSPC);
+
+	/* determine the block number within the file system corresponding
+	 * to the leaf at which free space was found.
+	 */
+	blkno = le64_to_cpu(dp->start) + (leafidx << L2DBWORD);
+
+	/* if not all bits of the dmap word are free, get the starting
+	 * bit number within the dmap word of the required string of free
+	 * bits and adjust the block number with this value.
+	 */
+	if (dp->tree.stree[leafidx + LEAFIND] < BUDMIN)
+		blkno += dbFindBits(le32_to_cpu(dp->wmap[leafidx]), l2nb);
+
+	/* allocate the blocks */
+	if ((rc = dbAllocDmap(bmp, dp, blkno, nblocks)) == 0)
+		*results = blkno;
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbAllocDmap()
+ *
+ * FUNCTION:    adjust the disk allocation map to reflect the allocation
+ *		of a specified block range within a dmap.
+ *
+ *		this routine allocates the specified blocks from the dmap
+ *		through a call to dbAllocBits(). if the allocation of the
+ *		block range causes the maximum string of free blocks within
+ *		the dmap to change (i.e. the value of the root of the dmap's
+ *		dmtree), this routine will cause this change to be reflected
+ *		up through the appropriate levels of the dmap control pages
+ *		by a call to dbAdjCtl() for the L0 dmap control page that
+ *		covers this dmap.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      dp	-  pointer to dmap to allocate the block range from.
+ *      blkno	-  starting block number of the block to be allocated.
+ *      nblocks	-  number of blocks to be allocated.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      EIO	- i/o error
+ *
+ * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static int dbAllocDmap(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks)
+{
+	s8 oldroot;
+	int rc;
+
+	/* save the current value of the root (i.e. maximum free string)
+	 * of the dmap tree.
+	 */
+	oldroot = dp->tree.stree[ROOT];
+
+	/* allocate the specified (blocks) bits */
+	dbAllocBits(bmp, dp, blkno, nblocks);
+
+	/* if the root has not changed, done. */
+	if (dp->tree.stree[ROOT] == oldroot)
+		return (0);
+
+	/* root changed. bubble the change up to the dmap control pages.
+	 * if the adjustment of the upper level control pages fails,
+	 * backout the bit allocation (thus making everything consistent).
+	 */
+	if ((rc = dbAdjCtl(bmp, blkno, dp->tree.stree[ROOT], 1, 0)))
+		dbFreeBits(bmp, dp, blkno, nblocks);
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbFreeDmap()
+ *
+ * FUNCTION:    adjust the disk allocation map to reflect the allocation
+ *		of a specified block range within a dmap.
+ *
+ *		this routine frees the specified blocks from the dmap through
+ *		a call to dbFreeBits(). if the deallocation of the block range
+ *		causes the maximum string of free blocks within the dmap to
+ *		change (i.e. the value of the root of the dmap's dmtree), this
+ *		routine will cause this change to be reflected up through the
+ *	        appropriate levels of the dmap control pages by a call to
+ *		dbAdjCtl() for the L0 dmap control page that covers this dmap.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      dp	-  pointer to dmap to free the block range from.
+ *      blkno	-  starting block number of the block to be freed.
+ *      nblocks	-  number of blocks to be freed.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      EIO	- i/o error
+ *
+ * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static int dbFreeDmap(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks)
+{
+	s8 oldroot;
+	int rc, word;
+
+	/* save the current value of the root (i.e. maximum free string)
+	 * of the dmap tree.
+	 */
+	oldroot = dp->tree.stree[ROOT];
+
+	/* free the specified (blocks) bits */
+	dbFreeBits(bmp, dp, blkno, nblocks);
+
+	/* if the root has not changed, done. */
+	if (dp->tree.stree[ROOT] == oldroot)
+		return (0);
+
+	/* root changed. bubble the change up to the dmap control pages.
+	 * if the adjustment of the upper level control pages fails,
+	 * backout the deallocation. 
+	 */
+	if ((rc = dbAdjCtl(bmp, blkno, dp->tree.stree[ROOT], 0, 0))) {
+		word = (blkno & (BPERDMAP - 1)) >> L2DBWORD;
+
+		/* as part of backing out the deallocation, we will have
+		 * to back split the dmap tree if the deallocation caused
+		 * the freed blocks to become part of a larger binary buddy
+		 * system.
+		 */
+		if (dp->tree.stree[word] == NOFREE)
+			dbBackSplit((dmtree_t *) & dp->tree, word);
+
+		dbAllocBits(bmp, dp, blkno, nblocks);
+	}
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbAllocBits()
+ *
+ * FUNCTION:    allocate a specified block range from a dmap.
+ *
+ *		this routine updates the dmap to reflect the working
+ *		state allocation of the specified block range. it directly
+ *		updates the bits of the working map and causes the adjustment
+ *		of the binary buddy system described by the dmap's dmtree
+ *		leaves to reflect the bits allocated.  it also causes the
+ *		dmap's dmtree, as a whole, to reflect the allocated range.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      dp	-  pointer to dmap to allocate bits from.
+ *      blkno	-  starting block number of the bits to be allocated.
+ *      nblocks	-  number of bits to be allocated.
+ *
+ * RETURN VALUES: none
+ *
+ * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static void dbAllocBits(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks)
+{
+	int dbitno, word, rembits, nb, nwords, wbitno, nw, agno;
+	dmtree_t *tp = (dmtree_t *) & dp->tree;
+	int size;
+	s8 *leaf;
+
+	/* pick up a pointer to the leaves of the dmap tree */
+	leaf = dp->tree.stree + LEAFIND;
+
+	/* determine the bit number and word within the dmap of the
+	 * starting block.
+	 */
+	dbitno = blkno & (BPERDMAP - 1);
+	word = dbitno >> L2DBWORD;
+
+	/* block range better be within the dmap */
+	assert(dbitno + nblocks <= BPERDMAP);
+
+	/* allocate the bits of the dmap's words corresponding to the block
+	 * range. not all bits of the first and last words may be contained
+	 * within the block range.  if this is the case, we'll work against
+	 * those words (i.e. partial first and/or last) on an individual basis
+	 * (a single pass), allocating the bits of interest by hand and
+	 * updating the leaf corresponding to the dmap word. a single pass
+	 * will be used for all dmap words fully contained within the
+	 * specified range.  within this pass, the bits of all fully contained
+	 * dmap words will be marked as free in a single shot and the leaves
+	 * will be updated. a single leaf may describe the free space of
+	 * multiple dmap words, so we may update only a subset of the actual
+	 * leaves corresponding to the dmap words of the block range.
+	 */
+	for (rembits = nblocks; rembits > 0; rembits -= nb, dbitno += nb) {
+		/* determine the bit number within the word and
+		 * the number of bits within the word.
+		 */
+		wbitno = dbitno & (DBWORD - 1);
+		nb = min(rembits, DBWORD - wbitno);
+
+		/* check if only part of a word is to be allocated.
+		 */
+		if (nb < DBWORD) {
+			/* allocate (set to 1) the appropriate bits within
+			 * this dmap word.
+			 */
+			dp->wmap[word] |= cpu_to_le32(ONES << (DBWORD - nb)
+						      >> wbitno);
+
+			/* update the leaf for this dmap word. in addition
+			 * to setting the leaf value to the binary buddy max
+			 * of the updated dmap word, dbSplit() will split
+			 * the binary system of the leaves if need be.
+			 */
+			dbSplit(tp, word, BUDMIN,
+				dbMaxBud((u8 *) & dp->wmap[word]));
+
+			word += 1;
+		} else {
+			/* one or more dmap words are fully contained
+			 * within the block range.  determine how many
+			 * words and allocate (set to 1) the bits of these
+			 * words.
+			 */
+			nwords = rembits >> L2DBWORD;
+			memset(&dp->wmap[word], (int) ONES, nwords * 4);
+
+			/* determine how many bits.
+			 */
+			nb = nwords << L2DBWORD;
+
+			/* now update the appropriate leaves to reflect
+			 * the allocated words.
+			 */
+			for (; nwords > 0; nwords -= nw) {
+				assert(leaf[word] >= BUDMIN);
+
+				/* determine what the leaf value should be
+				 * updated to as the minimum of the l2 number
+				 * of bits being allocated and the l2 number
+				 * of bits currently described by this leaf.
+				 */
+				size = min((int)leaf[word], NLSTOL2BSZ(nwords));
+
+				/* update the leaf to reflect the allocation.
+				 * in addition to setting the leaf value to
+				 * NOFREE, dbSplit() will split the binary
+				 * system of the leaves to reflect the current
+				 * allocation (size).
+				 */
+				dbSplit(tp, word, size, NOFREE);
+
+				/* get the number of dmap words handled */
+				nw = BUDSIZE(size, BUDMIN);
+				word += nw;
+			}
+		}
+	}
+
+	/* update the free count for this dmap */
+	dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) - nblocks);
+
+	BMAP_LOCK(bmp);
+
+	/* if this allocation group is completely free,
+	 * update the maximum allocation group number if this allocation
+	 * group is the new max.
+	 */
+	agno = blkno >> bmp->db_agl2size;
+	if (agno > bmp->db_maxag)
+		bmp->db_maxag = agno;
+
+	/* update the free count for the allocation group and map */
+	bmp->db_agfree[agno] -= nblocks;
+	bmp->db_nfree -= nblocks;
+
+	BMAP_UNLOCK(bmp);
+}
+
+
+/*
+ * NAME:	dbFreeBits()
+ *
+ * FUNCTION:    free a specified block range from a dmap.
+ *
+ *		this routine updates the dmap to reflect the working
+ *		state allocation of the specified block range. it directly
+ *		updates the bits of the working map and causes the adjustment
+ *		of the binary buddy system described by the dmap's dmtree
+ *		leaves to reflect the bits freed.  it also causes the dmap's
+ *		dmtree, as a whole, to reflect the deallocated range.
+ *
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      dp	-  pointer to dmap to free bits from.
+ *      blkno	-  starting block number of the bits to be freed.
+ *      nblocks	-  number of bits to be freed.
+ *
+ * RETURN VALUES: none
+ *
+ * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static void dbFreeBits(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks)
+{
+	int dbitno, word, rembits, nb, nwords, wbitno, nw, agno;
+	dmtree_t *tp = (dmtree_t *) & dp->tree;
+	int size;
+
+	/* determine the bit number and word within the dmap of the
+	 * starting block.
+	 */
+	dbitno = blkno & (BPERDMAP - 1);
+	word = dbitno >> L2DBWORD;
+
+	/* block range better be within the dmap.
+	 */
+	assert(dbitno + nblocks <= BPERDMAP);
+
+	/* free the bits of the dmaps words corresponding to the block range.
+	 * not all bits of the first and last words may be contained within
+	 * the block range.  if this is the case, we'll work against those
+	 * words (i.e. partial first and/or last) on an individual basis
+	 * (a single pass), freeing the bits of interest by hand and updating
+	 * the leaf corresponding to the dmap word. a single pass will be used
+	 * for all dmap words fully contained within the specified range.  
+	 * within this pass, the bits of all fully contained dmap words will
+	 * be marked as free in a single shot and the leaves will be updated. a
+	 * single leaf may describe the free space of multiple dmap words,
+	 * so we may update only a subset of the actual leaves corresponding
+	 * to the dmap words of the block range.
+	 *
+	 * dbJoin() is used to update leaf values and will join the binary
+	 * buddy system of the leaves if the new leaf values indicate this
+	 * should be done.
+	 */
+	for (rembits = nblocks; rembits > 0; rembits -= nb, dbitno += nb) {
+		/* determine the bit number within the word and
+		 * the number of bits within the word.
+		 */
+		wbitno = dbitno & (DBWORD - 1);
+		nb = min(rembits, DBWORD - wbitno);
+
+		/* check if only part of a word is to be freed.
+		 */
+		if (nb < DBWORD) {
+			/* free (zero) the appropriate bits within this
+			 * dmap word. 
+			 */
+			dp->wmap[word] &=
+			    cpu_to_le32(~(ONES << (DBWORD - nb)
+					  >> wbitno));
+
+			/* update the leaf for this dmap word.
+			 */
+			dbJoin(tp, word,
+			       dbMaxBud((u8 *) & dp->wmap[word]));
+
+			word += 1;
+		} else {
+			/* one or more dmap words are fully contained
+			 * within the block range.  determine how many
+			 * words and free (zero) the bits of these words.
+			 */
+			nwords = rembits >> L2DBWORD;
+			memset(&dp->wmap[word], 0, nwords * 4);
+
+			/* determine how many bits.
+			 */
+			nb = nwords << L2DBWORD;
+
+			/* now update the appropriate leaves to reflect
+			 * the freed words.
+			 */
+			for (; nwords > 0; nwords -= nw) {
+				/* determine what the leaf value should be
+				 * updated to as the minimum of the l2 number
+				 * of bits being freed and the l2 (max) number
+				 * of bits that can be described by this leaf.
+				 */
+				size =
+				    min(LITOL2BSZ
+					(word, L2LPERDMAP, BUDMIN),
+					NLSTOL2BSZ(nwords));
+
+				/* update the leaf.
+				 */
+				dbJoin(tp, word, size);
+
+				/* get the number of dmap words handled.
+				 */
+				nw = BUDSIZE(size, BUDMIN);
+				word += nw;
+			}
+		}
+	}
+
+	/* update the free count for this dmap.
+	 */
+	dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) + nblocks);
+
+	BMAP_LOCK(bmp);
+
+	/* update the free count for the allocation group and 
+	 * map.
+	 */
+	agno = blkno >> bmp->db_agl2size;
+	bmp->db_nfree += nblocks;
+	bmp->db_agfree[agno] += nblocks;
+
+	/* check if this allocation group is not completely free and
+	 * if it is currently the maximum (rightmost) allocation group.
+	 * if so, establish the new maximum allocation group number by
+	 * searching left for the first allocation group with allocation.
+	 */
+	if ((bmp->db_agfree[agno] == bmp->db_agsize
+	     && agno == bmp->db_maxag) || (agno == bmp->db_numag - 1
+					   && bmp->db_agfree[agno] ==
+					   (bmp-> db_mapsize &
+					    (BPERDMAP - 1)))) {
+		while (bmp->db_maxag > 0) {
+			bmp->db_maxag -= 1;
+			if (bmp->db_agfree[bmp->db_maxag] !=
+			    bmp->db_agsize)
+				break;
+		}
+
+		/* re-establish the allocation group preference if the
+		 * current preference is right of the maximum allocation
+		 * group.
+		 */
+		if (bmp->db_agpref > bmp->db_maxag)
+			bmp->db_agpref = bmp->db_maxag;
+	}
+
+	BMAP_UNLOCK(bmp);
+}
+
+
+/*
+ * NAME:	dbAdjCtl()
+ *
+ * FUNCTION:	adjust a dmap control page at a specified level to reflect
+ *		the change in a lower level dmap or dmap control page's
+ *		maximum string of free blocks (i.e. a change in the root
+ *		of the lower level object's dmtree) due to the allocation
+ *		or deallocation of a range of blocks with a single dmap.
+ *
+ *		on entry, this routine is provided with the new value of
+ *		the lower level dmap or dmap control page root and the
+ *		starting block number of the block range whose allocation
+ *		or deallocation resulted in the root change.  this range
+ *		is respresented by a single leaf of the current dmapctl
+ *		and the leaf will be updated with this value, possibly
+ *		causing a binary buddy system within the leaves to be 
+ *		split or joined.  the update may also cause the dmapctl's
+ *		dmtree to be updated.
+ *
+ *		if the adjustment of the dmap control page, itself, causes its
+ *		root to change, this change will be bubbled up to the next dmap
+ *		control level by a recursive call to this routine, specifying
+ *		the new root value and the next dmap control page level to
+ *		be adjusted.
+ * PARAMETERS:
+ *      bmp	-  pointer to bmap descriptor
+ *      blkno	-  the first block of a block range within a dmap.  it is
+ *		   the allocation or deallocation of this block range that
+ *		   requires the dmap control page to be adjusted.
+ *      newval	-  the new value of the lower level dmap or dmap control
+ *		   page root.
+ *      alloc	-  TRUE if adjustment is due to an allocation.
+ *      level	-  current level of dmap control page (i.e. L0, L1, L2) to
+ *		   be adjusted.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      EIO	- i/o error
+ *
+ * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static int
+dbAdjCtl(bmap_t * bmp, s64 blkno, int newval, int alloc, int level)
+{
+	metapage_t *mp;
+	s8 oldroot;
+	int oldval;
+	s64 lblkno;
+	dmapctl_t *dcp;
+	int rc, leafno, ti;
+
+	/* get the buffer for the dmap control page for the specified
+	 * block number and control page level.
+	 */
+	lblkno = BLKTOCTL(blkno, bmp->db_l2nbperpage, level);
+	mp = read_metapage(bmp->db_ipbmap, lblkno, PSIZE, 0);
+	if (mp == NULL)
+		return (EIO);
+	dcp = (dmapctl_t *) mp->data;
+
+	/* determine the leaf number corresponding to the block and
+	 * the index within the dmap control tree.
+	 */
+	leafno = BLKTOCTLLEAF(blkno, dcp->budmin);
+	ti = leafno + le32_to_cpu(dcp->leafidx);
+
+	/* save the current leaf value and the current root level (i.e.
+	 * maximum l2 free string described by this dmapctl).
+	 */
+	oldval = dcp->stree[ti];
+	oldroot = dcp->stree[ROOT];
+
+	/* check if this is a control page update for an allocation.
+	 * if so, update the leaf to reflect the new leaf value using
+	 * dbSplit(); otherwise (deallocation), use dbJoin() to udpate
+	 * the leaf with the new value.  in addition to updating the
+	 * leaf, dbSplit() will also split the binary buddy system of
+	 * the leaves, if required, and bubble new values within the
+	 * dmapctl tree, if required.  similarly, dbJoin() will join
+	 * the binary buddy system of leaves and bubble new values up
+	 * the dmapctl tree as required by the new leaf value.
+	 */
+	if (alloc) {
+		/* check if we are in the middle of a binary buddy
+		 * system.  this happens when we are performing the
+		 * first allocation out of an allocation group that
+		 * is part (not the first part) of a larger binary
+		 * buddy system.  if we are in the middle, back split
+		 * the system prior to calling dbSplit() which assumes
+		 * that it is at the front of a binary buddy system.
+		 */
+		if (oldval == NOFREE) {
+			dbBackSplit((dmtree_t *) dcp, leafno);
+			oldval = dcp->stree[ti];
+		}
+		dbSplit((dmtree_t *) dcp, leafno, dcp->budmin, newval);
+	} else {
+		dbJoin((dmtree_t *) dcp, leafno, newval);
+	}
+
+	/* check if the root of the current dmap control page changed due
+	 * to the update and if the current dmap control page is not at
+	 * the current top level (i.e. L0, L1, L2) of the map.  if so (i.e.
+	 * root changed and this is not the top level), call this routine
+	 * again (recursion) for the next higher level of the mapping to
+	 * reflect the change in root for the current dmap control page.
+	 */
+	if (dcp->stree[ROOT] != oldroot) {
+		/* are we below the top level of the map.  if so,
+		 * bubble the root up to the next higher level.
+		 */
+		if (level < bmp->db_maxlevel) {
+			/* bubble up the new root of this dmap control page to
+			 * the next level.
+			 */
+			if ((rc =
+			     dbAdjCtl(bmp, blkno, dcp->stree[ROOT], alloc,
+				      level + 1))) {
+				/* something went wrong in bubbling up the new
+				 * root value, so backout the changes to the
+				 * current dmap control page.
+				 */
+				if (alloc) {
+					dbJoin((dmtree_t *) dcp, leafno,
+					       oldval);
+				} else {
+					/* the dbJoin() above might have
+					 * caused a larger binary buddy system
+					 * to form and we may now be in the
+					 * middle of it.  if this is the case,
+					 * back split the buddies.
+					 */
+					if (dcp->stree[ti] == NOFREE)
+						dbBackSplit((dmtree_t *)
+							    dcp, leafno);
+					dbSplit((dmtree_t *) dcp, leafno,
+						dcp->budmin, oldval);
+				}
+
+				/* release the buffer and return the error.
+				 */
+				release_metapage(mp);
+				return (rc);
+			}
+		} else {
+			/* we're at the top level of the map. update
+			 * the bmap control page to reflect the size
+			 * of the maximum free buddy system.
+			 */
+			assert(level == bmp->db_maxlevel);
+			assert(bmp->db_maxfreebud == oldroot);
+			bmp->db_maxfreebud = dcp->stree[ROOT];
+		}
+	}
+
+	/* write the buffer.
+	 */
+	write_metapage(mp);
+
+	return (0);
+}
+
+
+/*
+ * NAME:	dbSplit()
+ *
+ * FUNCTION:    update the leaf of a dmtree with a new value, splitting
+ *		the leaf from the binary buddy system of the dmtree's
+ *		leaves, as required.
+ *
+ * PARAMETERS:
+ *      tp	- pointer to the tree containing the leaf.
+ *      leafno	- the number of the leaf to be updated.
+ *      splitsz	- the size the binary buddy system starting at the leaf
+ *		  must be split to, specified as the log2 number of blocks.
+ *      newval	- the new value for the leaf.
+ *
+ * RETURN VALUES: none
+ *
+ * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval)
+{
+	int budsz;
+	int cursz;
+	s8 *leaf = tp->dmt_stree + le32_to_cpu(tp->dmt_leafidx);
+
+	/* check if the leaf needs to be split.
+	 */
+	if (leaf[leafno] > tp->dmt_budmin) {
+		/* the split occurs by cutting the buddy system in half
+		 * at the specified leaf until we reach the specified
+		 * size.  pick up the starting split size (current size
+		 * - 1 in l2) and the corresponding buddy size.
+		 */
+		cursz = leaf[leafno] - 1;
+		budsz = BUDSIZE(cursz, tp->dmt_budmin);
+
+		/* split until we reach the specified size.
+		 */
+		while (cursz >= splitsz) {
+			/* update the buddy's leaf with its new value.
+			 */
+			dbAdjTree(tp, leafno ^ budsz, cursz);
+
+			/* on to the next size and buddy.
+			 */
+			cursz -= 1;
+			budsz >>= 1;
+		}
+	}
+
+	/* adjust the dmap tree to reflect the specified leaf's new 
+	 * value.
+	 */
+	dbAdjTree(tp, leafno, newval);
+}
+
+
+/*
+ * NAME:	dbBackSplit()
+ *
+ * FUNCTION:    back split the binary buddy system of dmtree leaves
+ *		that hold a specified leaf until the specified leaf
+ *		starts its own binary buddy system.
+ *
+ *		the allocators typically perform allocations at the start
+ *		of binary buddy systems and dbSplit() is used to accomplish
+ *		any required splits.  in some cases, however, allocation
+ *		may occur in the middle of a binary system and requires a
+ *		back split, with the split proceeding out from the middle of
+ *		the system (less efficient) rather than the start of the
+ *		system (more efficient).  the cases in which a back split
+ *		is required are rare and are limited to the first allocation
+ *		within an allocation group which is a part (not first part)
+ *		of a larger binary buddy system and a few exception cases
+ *		in which a previous join operation must be backed out.
+ *
+ * PARAMETERS:
+ *      tp	- pointer to the tree containing the leaf.
+ *      leafno	- the number of the leaf to be updated.
+ *
+ * RETURN VALUES: none
+ *
+ * serialization: IREAD_LOCK(ipbmap) or IWRITE_LOCK(ipbmap) held on entry/exit;
+ */
+static void dbBackSplit(dmtree_t * tp, int leafno)
+{
+	int budsz, bud, w, bsz, size;
+	int cursz;
+	s8 *leaf = tp->dmt_stree + le32_to_cpu(tp->dmt_leafidx);
+
+	/* leaf should be part (not first part) of a binary
+	 * buddy system.
+	 */
+	assert(leaf[leafno] == NOFREE);
+
+	/* the back split is accomplished by iteratively finding the leaf
+	 * that starts the buddy system that contains the specified leaf and
+	 * splitting that system in two.  this iteration continues until
+	 * the specified leaf becomes the start of a buddy system. 
+	 *
+	 * determine maximum possible l2 size for the specified leaf.
+	 */
+	size =
+	    LITOL2BSZ(leafno, le32_to_cpu(tp->dmt_l2nleafs),
+		      tp->dmt_budmin);
+
+	/* determine the number of leaves covered by this size.  this
+	 * is the buddy size that we will start with as we search for
+	 * the buddy system that contains the specified leaf.
+	 */
+	budsz = BUDSIZE(size, tp->dmt_budmin);
+
+	/* back split.
+	 */
+	while (leaf[leafno] == NOFREE) {
+		/* find the leftmost buddy leaf.
+		 */
+		for (w = leafno, bsz = budsz;; bsz <<= 1,
+		     w = (w < bud) ? w : bud) {
+			assert(bsz < le32_to_cpu(tp->dmt_nleafs));
+
+			/* determine the buddy.
+			 */
+			bud = w ^ bsz;
+
+			/* check if this buddy is the start of the system.
+			 */
+			if (leaf[bud] != NOFREE) {
+				/* split the leaf at the start of the
+				 * system in two.
+				 */
+				cursz = leaf[bud] - 1;
+				dbSplit(tp, bud, cursz, cursz);
+				break;
+			}
+		}
+	}
+
+	assert(leaf[leafno] == size);
+}
+
+
+/*
+ * NAME:	dbJoin()
+ *
+ * FUNCTION:    update the leaf of a dmtree with a new value, joining
+ *		the leaf with other leaves of the dmtree into a multi-leaf
+ *		binary buddy system, as required.
+ *
+ * PARAMETERS:
+ *      tp	- pointer to the tree containing the leaf.
+ *      leafno	- the number of the leaf to be updated.
+ *      newval	- the new value for the leaf.
+ *
+ * RETURN VALUES: none
+ */
+static void dbJoin(dmtree_t * tp, int leafno, int newval)
+{
+	int budsz, buddy;
+	s8 *leaf;
+
+	/* can the new leaf value require a join with other leaves ?
+	 */
+	if (newval >= tp->dmt_budmin) {
+		/* pickup a pointer to the leaves of the tree.
+		 */
+		leaf = tp->dmt_stree + le32_to_cpu(tp->dmt_leafidx);
+
+		/* try to join the specified leaf into a large binary
+		 * buddy system.  the join proceeds by attempting to join
+		 * the specified leafno with its buddy (leaf) at new value.
+		 * if the join occurs, we attempt to join the left leaf
+		 * of the joined buddies with its buddy at new value + 1.
+		 * we continue to join until we find a buddy that cannot be
+		 * joined (does not have a value equal to the size of the
+		 * last join) or until all leaves have been joined into a
+		 * single system.
+		 *
+		 * get the buddy size (number of words covered) of
+		 * the new value.
+		 */
+		budsz = BUDSIZE(newval, tp->dmt_budmin);
+
+		/* try to join.
+		 */
+		while (budsz < le32_to_cpu(tp->dmt_nleafs)) {
+			/* get the buddy leaf.
+			 */
+			buddy = leafno ^ budsz;
+
+			/* if the leaf's new value is greater than its
+			 * buddy's value, we join no more.
+			 */
+			if (newval > leaf[buddy])
+				break;
+
+			assert(newval == leaf[buddy]);
+
+			/* check which (leafno or buddy) is the left buddy.
+			 * the left buddy gets to claim the blocks resulting
+			 * from the join while the right gets to claim none.
+			 * the left buddy is also eligable to participate in
+			 * a join at the next higher level while the right
+			 * is not.
+			 *
+			 */
+			if (leafno < buddy) {
+				/* leafno is the left buddy.
+				 */
+				dbAdjTree(tp, buddy, NOFREE);
+			} else {
+				/* buddy is the left buddy and becomes
+				 * leafno.
+				 */
+				dbAdjTree(tp, leafno, NOFREE);
+				leafno = buddy;
+			}
+
+			/* on to try the next join.
+			 */
+			newval += 1;
+			budsz <<= 1;
+		}
+	}
+
+	/* update the leaf value.
+	 */
+	dbAdjTree(tp, leafno, newval);
+}
+
+
+/*
+ * NAME:	dbAdjTree()
+ *
+ * FUNCTION:    update a leaf of a dmtree with a new value, adjusting
+ *		the dmtree, as required, to reflect the new leaf value.
+ *		the combination of any buddies must already be done before
+ *		this is called.
+ *
+ * PARAMETERS:
+ *      tp	- pointer to the tree to be adjusted.
+ *      leafno	- the number of the leaf to be updated.
+ *      newval	- the new value for the leaf.
+ *
+ * RETURN VALUES: none
+ */
+static void dbAdjTree(dmtree_t * tp, int leafno, int newval)
+{
+	int lp, pp, k;
+	int max;
+
+	/* pick up the index of the leaf for this leafno.
+	 */
+	lp = leafno + le32_to_cpu(tp->dmt_leafidx);
+
+	/* is the current value the same as the old value ?  if so,
+	 * there is nothing to do.
+	 */
+	if (tp->dmt_stree[lp] == newval)
+		return;
+
+	/* set the new value.
+	 */
+	tp->dmt_stree[lp] = newval;
+
+	/* bubble the new value up the tree as required.
+	 */
+	for (k = 0; k < le32_to_cpu(tp->dmt_height); k++) {
+		/* get the index of the first leaf of the 4 leaf
+		 * group containing the specified leaf (leafno).
+		 */
+		lp = ((lp - 1) & ~0x03) + 1;
+
+		/* get the index of the parent of this 4 leaf group.
+		 */
+		pp = (lp - 1) >> 2;
+
+		/* determine the maximum of the 4 leaves.
+		 */
+		max = TREEMAX(&tp->dmt_stree[lp]);
+
+		/* if the maximum of the 4 is the same as the
+		 * parent's value, we're done.
+		 */
+		if (tp->dmt_stree[pp] == max)
+			break;
+
+		/* parent gets new value.
+		 */
+		tp->dmt_stree[pp] = max;
+
+		/* parent becomes leaf for next go-round.
+		 */
+		lp = pp;
+	}
+}
+
+
+/*
+ * NAME:	dbFindLeaf()
+ *
+ * FUNCTION:    search a dmtree_t for sufficient free blocks, returning
+ *		the index of a leaf describing the free blocks if 
+ *		sufficient free blocks are found.
+ *
+ *		the search starts at the top of the dmtree_t tree and
+ *		proceeds down the tree to the leftmost leaf with sufficient
+ *		free space.
+ *
+ * PARAMETERS:
+ *      tp	- pointer to the tree to be searched.
+ *      l2nb	- log2 number of free blocks to search for.
+ *	leafidx	- return pointer to be set to the index of the leaf
+ *		  describing at least l2nb free blocks if sufficient
+ *		  free blocks are found.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      ENOSPC	- insufficient free blocks. 
+ */
+static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx)
+{
+	int ti, n = 0, k, x = 0;
+
+	/* first check the root of the tree to see if there is
+	 * sufficient free space.
+	 */
+	if (l2nb > tp->dmt_stree[ROOT])
+		return (ENOSPC);
+
+	/* sufficient free space available. now search down the tree
+	 * starting at the next level for the leftmost leaf that
+	 * describes sufficient free space.
+	 */
+	for (k = le32_to_cpu(tp->dmt_height), ti = 1;
+	     k > 0; k--, ti = ((ti + n) << 2) + 1) {
+		/* search the four nodes at this level, starting from
+		 * the left.
+		 */
+		for (x = ti, n = 0; n < 4; n++) {
+			/* sufficient free space found.  move to the next
+			 * level (or quit if this is the last level).
+			 */
+			if (l2nb <= tp->dmt_stree[x + n])
+				break;
+		}
+
+		/* better have found something since the higher
+		 * levels of the tree said it was here.
+		 */
+		assert(n < 4);
+	}
+
+	/* set the return to the leftmost leaf describing sufficient
+	 * free space.
+	 */
+	*leafidx = x + n - le32_to_cpu(tp->dmt_leafidx);
+
+	return (0);
+}
+
+
+/*
+ * NAME:	dbFindBits()
+ *
+ * FUNCTION:    find a specified number of binary buddy free bits within a
+ *		dmap bitmap word value.
+ *
+ *		this routine searches the bitmap value for (1 << l2nb) free
+ *		bits at (1 << l2nb) alignments within the value.
+ *
+ * PARAMETERS:
+ *      word	-  dmap bitmap word value.
+ *      l2nb	-  number of free bits specified as a log2 number.
+ *
+ * RETURN VALUES:
+ *      starting bit number of free bits.
+ */
+static int dbFindBits(u32 word, int l2nb)
+{
+	int bitno, nb;
+	u32 mask;
+
+	/* get the number of bits.
+	 */
+	nb = 1 << l2nb;
+	assert(nb <= DBWORD);
+
+	/* complement the word so we can use a mask (i.e. 0s represent
+	 * free bits) and compute the mask.
+	 */
+	word = ~word;
+	mask = ONES << (DBWORD - nb);
+
+	/* scan the word for nb free bits at nb alignments.
+	 */
+	for (bitno = 0; mask != 0; bitno += nb, mask >>= nb) {
+		if ((mask & word) == mask)
+			break;
+	}
+
+	ASSERT(bitno < 32);
+
+	/* return the bit number.
+	 */
+	return (bitno);
+}
+
+
+/*
+ * NAME:	dbMaxBud(u8 *cp)
+ *
+ * FUNCTION:    determine the largest binary buddy string of free
+ *		bits within 32-bits of the map.
+ *
+ * PARAMETERS:
+ *      cp	-  pointer to the 32-bit value.
+ *
+ * RETURN VALUES:
+ *      largest binary buddy of free bits within a dmap word.
+ */
+static int dbMaxBud(u8 * cp)
+{
+	signed char tmp1, tmp2;
+
+	/* check if the wmap word is all free. if so, the
+	 * free buddy size is BUDMIN.
+	 */
+	if (*((uint *) cp) == 0)
+		return (BUDMIN);
+
+	/* check if the wmap word is half free. if so, the
+	 * free buddy size is BUDMIN-1.
+	 */
+	if (*((u16 *) cp) == 0 || *((u16 *) cp + 1) == 0)
+		return (BUDMIN - 1);
+
+	/* not all free or half free. determine the free buddy
+	 * size thru table lookup using quarters of the wmap word.
+	 */
+	tmp1 = max(budtab[cp[2]], budtab[cp[3]]);
+	tmp2 = max(budtab[cp[0]], budtab[cp[1]]);
+	return (max(tmp1, tmp2));
+}
+
+
+/*
+ * NAME:	cnttz(uint word)
+ *
+ * FUNCTION:    determine the number of trailing zeros within a 32-bit
+ *		value.
+ *
+ * PARAMETERS:
+ *      value	-  32-bit value to be examined.
+ *
+ * RETURN VALUES:
+ *      count of trailing zeros
+ */
+int cnttz(u32 word)
+{
+	int n;
+
+	for (n = 0; n < 32; n++, word >>= 1) {
+		if (word & 0x01)
+			break;
+	}
+
+	return (n);
+}
+
+
+/*
+ * NAME:	cntlz(u32 value)
+ *
+ * FUNCTION:    determine the number of leading zeros within a 32-bit
+ *		value.
+ *
+ * PARAMETERS:
+ *      value	-  32-bit value to be examined.
+ *
+ * RETURN VALUES:
+ *      count of leading zeros
+ */
+int cntlz(u32 value)
+{
+	int n;
+
+	for (n = 0; n < 32; n++, value <<= 1) {
+		if (value & HIGHORDER)
+			break;
+	}
+	return (n);
+}
+
+
+/*
+ * NAME:	blkstol2(s64 nb)
+ *
+ * FUNCTION:	convert a block count to its log2 value. if the block
+ *	        count is not a l2 multiple, it is rounded up to the next
+ *		larger l2 multiple.
+ *
+ * PARAMETERS:
+ *      nb	-  number of blocks
+ *
+ * RETURN VALUES:
+ *      log2 number of blocks
+ */
+int blkstol2(s64 nb)
+{
+	int l2nb;
+	s64 mask;		/* meant to be signed */
+
+	mask = (s64) 1 << (64 - 1);
+
+	/* count the leading bits.
+	 */
+	for (l2nb = 0; l2nb < 64; l2nb++, mask >>= 1) {
+		/* leading bit found.
+		 */
+		if (nb & mask) {
+			/* determine the l2 value.
+			 */
+			l2nb = (64 - 1) - l2nb;
+
+			/* check if we need to round up.
+			 */
+			if (~mask & nb)
+				l2nb++;
+
+			return (l2nb);
+		}
+	}
+	assert(0);
+	return 0;		/* fix compiler warning */
+}
+
+
+/*
+ * NAME:	fsDirty()
+ *
+ * FUNCTION:    xxx
+ *
+ * PARAMETERS:
+ *      ipmnt	- mount inode
+ *
+ * RETURN VALUES:
+ *      none
+ */
+void fsDirty()
+{
+	printk("fsDirty(): bye-bye\n");
+	assert(0);
+}
+
+
+/*
+ * NAME:    	dbAllocBottomUp()
+ *
+ * FUNCTION:	alloc the specified block range from the working block
+ *		allocation map.
+ *
+ *		the blocks will be alloc from the working map one dmap
+ *		at a time.
+ *
+ * PARAMETERS:
+ *      ip	-  pointer to in-core inode;
+ *      blkno	-  starting block number to be freed.
+ *      nblocks	-  number of blocks to be freed.
+ *
+ * RETURN VALUES:
+ *      0	- success
+ *      EIO	- i/o error
+ */
+int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks)
+{
+	metapage_t *mp;
+	dmap_t *dp;
+	int nb, rc;
+	s64 lblkno, rem;
+	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+	bmap_t *bmp = JFS_SBI(ip->i_sb)->bmap;
+
+	IREAD_LOCK(ipbmap);
+
+	/* block to be allocated better be within the mapsize. */
+	ASSERT(nblocks <= bmp->db_mapsize - blkno);
+
+	/*
+	 * allocate the blocks a dmap at a time.
+	 */
+	mp = NULL;
+	for (rem = nblocks; rem > 0; rem -= nb, blkno += nb) {
+		/* release previous dmap if any */
+		if (mp) {
+			write_metapage(mp);
+		}
+
+		/* get the buffer for the current dmap. */
+		lblkno = BLKTODMAP(blkno, bmp->db_l2nbperpage);
+		mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL) {
+			IREAD_UNLOCK(ipbmap);
+			return (EIO);
+		}
+		dp = (dmap_t *) mp->data;
+
+		/* determine the number of blocks to be allocated from
+		 * this dmap.
+		 */
+		nb = min(rem, BPERDMAP - (blkno & (BPERDMAP - 1)));
+
+		DBFREECK(bmp->db_DBmap, bmp->db_mapsize, blkno, nb);
+
+		/* allocate the blocks. */
+		if ((rc = dbAllocDmapBU(bmp, dp, blkno, nb))) {
+			release_metapage(mp);
+			IREAD_UNLOCK(ipbmap);
+			return (rc);
+		}
+
+		DBALLOC(bmp->db_DBmap, bmp->db_mapsize, blkno, nb);
+	}
+
+	/* write the last buffer. */
+	write_metapage(mp);
+
+	IREAD_UNLOCK(ipbmap);
+
+	return (0);
+}
+
+
+static int dbAllocDmapBU(bmap_t * bmp, dmap_t * dp, s64 blkno, int nblocks)
+{
+	int rc;
+	int dbitno, word, rembits, nb, nwords, wbitno, agno;
+	s8 oldroot, *leaf;
+	dmaptree_t *tp = (dmaptree_t *) & dp->tree;
+
+	/* save the current value of the root (i.e. maximum free string)
+	 * of the dmap tree.
+	 */
+	oldroot = tp->stree[ROOT];
+
+	/* pick up a pointer to the leaves of the dmap tree */
+	leaf = tp->stree + LEAFIND;
+
+	/* determine the bit number and word within the dmap of the
+	 * starting block.
+	 */
+	dbitno = blkno & (BPERDMAP - 1);
+	word = dbitno >> L2DBWORD;
+
+	/* block range better be within the dmap */
+	assert(dbitno + nblocks <= BPERDMAP);
+
+	/* allocate the bits of the dmap's words corresponding to the block
+	 * range. not all bits of the first and last words may be contained
+	 * within the block range.  if this is the case, we'll work against
+	 * those words (i.e. partial first and/or last) on an individual basis
+	 * (a single pass), allocating the bits of interest by hand and
+	 * updating the leaf corresponding to the dmap word. a single pass
+	 * will be used for all dmap words fully contained within the
+	 * specified range.  within this pass, the bits of all fully contained
+	 * dmap words will be marked as free in a single shot and the leaves
+	 * will be updated. a single leaf may describe the free space of
+	 * multiple dmap words, so we may update only a subset of the actual
+	 * leaves corresponding to the dmap words of the block range.
+	 */
+	for (rembits = nblocks; rembits > 0; rembits -= nb, dbitno += nb) {
+		/* determine the bit number within the word and
+		 * the number of bits within the word.
+		 */
+		wbitno = dbitno & (DBWORD - 1);
+		nb = min(rembits, DBWORD - wbitno);
+
+		/* check if only part of a word is to be allocated.
+		 */
+		if (nb < DBWORD) {
+			/* allocate (set to 1) the appropriate bits within
+			 * this dmap word.
+			 */
+			dp->wmap[word] |= cpu_to_le32(ONES << (DBWORD - nb)
+						      >> wbitno);
+
+			word += 1;
+		} else {
+			/* one or more dmap words are fully contained
+			 * within the block range.  determine how many
+			 * words and allocate (set to 1) the bits of these
+			 * words.
+			 */
+			nwords = rembits >> L2DBWORD;
+			memset(&dp->wmap[word], (int) ONES, nwords * 4);
+
+			/* determine how many bits */
+			nb = nwords << L2DBWORD;
+		}
+	}
+
+	/* update the free count for this dmap */
+	dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) - nblocks);
+
+	/* reconstruct summary tree */
+	dbInitDmapTree(dp);
+
+	BMAP_LOCK(bmp);
+
+	/* if this allocation group is completely free,
+	 * update the highest active allocation group number 
+	 * if this allocation group is the new max.
+	 */
+	agno = blkno >> bmp->db_agl2size;
+	if (agno > bmp->db_maxag)
+		bmp->db_maxag = agno;
+
+	/* update the free count for the allocation group and map */
+	bmp->db_agfree[agno] -= nblocks;
+	bmp->db_nfree -= nblocks;
+
+	BMAP_UNLOCK(bmp);
+
+	/* if the root has not changed, done. */
+	if (tp->stree[ROOT] == oldroot)
+		return (0);
+
+	/* root changed. bubble the change up to the dmap control pages.
+	 * if the adjustment of the upper level control pages fails,
+	 * backout the bit allocation (thus making everything consistent).
+	 */
+	if ((rc = dbAdjCtl(bmp, blkno, tp->stree[ROOT], 1, 0)))
+		dbFreeBits(bmp, dp, blkno, nblocks);
+
+	return (rc);
+}
+
+
+/*
+ * NAME:	dbExtendFS()
+ *
+ * FUNCTION:	extend bmap from blkno for nblocks;
+ * 		dbExtendFS() updates bmap ready for dbAllocBottomUp();
+ *
+ * L2
+ *  |
+ *   L1---------------------------------L1
+ *    |                                  |
+ *     L0---------L0---------L0           L0---------L0---------L0
+ *      |          |          |            |          |          |
+ *       d0,...,dn  d0,...,dn  d0,...,dn    d0,...,dn  d0,...,dn  d0,.,dm;
+ * L2L1L0d0,...,dnL0d0,...,dnL0d0,...,dnL1L0d0,...,dnL0d0,...,dnL0d0,..dm
+ *
+ * <---old---><----------------------------extend----------------------->   
+ */
+int dbExtendFS(struct inode *ipbmap, s64 blkno,	s64 nblocks)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ipbmap->i_sb);
+	int nbperpage = sbi->nbperpage;
+	int i, i0 = TRUE, j, j0 = TRUE, k, n;
+	s64 newsize;
+	s64 p;
+	metapage_t *mp, *l2mp, *l1mp, *l0mp;
+	dmapctl_t *l2dcp, *l1dcp, *l0dcp;
+	dmap_t *dp;
+	s8 *l0leaf, *l1leaf, *l2leaf;
+	bmap_t *bmp = sbi->bmap;
+	int agno, l2agsize, oldl2agsize;
+	s64 ag_rem;
+
+	newsize = blkno + nblocks;
+
+	jEVENT(0, ("dbExtendFS: blkno:%Ld nblocks:%Ld newsize:%Ld\n",
+		   (long long) blkno, (long long) nblocks,
+		   (long long) newsize));
+
+	/*
+	 *      initialize bmap control page.
+	 *
+	 * all the data in bmap control page should exclude
+	 * the mkfs hidden dmap page.
+	 */
+
+	/* update mapsize */
+	bmp->db_mapsize = newsize;
+	bmp->db_maxlevel = BMAPSZTOLEV(bmp->db_mapsize);
+
+	/* compute new AG size */
+	l2agsize = dbGetL2AGSize(newsize);
+	oldl2agsize = bmp->db_agl2size;
+
+	bmp->db_agl2size = l2agsize;
+	bmp->db_agsize = 1 << l2agsize;
+
+	/* compute new number of AG */
+	agno = bmp->db_numag;
+	bmp->db_numag = newsize >> l2agsize;
+	bmp->db_numag += ((u32) newsize % (u32) bmp->db_agsize) ? 1 : 0;
+
+	/*
+	 *      reconfigure db_agfree[] 
+	 * from old AG configuration to new AG configuration;
+	 *
+	 * coalesce contiguous k (newAGSize/oldAGSize) AGs;
+	 * i.e., (AGi, ..., AGj) where i = k*n and j = k*(n+1) - 1 to AGn;
+	 * note: new AG size = old AG size * (2**x).
+	 */
+	if (l2agsize == oldl2agsize)
+		goto extend;
+	k = 1 << (l2agsize - oldl2agsize);
+	ag_rem = bmp->db_agfree[0];	/* save agfree[0] */
+	for (i = 0, n = 0; i < agno; n++) {
+		bmp->db_agfree[n] = 0;	/* init collection point */
+
+		/* coalesce cotiguous k AGs; */
+		for (j = 0; j < k && i < agno; j++, i++) {
+			/* merge AGi to AGn */
+			bmp->db_agfree[n] += bmp->db_agfree[i];
+		}
+	}
+	bmp->db_agfree[0] += ag_rem;	/* restore agfree[0] */
+
+	for (; n < MAXAG; n++)
+		bmp->db_agfree[n] = 0;
+
+	/*
+	 * update highest active ag number
+	 */
+
+	bmp->db_maxag = bmp->db_maxag / k;
+
+	/*
+	 *      extend bmap
+	 *
+	 * update bit maps and corresponding level control pages;
+	 * global control page db_nfree, db_agfree[agno], db_maxfreebud;
+	 */
+      extend:
+	/* get L2 page */
+	p = BMAPBLKNO + nbperpage;	/* L2 page */
+	l2mp = read_metapage(ipbmap, p, PSIZE, 0);
+	assert(l2mp);
+	l2dcp = (dmapctl_t *) l2mp->data;
+
+	/* compute start L1 */
+	k = blkno >> L2MAXL1SIZE;
+	l2leaf = l2dcp->stree + CTLLEAFIND + k;
+	p = BLKTOL1(blkno, sbi->l2nbperpage);	/* L1 page */
+
+	/*
+	 * extend each L1 in L2
+	 */
+	for (; k < LPERCTL; k++, p += nbperpage) {
+		/* get L1 page */
+		if (j0) {
+			/* read in L1 page: (blkno & (MAXL1SIZE - 1)) */
+			l1mp = read_metapage(ipbmap, p, PSIZE, 0);
+			if (l1mp == NULL)
+				goto errout;
+			l1dcp = (dmapctl_t *) l1mp->data;
+
+			/* compute start L0 */
+			j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE;
+			l1leaf = l1dcp->stree + CTLLEAFIND + j;
+			p = BLKTOL0(blkno, sbi->l2nbperpage);
+			j0 = FALSE;
+		} else {
+			/* assign/init L1 page */
+			l1mp = get_metapage(ipbmap, p, PSIZE, 0);
+			if (l1mp == NULL)
+				goto errout;
+
+			l1dcp = (dmapctl_t *) l1mp->data;
+
+			/* compute start L0 */
+			j = 0;
+			l1leaf = l1dcp->stree + CTLLEAFIND;
+			p += nbperpage;	/* 1st L0 of L1.k  */
+		}
+
+		/*
+		 * extend each L0 in L1
+		 */
+		for (; j < LPERCTL; j++) {
+			/* get L0 page */
+			if (i0) {
+				/* read in L0 page: (blkno & (MAXL0SIZE - 1)) */
+
+				l0mp = read_metapage(ipbmap, p, PSIZE, 0);
+				if (l0mp == NULL)
+					goto errout;
+				l0dcp = (dmapctl_t *) l0mp->data;
+
+				/* compute start dmap */
+				i = (blkno & (MAXL0SIZE - 1)) >>
+				    L2BPERDMAP;
+				l0leaf = l0dcp->stree + CTLLEAFIND + i;
+				p = BLKTODMAP(blkno,
+					      sbi->l2nbperpage);
+				i0 = FALSE;
+			} else {
+				/* assign/init L0 page */
+				l0mp = get_metapage(ipbmap, p, PSIZE, 0);
+				if (l0mp == NULL)
+					goto errout;
+
+				l0dcp = (dmapctl_t *) l0mp->data;
+
+				/* compute start dmap */
+				i = 0;
+				l0leaf = l0dcp->stree + CTLLEAFIND;
+				p += nbperpage;	/* 1st dmap of L0.j */
+			}
+
+			/*
+			 * extend each dmap in L0
+			 */
+			for (; i < LPERCTL; i++) {
+				/*
+				 * reconstruct the dmap page, and
+				 * initialize corresponding parent L0 leaf
+				 */
+				if ((n = blkno & (BPERDMAP - 1))) {
+					/* read in dmap page: */
+					mp = read_metapage(ipbmap, p,
+							   PSIZE, 0);
+					if (mp == NULL)
+						goto errout;
+					n = min(nblocks, (s64)BPERDMAP - n);
+				} else {
+					/* assign/init dmap page */
+					mp = read_metapage(ipbmap, p,
+							   PSIZE, 0);
+					if (mp == NULL)
+						goto errout;
+
+					n = min(nblocks, (s64)BPERDMAP);
+				}
+
+				dp = (dmap_t *) mp->data;
+				*l0leaf = dbInitDmap(dp, blkno, n);
+
+				bmp->db_nfree += n;
+				agno = le64_to_cpu(dp->start) >> l2agsize;
+				bmp->db_agfree[agno] += n;
+
+				write_metapage(mp);
+
+				l0leaf++;
+				p += nbperpage;
+
+				blkno += n;
+				nblocks -= n;
+				if (nblocks == 0)
+					break;
+			}	/* for each dmap in a L0 */
+
+			/*
+			 * build current L0 page from its leaves, and 
+			 * initialize corresponding parent L1 leaf
+			 */
+			*l1leaf = dbInitDmapCtl(l0dcp, 0, ++i);
+			write_metapage(l0mp);
+
+			if (nblocks)
+				l1leaf++;	/* continue for next L0 */
+			else {
+				/* more than 1 L0 ? */
+				if (j > 0)
+					break;	/* build L1 page */
+				else {
+					/* summarize in global bmap page */
+					bmp->db_maxfreebud = *l1leaf;
+					release_metapage(l1mp);
+					release_metapage(l2mp);
+					goto finalize;
+				}
+			}
+		}		/* for each L0 in a L1 */
+
+		/*
+		 * build current L1 page from its leaves, and 
+		 * initialize corresponding parent L2 leaf
+		 */
+		*l2leaf = dbInitDmapCtl(l1dcp, 1, ++j);
+		write_metapage(l1mp);
+
+		if (nblocks)
+			l2leaf++;	/* continue for next L1 */
+		else {
+			/* more than 1 L1 ? */
+			if (k > 0)
+				break;	/* build L2 page */
+			else {
+				/* summarize in global bmap page */
+				bmp->db_maxfreebud = *l2leaf;
+				release_metapage(l2mp);
+				goto finalize;
+			}
+		}
+	}			/* for each L1 in a L2 */
+
+	assert(0);
+
+	/*
+	 *      finalize bmap control page
+	 */
+      finalize:
+
+	return 0;
+
+      errout:
+	return EIO;
+}
+
+
+/*
+ *	dbFinalizeBmap()
+ */
+void dbFinalizeBmap(struct inode *ipbmap)
+{
+	bmap_t *bmp = JFS_SBI(ipbmap->i_sb)->bmap;
+	int actags, inactags, l2nl;
+	s64 ag_rem, actfree, inactfree, avgfree;
+	int i, n;
+
+	/*
+	 *      finalize bmap control page
+	 */
+//finalize:
+	/* 
+	 * compute db_agpref: preferred ag to allocate from
+	 * (the leftmost ag with average free space in it);
+	 */
+//agpref:
+	/* get the number of active ags and inacitve ags */
+	actags = bmp->db_maxag + 1;
+	inactags = bmp->db_numag - actags;
+	ag_rem = bmp->db_mapsize & (bmp->db_agsize - 1);	/* ??? */
+
+	/* determine how many blocks are in the inactive allocation
+	 * groups. in doing this, we must account for the fact that
+	 * the rightmost group might be a partial group (i.e. file
+	 * system size is not a multiple of the group size).
+	 */
+	inactfree = (inactags && ag_rem) ?
+	    ((inactags - 1) << bmp->db_agl2size) + ag_rem
+	    : inactags << bmp->db_agl2size;
+
+	/* determine how many free blocks are in the active
+	 * allocation groups plus the average number of free blocks
+	 * within the active ags.
+	 */
+	actfree = bmp->db_nfree - inactfree;
+	avgfree = (u32) actfree / (u32) actags;
+
+	/* if the preferred allocation group has not average free space.
+	 * re-establish the preferred group as the leftmost
+	 * group with average free space.
+	 */
+	if (bmp->db_agfree[bmp->db_agpref] < avgfree) {
+		for (bmp->db_agpref = 0; bmp->db_agpref < actags;
+		     bmp->db_agpref++) {
+			if (bmp->db_agfree[bmp->db_agpref] >= avgfree)
+				break;
+		}
+		assert(bmp->db_agpref < bmp->db_numag);
+	}
+
+	/*
+	 * compute db_aglevel, db_agheigth, db_width, db_agstart:
+	 * an ag is covered in aglevel dmapctl summary tree, 
+	 * at agheight level height (from leaf) with agwidth number of nodes 
+	 * each, which starts at agstart index node of the smmary tree node 
+	 * array;
+	 */
+	bmp->db_aglevel = BMAPSZTOLEV(bmp->db_agsize);
+	l2nl =
+	    bmp->db_agl2size - (L2BPERDMAP + bmp->db_aglevel * L2LPERCTL);
+	bmp->db_agheigth = l2nl >> 1;
+	bmp->db_agwidth = 1 << (l2nl - (bmp->db_agheigth << 1));
+	for (i = 5 - bmp->db_agheigth, bmp->db_agstart = 0, n = 1; i > 0;
+	     i--) {
+		bmp->db_agstart += n;
+		n <<= 2;
+	}
+
+/*
+printk("bmap: agpref:%d aglevel:%d agheigth:%d agwidth:%d\n",
+	bmp->db_agpref, bmp->db_aglevel, bmp->db_agheigth, bmp->db_agwidth);
+*/
+}
+
+
+/*
+ * NAME:	dbInitDmap()/ujfs_idmap_page()
+ *                                                                    
+ * FUNCTION:	initialize working/persistent bitmap of the dmap page
+ *		for the specified number of blocks:
+ *                                                                    
+ *		at entry, the bitmaps had been initialized as free (ZEROS);
+ *		The number of blocks will only account for the actually 
+ *		existing blocks. Blocks which don't actually exist in 
+ *		the aggregate will be marked as allocated (ONES);
+ *
+ * PARAMETERS:
+ *	dp	- pointer to page of map
+ *	nblocks	- number of blocks this page
+ *
+ * RETURNS: NONE
+ */
+static int dbInitDmap(dmap_t * dp, s64 Blkno, int nblocks)
+{
+	int blkno, w, b, r, nw, nb, i;
+/*
+printk("sbh_dmap:  in dbInitDmap blkno:%Ld nblocks:%ld\n", Blkno, nblocks); 
+*/
+
+	/* starting block number within the dmap */
+	blkno = Blkno & (BPERDMAP - 1);
+
+	if (blkno == 0) {
+		dp->nblocks = dp->nfree = cpu_to_le32(nblocks);
+		dp->start = cpu_to_le64(Blkno);
+
+		if (nblocks == BPERDMAP) {
+			memset(&dp->wmap[0], 0, LPERDMAP * 4);
+			memset(&dp->pmap[0], 0, LPERDMAP * 4);
+			goto initTree;
+		}
+	} else {
+		dp->nblocks =
+		    cpu_to_le32(le32_to_cpu(dp->nblocks) + nblocks);
+		dp->nfree = cpu_to_le32(le32_to_cpu(dp->nfree) + nblocks);
+	}
+
+	/* word number containing start block number */
+	w = blkno >> L2DBWORD;
+
+	/*
+	 * free the bits corresponding to the block range (ZEROS):
+	 * note: not all bits of the first and last words may be contained 
+	 * within the block range.
+	 */
+	for (r = nblocks; r > 0; r -= nb, blkno += nb) {
+		/* number of bits preceding range to be freed in the word */
+		b = blkno & (DBWORD - 1);
+		/* number of bits to free in the word */
+		nb = min(r, DBWORD - b);
+
+		/* is partial word to be freed ? */
+		if (nb < DBWORD) {
+			/* free (set to 0) from the bitmap word */
+			dp->wmap[w] &= cpu_to_le32(~(ONES << (DBWORD - nb)
+						     >> b));
+			dp->pmap[w] &= cpu_to_le32(~(ONES << (DBWORD - nb)
+						     >> b));
+
+			/* skip the word freed */
+			w++;
+		} else {
+			/* free (set to 0) contiguous bitmap words */
+			nw = r >> L2DBWORD;
+			memset(&dp->wmap[w], 0, nw * 4);
+			memset(&dp->pmap[w], 0, nw * 4);
+
+			/* skip the words freed */
+			nb = nw << L2DBWORD;
+			w += nw;
+		}
+	}
+
+	/*
+	 * mark bits following the range to be freed (non-existing 
+	 * blocks) as allocated (ONES)
+	 */
+/*
+printk("sbh_dmap:  in dbInitDmap, preparing to mark unbacked, blkno:%ld nblocks:%ld\n",
+		blkno, nblocks); 
+*/
+
+	if (blkno == BPERDMAP)
+		goto initTree;
+
+	/* the first word beyond the end of existing blocks */
+	w = blkno >> L2DBWORD;
+
+	/* does nblocks fall on a 32-bit boundary ? */
+	b = blkno & (DBWORD - 1);
+/*
+printk("sbh_dmap:  in dbInitDmap, b:%ld w:%ld mask: %lx\n", b, w, (ONES>>b)); 
+*/
+	if (b) {
+		/* mark a partial word allocated */
+		dp->wmap[w] = dp->pmap[w] = cpu_to_le32(ONES >> b);
+		w++;
+	}
+
+	/* set the rest of the words in the page to allocated (ONES) */
+	for (i = w; i < LPERDMAP; i++)
+		dp->pmap[i] = dp->wmap[i] = ONES;
+
+	/*
+	 * init tree
+	 */
+      initTree:
+	return (dbInitDmapTree(dp));
+}
+
+
+/*
+ * NAME:	dbInitDmapTree()/ujfs_complete_dmap()
+ *                                                                    
+ * FUNCTION:	initialize summary tree of the specified dmap:
+ *
+ *		at entry, bitmap of the dmap has been initialized;
+ *                                                                    
+ * PARAMETERS:
+ *	dp	- dmap to complete
+ *	blkno	- starting block number for this dmap
+ *	treemax	- will be filled in with max free for this dmap
+ *
+ * RETURNS:	max free string at the root of the tree
+ */
+static int dbInitDmapTree(dmap_t * dp)
+{
+	dmaptree_t *tp;
+	s8 *cp;
+	int i;
+
+	/* init fixed info of tree */
+	tp = &dp->tree;
+	tp->nleafs = cpu_to_le32(LPERDMAP);
+	tp->l2nleafs = cpu_to_le32(L2LPERDMAP);
+	tp->leafidx = cpu_to_le32(LEAFIND);
+	tp->height = cpu_to_le32(4);
+	tp->budmin = BUDMIN;
+
+	/* init each leaf from corresponding wmap word:
+	 * note: leaf is set to NOFREE(-1) if all blocks of corresponding
+	 * bitmap word are allocated. 
+	 */
+	cp = tp->stree + le32_to_cpu(tp->leafidx);
+	for (i = 0; i < LPERDMAP; i++)
+		*cp++ = dbMaxBud((u8 *) & dp->wmap[i]);
+
+	/* build the dmap's binary buddy summary tree */
+	return (dbInitTree(tp));
+}
+
+
+/*
+ * NAME:	dbInitTree()/ujfs_adjtree()
+ *                                                                    
+ * FUNCTION:	initialize binary buddy summary tree of a dmap or dmapctl.
+ *
+ *		at entry, the leaves of the tree has been initialized 
+ *		from corresponding bitmap word or root of summary tree
+ *		of the child control page;
+ *		configure binary buddy system at the leaf level, then
+ *		bubble up the values of the leaf nodes up the tree.
+ *
+ * PARAMETERS:
+ *	cp	- Pointer to the root of the tree
+ *	l2leaves- Number of leaf nodes as a power of 2
+ *	l2min	- Number of blocks that can be covered by a leaf
+ *		  as a power of 2
+ *
+ * RETURNS: max free string at the root of the tree
+ */
+static int dbInitTree(dmaptree_t * dtp)
+{
+	int l2max, l2free, bsize, nextb, i;
+	int child, parent, nparent;
+	s8 *tp, *cp, *cp1;
+
+	tp = dtp->stree;
+
+	/* Determine the maximum free string possible for the leaves */
+	l2max = le32_to_cpu(dtp->l2nleafs) + dtp->budmin;
+
+	/*
+	 * configure the leaf levevl into binary buddy system
+	 *
+	 * Try to combine buddies starting with a buddy size of 1 
+	 * (i.e. two leaves). At a buddy size of 1 two buddy leaves 
+	 * can be combined if both buddies have a maximum free of l2min; 
+	 * the combination will result in the left-most buddy leaf having 
+	 * a maximum free of l2min+1.  
+	 * After processing all buddies for a given size, process buddies 
+	 * at the next higher buddy size (i.e. current size * 2) and 
+	 * the next maximum free (current free + 1).  
+	 * This continues until the maximum possible buddy combination 
+	 * yields maximum free.
+	 */
+	for (l2free = dtp->budmin, bsize = 1; l2free < l2max;
+	     l2free++, bsize = nextb) {
+		/* get next buddy size == current buddy pair size */
+		nextb = bsize << 1;
+
+		/* scan each adjacent buddy pair at current buddy size */
+		for (i = 0, cp = tp + le32_to_cpu(dtp->leafidx);
+		     i < le32_to_cpu(dtp->nleafs);
+		     i += nextb, cp += nextb) {
+			/* coalesce if both adjacent buddies are max free */
+			if (*cp == l2free && *(cp + bsize) == l2free) {
+				*cp = l2free + 1;	/* left take right */
+				*(cp + bsize) = -1;	/* right give left */
+			}
+		}
+	}
+
+	/*
+	 * bubble summary information of leaves up the tree.
+	 *
+	 * Starting at the leaf node level, the four nodes described by
+	 * the higher level parent node are compared for a maximum free and 
+	 * this maximum becomes the value of the parent node.  
+	 * when all lower level nodes are processed in this fashion then 
+	 * move up to the next level (parent becomes a lower level node) and 
+	 * continue the process for that level.
+	 */
+	for (child = le32_to_cpu(dtp->leafidx),
+	     nparent = le32_to_cpu(dtp->nleafs) >> 2;
+	     nparent > 0; nparent >>= 2, child = parent) {
+		/* get index of 1st node of parent level */
+		parent = (child - 1) >> 2;
+
+		/* set the value of the parent node as the maximum 
+		 * of the four nodes of the current level.
+		 */
+		for (i = 0, cp = tp + child, cp1 = tp + parent;
+		     i < nparent; i++, cp += 4, cp1++)
+			*cp1 = TREEMAX(cp);
+	}
+
+	return (*tp);
+}
+
+
+/*
+ *	dbInitDmapCtl()
+ *
+ * function: initialize dmapctl page
+ */
+static int dbInitDmapCtl(dmapctl_t * dcp, int level, int i)
+{				/* start leaf index not covered by range */
+	s8 *cp;
+
+	dcp->nleafs = cpu_to_le32(LPERCTL);
+	dcp->l2nleafs = cpu_to_le32(L2LPERCTL);
+	dcp->leafidx = cpu_to_le32(CTLLEAFIND);
+	dcp->height = cpu_to_le32(5);
+	dcp->budmin = L2BPERDMAP + L2LPERCTL * level;
+
+	/*
+	 * initialize the leaves of current level that were not covered 
+	 * by the specified input block range (i.e. the leaves have no 
+	 * low level dmapctl or dmap).
+	 */
+	cp = &dcp->stree[CTLLEAFIND + i];
+	for (; i < LPERCTL; i++)
+		*cp++ = NOFREE;
+
+	/* build the dmap's binary buddy summary tree */
+	return (dbInitTree((dmaptree_t *) dcp));
+}
+
+
+/*
+ * NAME:	dbGetL2AGSize()/ujfs_getagl2size()
+ *                                                                    
+ * FUNCTION:	Determine log2(allocation group size) from aggregate size
+ *                                                                    
+ * PARAMETERS:
+ *	nblocks	- Number of blocks in aggregate
+ *
+ * RETURNS: log2(allocation group size) in aggregate blocks
+ */
+static int dbGetL2AGSize(s64 nblocks)
+{
+	s64 sz;
+	s64 m;
+	int l2sz;
+
+	if (nblocks < BPERDMAP * MAXAG)
+		return (L2BPERDMAP);
+
+	/* round up aggregate size to power of 2 */
+	m = ((u64) 1 << (64 - 1));
+	for (l2sz = 64; l2sz >= 0; l2sz--, m >>= 1) {
+		if (m & nblocks)
+			break;
+	}
+
+	sz = (s64) 1 << l2sz;
+	if (sz < nblocks)
+		l2sz += 1;
+
+	/* agsize = roundupSize/max_number_of_ag */
+	return (l2sz - L2MAXAG);
+}
+
+
+/*
+ * NAME:	dbMapFileSizeToMapSize()
+ *                                                                    
+ * FUNCTION:	compute number of blocks the block allocation map file 
+ *		can cover from the map file size;
+ *
+ * RETURNS:	Number of blocks which can be covered by this block map file;
+ */
+
+/*
+ * maximum number of map pages at each level including control pages
+ */
+#define MAXL0PAGES	(1 + LPERCTL)
+#define MAXL1PAGES	(1 + LPERCTL * MAXL0PAGES)
+#define MAXL2PAGES	(1 + LPERCTL * MAXL1PAGES)
+
+/*
+ * convert number of map pages to the zero origin top dmapctl level
+ */
+#define BMAPPGTOLEV(npages)	\
+	(((npages) <= 3 + MAXL0PAGES) ? 0 \
+       : ((npages) <= 2 + MAXL1PAGES) ? 1 : 2)
+
+s64 dbMapFileSizeToMapSize(struct inode * ipbmap)
+{
+	struct super_block *sb = ipbmap->i_sb;
+	s64 nblocks;
+	s64 npages, ndmaps;
+	int level, i;
+	int complete, factor;
+
+	nblocks = ipbmap->i_size >> JFS_SBI(sb)->l2bsize;
+	npages = nblocks >> JFS_SBI(sb)->l2nbperpage;
+	level = BMAPPGTOLEV(npages);
+
+	/* At each level, accumulate the number of dmap pages covered by 
+	 * the number of full child levels below it;
+	 * repeat for the last incomplete child level.
+	 */
+	ndmaps = 0;
+	npages--;		/* skip the first global control page */
+	/* skip higher level control pages above top level covered by map */
+	npages -= (2 - level);
+	npages--;		/* skip top level's control page */
+	for (i = level; i >= 0; i--) {
+		factor =
+		    (i == 2) ? MAXL1PAGES : ((i == 1) ? MAXL0PAGES : 1);
+		complete = (u32) npages / factor;
+		ndmaps += complete * ((i == 2) ? LPERCTL * LPERCTL
+				      : ((i == 1) ? LPERCTL : 1));
+
+		/* pages in last/incomplete child */
+		npages = (u32) npages % factor;
+		/* skip incomplete child's level control page */
+		npages--;
+	}
+
+	/* convert the number of dmaps into the number of blocks 
+	 * which can be covered by the dmaps;
+	 */
+	nblocks = ndmaps << L2BPERDMAP;
+
+	return (nblocks);
+}
+
+
+#ifdef	_JFS_DEBUG_DMAP
+/*
+ *	DBinitmap()
+ */
+static void DBinitmap(s64 size, struct inode *ipbmap, u32 ** results)
+{
+	int npages;
+	u32 *dbmap, *d;
+	int n;
+	s64 lblkno, cur_block;
+	dmap_t *dp;
+	metapage_t *mp;
+
+	npages = size / 32768;
+	npages += (size % 32768) ? 1 : 0;
+
+	dbmap = (u32 *) xmalloc(npages * 4096, L2PSIZE, kernel_heap);
+	if (dbmap == NULL)
+		assert(0);
+
+	for (n = 0, d = dbmap; n < npages; n++, d += 1024)
+		bzero(d, 4096);
+
+	/* Need to initialize from disk map pages
+	 */
+	for (d = dbmap, cur_block = 0; cur_block < size;
+	     cur_block += BPERDMAP, d += LPERDMAP) {
+		lblkno = BLKTODMAP(cur_block,
+				   JFS_SBI(ipbmap->i_sb)->bmap->
+				   db_l2nbperpage);
+		mp = read_metapage(ipbmap, lblkno, PSIZE, 0);
+		if (mp == NULL) {
+			assert(0);
+		}
+		dp = (dmap_t *) mp->data;
+
+		for (n = 0; n < LPERDMAP; n++)
+			d[n] = le32_to_cpu(dp->wmap[n]);
+
+		release_metapage(mp);
+	}
+
+	*results = dbmap;
+}
+
+
+/*
+ *	DBAlloc()
+ */
+void DBAlloc(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks)
+{
+	int word, nb, bitno;
+	u32 mask;
+
+	assert(blkno > 0 && blkno < mapsize);
+	assert(nblocks > 0 && nblocks <= mapsize);
+
+	assert(blkno + nblocks <= mapsize);
+
+	dbmap += (blkno / 32);
+	while (nblocks > 0) {
+		bitno = blkno & (32 - 1);
+		nb = min(nblocks, 32 - bitno);
+
+		mask = (0xffffffff << (32 - nb) >> bitno);
+		assert((mask & *dbmap) == 0);
+		*dbmap |= mask;
+
+		dbmap++;
+		blkno += nb;
+		nblocks -= nb;
+	}
+}
+
+
+/*
+ *	DBFree()
+ */
+static void DBFree(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks)
+{
+	int word, nb, bitno;
+	u32 mask;
+
+	assert(blkno > 0 && blkno < mapsize);
+	assert(nblocks > 0 && nblocks <= mapsize);
+
+	assert(blkno + nblocks <= mapsize);
+
+	dbmap += (blkno / 32);
+	while (nblocks > 0) {
+		bitno = blkno & (32 - 1);
+		nb = min(nblocks, 32 - bitno);
+
+		mask = (0xffffffff << (32 - nb) >> bitno);
+		assert((mask & *dbmap) == mask);
+		*dbmap &= ~mask;
+
+		dbmap++;
+		blkno += nb;
+		nblocks -= nb;
+	}
+}
+
+
+/*
+ *	DBAllocCK()
+ */
+static void DBAllocCK(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks)
+{
+	int word, nb, bitno;
+	u32 mask;
+
+	assert(blkno > 0 && blkno < mapsize);
+	assert(nblocks > 0 && nblocks <= mapsize);
+
+	assert(blkno + nblocks <= mapsize);
+
+	dbmap += (blkno / 32);
+	while (nblocks > 0) {
+		bitno = blkno & (32 - 1);
+		nb = min(nblocks, 32 - bitno);
+
+		mask = (0xffffffff << (32 - nb) >> bitno);
+		assert((mask & *dbmap) == mask);
+
+		dbmap++;
+		blkno += nb;
+		nblocks -= nb;
+	}
+}
+
+
+/*
+ *	DBFreeCK()
+ */
+static void DBFreeCK(uint * dbmap, s64 mapsize, s64 blkno, s64 nblocks)
+{
+	int word, nb, bitno;
+	u32 mask;
+
+	assert(blkno > 0 && blkno < mapsize);
+	assert(nblocks > 0 && nblocks <= mapsize);
+
+	assert(blkno + nblocks <= mapsize);
+
+	dbmap += (blkno / 32);
+	while (nblocks > 0) {
+		bitno = blkno & (32 - 1);
+		nb = min(nblocks, 32 - bitno);
+
+		mask = (0xffffffff << (32 - nb) >> bitno);
+		assert((mask & *dbmap) == 0);
+
+		dbmap++;
+		blkno += nb;
+		nblocks -= nb;
+	}
+}
+
+
+/*
+ *	dbPrtMap()
+ */
+static void dbPrtMap(bmap_t * bmp)
+{
+	printk("   mapsize:   %d%d\n", bmp->db_mapsize);
+	printk("   nfree:     %d%d\n", bmp->db_nfree);
+	printk("   numag:     %d\n", bmp->db_numag);
+	printk("   agsize:    %d%d\n", bmp->db_agsize);
+	printk("   agl2size:  %d\n", bmp->db_agl2size);
+	printk("   agwidth:   %d\n", bmp->db_agwidth);
+	printk("   agstart:   %d\n", bmp->db_agstart);
+	printk("   agheigth:  %d\n", bmp->db_agheigth);
+	printk("   aglevel:   %d\n", bmp->db_aglevel);
+	printk("   maxlevel:  %d\n", bmp->db_maxlevel);
+	printk("   maxag:     %d\n", bmp->db_maxag);
+	printk("   agpref:    %d\n", bmp->db_agpref);
+	printk("   l2nbppg:   %d\n", bmp->db_l2nbperpage);
+}
+
+
+/*
+ *	dbPrtCtl()
+ */
+static void dbPrtCtl(dmapctl_t * dcp)
+{
+	int i, j, n;
+
+	printk("   height:    %08x\n", le32_to_cpu(dcp->height));
+	printk("   leafidx:   %08x\n", le32_to_cpu(dcp->leafidx));
+	printk("   budmin:    %08x\n", dcp->budmin);
+	printk("   nleafs:    %08x\n", le32_to_cpu(dcp->nleafs));
+	printk("   l2nleafs:  %08x\n", le32_to_cpu(dcp->l2nleafs));
+
+	printk("\n Tree:\n");
+	for (i = 0; i < CTLLEAFIND; i += 8) {
+		n = min(8, CTLLEAFIND - i);
+
+		for (j = 0; j < n; j++)
+			printf("  [%03x]: %02x", i + j,
+			       (char) dcp->stree[i + j]);
+		printf("\n");
+	}
+
+	printk("\n Tree Leaves:\n");
+	for (i = 0; i < LPERCTL; i += 8) {
+		n = min(8, LPERCTL - i);
+
+		for (j = 0; j < n; j++)
+			printf("  [%03x]: %02x",
+			       i + j,
+			       (char) dcp->stree[i + j + CTLLEAFIND]);
+		printf("\n");
+	}
+}
+#endif				/* _JFS_DEBUG_DMAP */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_dmap.h linux-2.5.6-pre2/fs/jfs/jfs_dmap.h
--- linux-2.5.6-pre1/fs/jfs/jfs_dmap.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_dmap.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,301 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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
+ *
+ *	jfs_dmap.h: block allocation map manager
+ */
+
+#ifndef	_H_JFS_DMAP
+#define _H_JFS_DMAP
+
+#include "jfs_txnmgr.h"
+
+#define BMAPVERSION	1	/* version number */
+#define	TREESIZE	(256+64+16+4+1)	/* size of a dmap tree */
+#define	LEAFIND		(64+16+4+1)	/* index of 1st leaf of a dmap tree */
+#define LPERDMAP	256	/* num leaves per dmap tree */
+#define L2LPERDMAP	8	/* l2 number of leaves per dmap tree */
+#define	DBWORD		32	/* # of blks covered by a map word */
+#define	L2DBWORD	5	/* l2 # of blks covered by a mword */
+#define BUDMIN  	L2DBWORD	/* max free string in a map word */
+#define BPERDMAP	(LPERDMAP * DBWORD)	/* num of blks per dmap */
+#define L2BPERDMAP	13	/* l2 num of blks per dmap */
+#define CTLTREESIZE	(1024+256+64+16+4+1)	/* size of a dmapctl tree */
+#define CTLLEAFIND	(256+64+16+4+1)	/* idx of 1st leaf of a dmapctl tree */
+#define LPERCTL		1024	/* num of leaves per dmapctl tree */
+#define L2LPERCTL	10	/* l2 num of leaves per dmapctl tree */
+#define	ROOT		0	/* index of the root of a tree */
+#define	NOFREE		((s8) -1)	/* no blocks free */
+#define	MAXAG		128	/* max number of allocation groups */
+#define L2MAXAG		7	/* l2 max num of AG */
+#define L2MINAGSZ	25	/* l2 of minimum AG size in bytes */
+#define	BMAPBLKNO	0	/* lblkno of bmap within the map */
+
+/*
+ * maximum l2 number of disk blocks at the various dmapctl levels.
+ */
+#define	L2MAXL0SIZE	(L2BPERDMAP + 1 * L2LPERCTL)
+#define	L2MAXL1SIZE	(L2BPERDMAP + 2 * L2LPERCTL)
+#define	L2MAXL2SIZE	(L2BPERDMAP + 3 * L2LPERCTL)
+
+/*
+ * maximum number of disk blocks at the various dmapctl levels.
+ */
+#define	MAXL0SIZE	((s64)1 << L2MAXL0SIZE)
+#define	MAXL1SIZE	((s64)1 << L2MAXL1SIZE)
+#define	MAXL2SIZE	((s64)1 << L2MAXL2SIZE)
+
+#define	MAXMAPSIZE	MAXL2SIZE	/* maximum aggregate map size */
+
+/* 
+ * determine the maximum free string for four (lower level) nodes
+ * of the tree.
+ */
+static __inline signed char TREEMAX(signed char *cp)
+{
+	signed char tmp1, tmp2;
+
+	tmp1 = max(*(cp+2), *(cp+3));
+	tmp2 = max(*(cp), *(cp+1));
+
+	return max(tmp1, tmp2);
+}
+
+/*
+ * convert disk block number to the logical block number of the dmap
+ * describing the disk block.  s is the log2(number of logical blocks per page)
+ *
+ * The calculation figures out how many logical pages are in front of the dmap.
+ *	- the number of dmaps preceding it
+ *	- the number of L0 pages preceding its L0 page
+ *	- the number of L1 pages preceding its L1 page
+ *	- 3 is added to account for the L2, L1, and L0 page for this dmap
+ *	- 1 is added to account for the control page of the map.
+ */
+#define BLKTODMAP(b,s)    \
+        ((((b) >> 13) + ((b) >> 23) + ((b) >> 33) + 3 + 1) << (s))
+
+/*
+ * convert disk block number to the logical block number of the LEVEL 0
+ * dmapctl describing the disk block.  s is the log2(number of logical blocks
+ * per page)
+ *
+ * The calculation figures out how many logical pages are in front of the L0.
+ *	- the number of dmap pages preceding it
+ *	- the number of L0 pages preceding it
+ *	- the number of L1 pages preceding its L1 page
+ *	- 2 is added to account for the L2, and L1 page for this L0
+ *	- 1 is added to account for the control page of the map.
+ */
+#define BLKTOL0(b,s)      \
+        (((((b) >> 23) << 10) + ((b) >> 23) + ((b) >> 33) + 2 + 1) << (s))
+
+/*
+ * convert disk block number to the logical block number of the LEVEL 1
+ * dmapctl describing the disk block.  s is the log2(number of logical blocks
+ * per page)
+ *
+ * The calculation figures out how many logical pages are in front of the L1.
+ *	- the number of dmap pages preceding it
+ *	- the number of L0 pages preceding it
+ *	- the number of L1 pages preceding it
+ *	- 1 is added to account for the L2 page
+ *	- 1 is added to account for the control page of the map.
+ */
+#define BLKTOL1(b,s)      \
+     (((((b) >> 33) << 20) + (((b) >> 33) << 10) + ((b) >> 33) + 1 + 1) << (s))
+
+/*
+ * convert disk block number to the logical block number of the dmapctl
+ * at the specified level which describes the disk block.
+ */
+#define BLKTOCTL(b,s,l)   \
+        (((l) == 2) ? 1 : ((l) == 1) ? BLKTOL1((b),(s)) : BLKTOL0((b),(s)))
+
+/* 
+ * convert aggregate map size to the zero origin dmapctl level of the
+ * top dmapctl.
+ */
+#define	BMAPSZTOLEV(size)	\
+	(((size) <= MAXL0SIZE) ? 0 : ((size) <= MAXL1SIZE) ? 1 : 2)
+
+/* convert disk block number to allocation group number.
+ */
+#define BLKTOAG(b,sbi)	((b) >> ((sbi)->bmap->db_agl2size))
+
+/* convert allocation group number to starting disk block
+ * number.
+ */
+#define AGTOBLK(a,ip)	\
+	((s64)(a) << (JFS_SBI((ip)->i_sb)->bmap->db_agl2size))
+
+/*
+ *	dmap summary tree
+ *
+ * dmaptree_t must be consistent with dmapctl_t.
+ */
+typedef struct {
+	s32 nleafs;		/* 4: number of tree leafs      */
+	s32 l2nleafs;		/* 4: l2 number of tree leafs   */
+	s32 leafidx;		/* 4: index of first tree leaf  */
+	s32 height;		/* 4: height of the tree        */
+	s8 budmin;		/* 1: min l2 tree leaf value to combine */
+	s8 stree[TREESIZE];	/* TREESIZE: tree               */
+	u8 pad[2];		/* 2: pad to word boundary      */
+} dmaptree_t;			/* - 360 -                      */
+
+/*
+ *	dmap page per 8K blocks bitmap
+ */
+typedef struct {
+	s32 nblocks;		/* 4: num blks covered by this dmap     */
+	s32 nfree;		/* 4: num of free blks in this dmap     */
+	s64 start;		/* 8: starting blkno for this dmap      */
+	dmaptree_t tree;	/* 360: dmap tree                       */
+	u8 pad[1672];		/* 1672: pad to 2048 bytes              */
+	u32 wmap[LPERDMAP];	/* 1024: bits of the working map        */
+	u32 pmap[LPERDMAP];	/* 1024: bits of the persistent map     */
+} dmap_t;			/* - 4096 -                             */
+
+/*
+ *	disk map control page per level.
+ *
+ * dmapctl_t must be consistent with dmaptree_t.
+ */
+typedef struct {
+	s32 nleafs;		/* 4: number of tree leafs      */
+	s32 l2nleafs;		/* 4: l2 number of tree leafs   */
+	s32 leafidx;		/* 4: index of the first tree leaf      */
+	s32 height;		/* 4: height of tree            */
+	s8 budmin;		/* 1: minimum l2 tree leaf value        */
+	s8 stree[CTLTREESIZE];	/* CTLTREESIZE: dmapctl tree    */
+	u8 pad[2714];		/* 2714: pad to 4096            */
+} dmapctl_t;			/* - 4096 -                     */
+
+/*
+ *	common definition for dmaptree_t within dmap and dmapctl
+ */
+typedef union {
+	dmaptree_t t1;
+	dmapctl_t t2;
+} dmtree_t;
+
+/* macros for accessing fields within dmtree_t */
+#define	dmt_nleafs	t1.nleafs
+#define	dmt_l2nleafs 	t1.l2nleafs
+#define	dmt_leafidx 	t1.leafidx
+#define	dmt_height 	t1.height
+#define	dmt_budmin 	t1.budmin
+#define	dmt_stree 	t1.stree
+
+/* 
+ *	on-disk aggregate disk allocation map descriptor.
+ */
+typedef struct {
+	s64 dn_mapsize;		/* 8: number of blocks in aggregate     */
+	s64 dn_nfree;		/* 8: num free blks in aggregate map    */
+	s32 dn_l2nbperpage;	/* 4: number of blks per page           */
+	s32 dn_numag;		/* 4: total number of ags               */
+	s32 dn_maxlevel;	/* 4: number of active ags              */
+	s32 dn_maxag;		/* 4: max active alloc group number     */
+	s32 dn_agpref;		/* 4: preferred alloc group (hint)      */
+	s32 dn_aglevel;		/* 4: dmapctl level holding the AG      */
+	s32 dn_agheigth;	/* 4: height in dmapctl of the AG       */
+	s32 dn_agwidth;		/* 4: width in dmapctl of the AG        */
+	s32 dn_agstart;		/* 4: start tree index at AG height     */
+	s32 dn_agl2size;	/* 4: l2 num of blks per alloc group    */
+	s64 dn_agfree[MAXAG];	/* 8*MAXAG: per AG free count           */
+	s64 dn_agsize;		/* 8: num of blks per alloc group       */
+	s8 dn_maxfreebud;	/* 1: max free buddy system             */
+	u8 pad[3007];		/* 3007: pad to 4096                    */
+} dbmap_t;			/* - 4096 -                             */
+
+/* 
+ *	in-memory aggregate disk allocation map descriptor.
+ */
+typedef struct bmap {
+	dbmap_t db_bmap;	/* on-disk aggregate map descriptor */
+	struct inode *db_ipbmap;	/* ptr to aggregate map incore inode */
+	struct semaphore db_bmaplock;	/* aggregate map lock */
+	u32 *db_DBmap;
+} bmap_t;
+
+/* macros for accessing fields within in-memory aggregate map descriptor */
+#define	db_mapsize	db_bmap.dn_mapsize
+#define	db_nfree	db_bmap.dn_nfree
+#define	db_agfree	db_bmap.dn_agfree
+#define	db_agsize	db_bmap.dn_agsize
+#define	db_agl2size	db_bmap.dn_agl2size
+#define	db_agwidth	db_bmap.dn_agwidth
+#define	db_agheigth	db_bmap.dn_agheigth
+#define	db_agstart	db_bmap.dn_agstart
+#define	db_numag	db_bmap.dn_numag
+#define	db_maxlevel	db_bmap.dn_maxlevel
+#define	db_aglevel	db_bmap.dn_aglevel
+#define	db_agpref	db_bmap.dn_agpref
+#define	db_maxag	db_bmap.dn_maxag
+#define	db_maxfreebud	db_bmap.dn_maxfreebud
+#define	db_l2nbperpage	db_bmap.dn_l2nbperpage
+
+/*
+ * macros for various conversions needed by the allocators.
+ * blkstol2(), cntlz(), and cnttz() are operating system dependent functions.
+ */
+/* convert number of blocks to log2 number of blocks, rounding up to
+ * the next log2 value if blocks is not a l2 multiple.
+ */
+#define	BLKSTOL2(d)		(blkstol2(d))
+
+/* convert number of leafs to log2 leaf value */
+#define	NLSTOL2BSZ(n)		(31 - cntlz((n)) + BUDMIN)
+
+/* convert leaf index to log2 leaf value */
+#define	LITOL2BSZ(n,m,b)	((((n) == 0) ? (m) : cnttz((n))) + (b))
+
+/* convert a block number to a dmap control leaf index */
+#define BLKTOCTLLEAF(b,m)	\
+	(((b) & (((s64)1 << ((m) + L2LPERCTL)) - 1)) >> (m))
+
+/* convert log2 leaf value to buddy size */
+#define	BUDSIZE(s,m)		(1 << ((s) - (m)))
+
+/*
+ *	external references.
+ */
+extern int dbMount(struct inode *ipbmap);
+
+extern int dbUnmount(struct inode *ipbmap, int mounterror);
+
+extern int dbFree(struct inode *ipbmap, s64 blkno, s64 nblocks);
+
+extern int dbUpdatePMap(struct inode *ipbmap,
+			int free, s64 blkno, s64 nblocks, tblock_t * tblk);
+
+extern int dbNextAG(struct inode *ipbmap);
+
+extern int dbAlloc(struct inode *ipbmap, s64 hint, s64 nblocks, s64 * results);
+
+extern int dbAllocExact(struct inode *ip, s64 blkno, int nblocks);
+
+extern int dbReAlloc(struct inode *ipbmap,
+		     s64 blkno, s64 nblocks, s64 addnblocks, s64 * results);
+
+extern int dbSync(struct inode *ipbmap);
+extern int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks);
+extern int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks);
+extern void dbFinalizeBmap(struct inode *ipbmap);
+extern s64 dbMapFileSizeToMapSize(struct inode *ipbmap);
+#endif				/* _H_JFS_DMAP */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_dtree.c linux-2.5.6-pre2/fs/jfs/jfs_dtree.c
--- linux-2.5.6-pre1/fs/jfs/jfs_dtree.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_dtree.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,4539 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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
+ *
+ * 
+*/
+
+/*
+ *	jfs_dtree.c: directory B+-tree manager
+ *
+ * B+-tree with variable length key directory:
+ *
+ * each directory page is structured as an array of 32-byte
+ * directory entry slots initialized as a freelist
+ * to avoid search/compaction of free space at insertion.
+ * when an entry is inserted, a number of slots are allocated
+ * from the freelist as required to store variable length data
+ * of the entry; when the entry is deleted, slots of the entry
+ * are returned to freelist.
+ *
+ * leaf entry stores full name as key and file serial number
+ * (aka inode number) as data.
+ * internal/router entry stores sufffix compressed name
+ * as key and simple extent descriptor as data.
+ *
+ * each directory page maintains a sorted entry index table
+ * which stores the start slot index of sorted entries
+ * to allow binary search on the table.
+ *
+ * directory starts as a root/leaf page in on-disk inode
+ * inline data area.
+ * when it becomes full, it starts a leaf of a external extent
+ * of length of 1 block. each time the first leaf becomes full,
+ * it is extended rather than split (its size is doubled),
+ * until its length becoms 4 KBytes, from then the extent is split
+ * with new 4 Kbyte extent when it becomes full
+ * to reduce external fragmentation of small directories.
+ *
+ * blah, blah, blah, for linear scan of directory in pieces by
+ * readdir().
+ *
+ *
+ *	case-insensitive directory file system
+ *
+ * names are stored in case-sensitive way in leaf entry.
+ * but stored, searched and compared in case-insensitive (uppercase) order
+ * (i.e., both search key and entry key are folded for search/compare):
+ * (note that case-sensitive order is BROKEN in storage, e.g.,
+ *  sensitive: Ad, aB, aC, aD -> insensitive: aB, aC, aD, Ad
+ *
+ *  entries which folds to the same key makes up a equivalent class
+ *  whose members are stored as contiguous cluster (may cross page boundary)
+ *  but whose order is arbitrary and acts as duplicate, e.g.,
+ *  abc, Abc, aBc, abC)
+ *
+ * once match is found at leaf, requires scan forward/backward
+ * either for, in case-insensitive search, duplicate
+ * or for, in case-sensitive search, for exact match
+ *
+ * router entry must be created/stored in case-insensitive way
+ * in internal entry:
+ * (right most key of left page and left most key of right page
+ * are folded, and its suffix compression is propagated as router
+ * key in parent)
+ * (e.g., if split occurs <abc> and <aBd>, <ABD> trather than <aB>
+ * should be made the router key for the split)
+ *
+ * case-insensitive search:
+ *
+ * 	fold search key;
+ *
+ *	case-insensitive search of B-tree:
+ *	for internal entry, router key is already folded;
+ *	for leaf entry, fold the entry key before comparison.
+ *
+ *	if (leaf entry case-insensitive match found)
+ *		if (next entry satisfies case-insensitive match)
+ *			return EDUPLICATE;
+ *		if (prev entry satisfies case-insensitive match)
+ *			return EDUPLICATE;
+ *		return match;
+ *	else
+ *		return no match;
+ *
+ * 	serialization:
+ * target directory inode lock is being held on entry/exit
+ * of all main directory service routines.
+ *
+ *	log based recovery:
+ */
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/locks.h>
+#include "jfs_incore.h"
+#include "jfs_superblock.h"
+#include "jfs_filsys.h"
+#include "jfs_metapage.h"
+#include "jfs_dmap.h"
+#include "jfs_unicode.h"
+#include "jfs_debug.h"
+
+/* dtree split parameter */
+typedef struct {
+	metapage_t *mp;
+	s16 index;
+	s16 nslot;
+	component_t *key;
+	ddata_t *data;
+	pxdlist_t *pxdlist;
+} dtsplit_t;
+
+#define DT_PAGE(IP, MP) BT_PAGE(IP, MP, dtpage_t, i_dtroot)
+
+/* get page buffer for specified block address */
+#define DT_GETPAGE(IP, BN, MP, SIZE, P, RC)\
+{\
+	BT_GETPAGE(IP, BN, MP, dtpage_t, SIZE, P, RC, i_dtroot)\
+	if (!(RC))\
+	{\
+		if (((P)->header.nextindex > (((BN)==0)?DTROOTMAXSLOT:(P)->header.maxslot)) ||\
+		    ((BN) && ((P)->header.maxslot > DTPAGEMAXSLOT)))\
+		{\
+			jERROR(1,("DT_GETPAGE: dtree page corrupt\n"));\
+			BT_PUTPAGE(MP);\
+			updateSuper((IP)->i_sb, FM_DIRTY);\
+			MP = NULL;\
+			RC = EIO;\
+		}\
+	}\
+}
+
+/* for consistency */
+#define DT_PUTPAGE(MP) BT_PUTPAGE(MP)
+
+#define DT_GETSEARCH(IP, LEAF, BN, MP, P, INDEX) \
+	BT_GETSEARCH(IP, LEAF, BN, MP, dtpage_t, P, INDEX, i_dtroot)
+
+/*
+ * forward references
+ */
+static int dtSplitUp(tid_t tid, struct inode *ip,
+		     dtsplit_t * split, btstack_t * btstack);
+
+static int dtSplitPage(tid_t tid, struct inode *ip, dtsplit_t * split,
+		       metapage_t ** rmpp, dtpage_t ** rpp, pxd_t * rxdp);
+
+static int dtExtendPage(tid_t tid, struct inode *ip,
+			dtsplit_t * split, btstack_t * btstack);
+
+static int dtSplitRoot(tid_t tid, struct inode *ip,
+		       dtsplit_t * split, metapage_t ** rmpp);
+
+static int dtDeleteUp(tid_t tid, struct inode *ip, metapage_t * fmp,
+		      dtpage_t * fp, btstack_t * btstack);
+
+static int dtSearchNode(struct inode *ip,
+			s64 lmxaddr, pxd_t * kpxd, btstack_t * btstack);
+
+static int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p);
+
+static int dtReadFirst(struct inode *ip, btstack_t * btstack);
+
+static int dtReadNext(struct inode *ip,
+		      loff_t * offset, btstack_t * btstack);
+
+static int dtCompare(component_t * key, dtpage_t * p, int si);
+
+static int ciCompare(component_t * key, dtpage_t * p, int si, int flag);
+
+static void dtGetKey(dtpage_t * p, int i, component_t * key, int flag);
+
+static void ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
+			       int ri, component_t * key, int flag);
+
+static void dtInsertEntry(dtpage_t * p, int index, component_t * key,
+			  ddata_t * data, dtlock_t ** dtlock);
+
+static void dtMoveEntry(dtpage_t * sp, int si, dtpage_t * dp,
+			dtlock_t ** sdtlock, dtlock_t ** ddtlock,
+			int do_index);
+
+static void dtDeleteEntry(dtpage_t * p, int fi, dtlock_t ** dtlock);
+
+static void dtTruncateEntry(dtpage_t * p, int ti, dtlock_t ** dtlock);
+
+static void dtLinelockFreelist(dtpage_t * p, int m, dtlock_t ** dtlock);
+
+#define ciToUpper(c)	UniStrupr((c)->name)
+
+/*
+ *	find_index()
+ *
+ *	Returns dtree page containing directory table entry for specified
+ *	index and pointer to its entry.
+ *
+ *	mp must be released by caller.
+ */
+static dir_table_slot_t *find_index(struct inode *ip, u32 index,
+				    metapage_t ** mp)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	s64 blkno;
+	s64 offset;
+	int page_offset;
+	dir_table_slot_t *slot;
+	static int maxWarnings = 10;
+
+	if (index < 2) {
+		if (maxWarnings) {
+			jERROR(1, ("find_entry called with index = %d\n",
+				   index));
+			maxWarnings--;
+		}
+		return 0;
+	}
+
+	if (index >= jfs_ip->next_index) {
+		jFYI(1, ("find_entry called with index >= next_index\n"));
+		return 0;
+	}
+
+	if (jfs_ip->next_index <= (MAX_INLINE_DIRTABLE_ENTRY + 1)) {
+		/*
+		 * Inline directory table
+		 */
+		*mp = 0;
+		slot = &jfs_ip->i_dirtable[index - 2];
+	} else {
+		offset = (index - 2) * sizeof(dir_table_slot_t);
+		page_offset = offset & (PSIZE - 1);
+		blkno = ((offset + 1) >> L2PSIZE) <<
+		    JFS_SBI(ip->i_sb)->l2nbperpage;
+
+		if (*mp && ((*mp)->index != blkno)) {
+			release_metapage(*mp);
+			*mp = 0;
+		}
+		if (*mp == 0)
+			*mp = read_metapage(ip, blkno, PSIZE, 0);
+		if (*mp == 0) {
+			jERROR(1,
+			       ("free_index: error reading directory table\n"));
+			return 0;
+		}
+
+		slot =
+		    (dir_table_slot_t *) ((char *) (*mp)->data +
+					  page_offset);
+	}
+	return slot;
+}
+
+static inline void lock_index(tid_t tid, struct inode *ip, metapage_t * mp,
+			      u32 index)
+{
+	tlock_t *tlck;
+	linelock_t *llck;
+	lv_t *lv;
+
+	tlck = txLock(tid, ip, mp, tlckDATA);
+	llck = (linelock_t *) tlck->lock;
+
+	if (llck->index >= llck->maxcnt)
+		llck = txLinelock(llck);
+	lv = &llck->lv[llck->index];
+
+	/*
+	 *      Linelock slot size is twice the size of directory table
+	 *      slot size.  512 entries per page.
+	 */
+	lv->offset = ((index - 2) & 511) >> 1;
+	lv->length = 1;
+	llck->index++;
+}
+
+/*
+ *	add_index()
+ *
+ *	Adds an entry to the directory index table.  This is used to provide
+ *	each directory entry with a persistent index in which to resume
+ *	directory traversals
+ */
+static u32 add_index(tid_t tid, struct inode *ip, s64 bn, int slot)
+{
+	struct super_block *sb = ip->i_sb;
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	u64 blkno;
+	dir_table_slot_t *dirtab_slot;
+	u32 index;
+	linelock_t *llck;
+	lv_t *lv;
+	metapage_t *mp;
+	s64 offset;
+	uint page_offset;
+	int rc;
+	tlock_t *tlck;
+	s64 xaddr;
+
+	ASSERT(DO_INDEX(ip));
+
+	if (jfs_ip->next_index < 2) {
+		jERROR(1, ("next_index = %d.  Please fix this!\n",
+			   jfs_ip->next_index));
+		jfs_ip->next_index = 2;
+	}
+
+	index = jfs_ip->next_index++;
+
+	if (index <= MAX_INLINE_DIRTABLE_ENTRY) {
+		/*
+		 * i_size reflects size of index table, or 8 bytes per entry.
+		 */
+		ip->i_size = (loff_t) (index - 1) << 3;
+
+		/*
+		 * dir table fits inline within inode
+		 */
+		dirtab_slot = &jfs_ip->i_dirtable[index-2];
+		dirtab_slot->flag = DIR_INDEX_VALID;
+		dirtab_slot->slot = slot;
+		DTSaddress(dirtab_slot, bn);
+
+		set_cflag(COMMIT_Dirtable, ip);
+
+		return index;
+	}
+	if (index == (MAX_INLINE_DIRTABLE_ENTRY + 1)) {
+		/*
+		 * It's time to move the inline table to an external
+		 * page and begin to build the xtree
+		 */
+
+		/*
+		 * Save the table, we're going to overwrite it with the
+		 * xtree root
+		 */
+		dir_table_slot_t temp_table[12];
+		memcpy(temp_table, &jfs_ip->i_dirtable, sizeof(temp_table));
+
+		/*
+		 * Initialize empty x-tree
+		 */
+		xtInitRoot(tid, ip);
+
+		/*
+		 * Allocate the first block & add it to the xtree
+		 */
+		xaddr = 0;
+		if ((rc =
+		     xtInsert(tid, ip, 0, 0, sbi->nbperpage,
+			      &xaddr, 0))) {
+			jFYI(1, ("add_index: xtInsert failed!\n"));
+			return -1;
+		}
+		ip->i_size = PSIZE;
+		ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage);
+
+		if ((mp = get_metapage(ip, 0, ip->i_blksize, 0)) == 0) {
+			jERROR(1, ("add_index: get_metapage failed!\n"));
+			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
+			return -1;
+		}
+		tlck = txLock(tid, ip, mp, tlckDATA);
+		llck = (linelock_t *) & tlck->lock;
+		ASSERT(llck->index == 0);
+		lv = &llck->lv[0];
+
+		lv->offset = 0;
+		lv->length = 6;	/* tlckDATA slot size is 16 bytes */
+		llck->index++;
+
+		memcpy(mp->data, temp_table, sizeof(temp_table));
+
+		mark_metapage_dirty(mp);
+		release_metapage(mp);
+
+		/*
+		 * Logging is now directed by xtree tlocks
+		 */
+		clear_cflag(COMMIT_Dirtable, ip);
+	}
+
+	offset = (index - 2) * sizeof(dir_table_slot_t);
+	page_offset = offset & (PSIZE - 1);
+	blkno = ((offset + 1) >> L2PSIZE) << sbi->l2nbperpage;
+	if (page_offset == 0) {
+		/*
+		 * This will be the beginning of a new page
+		 */
+		xaddr = 0;
+		if ((rc =
+		     xtInsert(tid, ip, 0, blkno, sbi->nbperpage,
+			      &xaddr, 0))) {
+			jFYI(1, ("add_index: xtInsert failed!\n"));
+			jfs_ip->next_index--;
+			return -1;
+		}
+		ip->i_size += PSIZE;
+		ip->i_blocks += LBLK2PBLK(sb, sbi->nbperpage);
+
+		if ((mp = get_metapage(ip, blkno, PSIZE, 0)))
+			memset(mp->data, 0, PSIZE);	/* Just looks better */
+		else
+			xtTruncate(tid, ip, offset, COMMIT_PWMAP);
+	} else
+		mp = read_metapage(ip, blkno, PSIZE, 0);
+
+	if (mp == 0) {
+		jERROR(1, ("add_index: get/read_metapage failed!\n"));
+		return -1;
+	}
+
+	lock_index(tid, ip, mp, index);
+
+	dirtab_slot =
+	    (dir_table_slot_t *) ((char *) mp->data + page_offset);
+	dirtab_slot->flag = DIR_INDEX_VALID;
+	dirtab_slot->slot = slot;
+	DTSaddress(dirtab_slot, bn);
+
+	mark_metapage_dirty(mp);
+	release_metapage(mp);
+
+	return index;
+}
+
+/*
+ *	free_index()
+ *
+ *	Marks an entry to the directory index table as free.
+ */
+static void free_index(tid_t tid, struct inode *ip, u32 index, u32 next)
+{
+	dir_table_slot_t *dirtab_slot;
+	metapage_t *mp = 0;
+
+	dirtab_slot = find_index(ip, index, &mp);
+
+	if (dirtab_slot == 0)
+		return;
+
+	dirtab_slot->flag = DIR_INDEX_FREE;
+	dirtab_slot->slot = dirtab_slot->addr1 = 0;
+	dirtab_slot->addr2 = cpu_to_le32(next);
+
+	if (mp) {
+		lock_index(tid, ip, mp, index);
+		mark_metapage_dirty(mp);
+		release_metapage(mp);
+	} else
+		set_cflag(COMMIT_Dirtable, ip);
+}
+
+/*
+ *	modify_index()
+ *
+ *	Changes an entry in the directory index table
+ */
+static void modify_index(tid_t tid, struct inode *ip, u32 index, s64 bn,
+			 int slot, metapage_t ** mp)
+{
+	dir_table_slot_t *dirtab_slot;
+
+	dirtab_slot = find_index(ip, index, mp);
+
+	if (dirtab_slot == 0)
+		return;
+
+	DTSaddress(dirtab_slot, bn);
+	dirtab_slot->slot = slot;
+
+	if (*mp) {
+		lock_index(tid, ip, *mp, index);
+		mark_metapage_dirty(*mp);
+	} else
+		set_cflag(COMMIT_Dirtable, ip);
+}
+
+/*
+ *	get_index()
+ *
+ *	reads a directory table slot
+ */
+static int get_index(struct inode *ip, u32 index,
+		     dir_table_slot_t * dirtab_slot)
+{
+	metapage_t *mp = 0;
+	dir_table_slot_t *slot;
+
+	slot = find_index(ip, index, &mp);
+	if (slot == 0) {
+		return -EIO;
+	}
+
+	memcpy(dirtab_slot, slot, sizeof(dir_table_slot_t));
+
+	if (mp)
+		release_metapage(mp);
+
+	return 0;
+}
+
+/*
+ *	dtSearch()
+ *
+ * function:
+ *	Search for the entry with specified key
+ *
+ * parameter:
+ *
+ * return: 0 - search result on stack, leaf page pinned;
+ *	   errno - I/O error
+ */
+int dtSearch(struct inode *ip,
+	 component_t * key, ino_t * data, btstack_t * btstack, int flag)
+{
+	int rc = 0;
+	int cmp = 1;		/* init for empty page */
+	s64 bn;
+	metapage_t *mp;
+	dtpage_t *p;
+	s8 *stbl;
+	int base, index, lim;
+	btframe_t *btsp;
+	pxd_t *pxd;
+	int psize = 288;	/* initial in-line directory */
+	ino_t inumber;
+	component_t ciKey;
+	struct super_block *sb = ip->i_sb;
+
+	ciKey.name =
+	    (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
+				GFP_NOFS);
+	if (ciKey.name == 0) {
+		rc = ENOMEM;
+		goto dtSearch_Exit2;
+	}
+
+
+	/* uppercase search key for c-i directory */
+	UniStrcpy(ciKey.name, key->name);
+	ciKey.namlen = key->namlen;
+
+	/* only uppercase if case-insensitive support is on */
+	if ((JFS_SBI(sb)->mntflag & JFS_OS2) == JFS_OS2) {
+		ciToUpper(&ciKey);
+	}
+	BT_CLR(btstack);	/* reset stack */
+
+	/* init level count for max pages to split */
+	btstack->nsplit = 1;
+
+	/*
+	 *      search down tree from root:
+	 *
+	 * between two consecutive entries of <Ki, Pi> and <Kj, Pj> of
+	 * internal page, child page Pi contains entry with k, Ki <= K < Kj.
+	 *
+	 * if entry with search key K is not found
+	 * internal page search find the entry with largest key Ki
+	 * less than K which point to the child page to search;
+	 * leaf page search find the entry with smallest key Kj
+	 * greater than K so that the returned index is the position of
+	 * the entry to be shifted right for insertion of new entry.
+	 * for empty tree, search key is greater than any key of the tree.
+	 *
+	 * by convention, root bn = 0.
+	 */
+	for (bn = 0;;) {
+		/* get/pin the page to search */
+		DT_GETPAGE(ip, bn, mp, psize, p, rc);
+		if (rc)
+			goto dtSearch_Exit1;
+
+		/* get sorted entry table of the page */
+		stbl = DT_GETSTBL(p);
+
+		/*
+		 * binary search with search key K on the current page.
+		 */
+		for (base = 0, lim = p->header.nextindex; lim; lim >>= 1) {
+			index = base + (lim >> 1);
+
+			if (p->header.flag & BT_LEAF) {
+				/* uppercase leaf name to compare */
+				cmp =
+				    ciCompare(&ciKey, p, stbl[index],
+					      JFS_SBI(sb)->mntflag);
+			} else {
+				/* router key is in uppercase */
+
+				cmp = dtCompare(&ciKey, p, stbl[index]);
+
+
+			}
+			if (cmp == 0) {
+				/*
+				 *      search hit
+				 */
+				/* search hit - leaf page:
+				 * return the entry found
+				 */
+				if (p->header.flag & BT_LEAF) {
+					inumber = le32_to_cpu(
+			((ldtentry_t *) & p->slot[stbl[index]])->inumber);
+
+					/*
+					 * search for JFS_LOOKUP
+					 */
+					if (flag == JFS_LOOKUP) {
+						*data = inumber;
+						rc = 0;
+						goto out;
+					}
+
+					/*
+					 * search for JFS_CREATE
+					 */
+					if (flag == JFS_CREATE) {
+						*data = inumber;
+						rc = EEXIST;
+						goto out;
+					}
+
+					/*
+					 * search for JFS_REMOVE or JFS_RENAME
+					 */
+					if ((flag == JFS_REMOVE ||
+					     flag == JFS_RENAME) &&
+					    *data != inumber) {
+						rc = ESTALE;
+						goto out;
+					}
+
+					/*
+					 * JFS_REMOVE|JFS_FINDDIR|JFS_RENAME
+					 */
+					/* save search result */
+					*data = inumber;
+					btsp = btstack->top;
+					btsp->bn = bn;
+					btsp->index = index;
+					btsp->mp = mp;
+
+					rc = 0;
+					goto dtSearch_Exit1;
+				}
+
+				/* search hit - internal page:
+				 * descend/search its child page
+				 */
+				goto getChild;
+			}
+
+			if (cmp > 0) {
+				base = index + 1;
+				--lim;
+			}
+		}
+
+		/*
+		 *      search miss
+		 *
+		 * base is the smallest index with key (Kj) greater than
+		 * search key (K) and may be zero or (maxindex + 1) index.
+		 */
+		/*
+		 * search miss - leaf page
+		 *
+		 * return location of entry (base) where new entry with
+		 * search key K is to be inserted.
+		 */
+		if (p->header.flag & BT_LEAF) {
+			/*
+			 * search for JFS_LOOKUP, JFS_REMOVE, or JFS_RENAME
+			 */
+			if (flag == JFS_LOOKUP || flag == JFS_REMOVE ||
+			    flag == JFS_RENAME) {
+				rc = ENOENT;
+				goto out;
+			}
+
+			/*
+			 * search for JFS_CREATE|JFS_FINDDIR:
+			 *
+			 * save search result
+			 */
+			*data = 0;
+			btsp = btstack->top;
+			btsp->bn = bn;
+			btsp->index = base;
+			btsp->mp = mp;
+
+			rc = 0;
+			goto dtSearch_Exit1;
+		}
+
+		/*
+		 * search miss - internal page
+		 *
+		 * if base is non-zero, decrement base by one to get the parent
+		 * entry of the child page to search.
+		 */
+		index = base ? base - 1 : base;
+
+		/*
+		 * go down to child page
+		 */
+	      getChild:
+		/* update max. number of pages to split */
+		if (btstack->nsplit >= 8) {
+			/* Something's corrupted, mark filesytem dirty so
+			 * chkdsk will fix it.
+			 */
+			jERROR(1, ("stack overrun in dtSearch!\n"));
+			updateSuper(sb, FM_DIRTY);
+			rc = EIO;
+			goto out;
+		}
+		btstack->nsplit++;
+
+		/* push (bn, index) of the parent page/entry */
+		BT_PUSH(btstack, bn, index);
+
+		/* get the child page block number */
+		pxd = (pxd_t *) & p->slot[stbl[index]];
+		bn = addressPXD(pxd);
+		psize = lengthPXD(pxd) << JFS_SBI(ip->i_sb)->l2bsize;
+
+		/* unpin the parent page */
+		DT_PUTPAGE(mp);
+	}
+
+      out:
+	DT_PUTPAGE(mp);
+
+      dtSearch_Exit1:
+
+	kfree(ciKey.name);
+
+      dtSearch_Exit2:
+
+	return rc;
+}
+
+
+/*
+ *	dtInsert()
+ *
+ * function: insert an entry to directory tree
+ *
+ * parameter:
+ *
+ * return: 0 - success;
+ *	   errno - failure;
+ */
+int dtInsert(tid_t tid, struct inode *ip,
+	 component_t * name, ino_t * fsn, btstack_t * btstack)
+{
+	int rc = 0;
+	metapage_t *mp;		/* meta-page buffer */
+	dtpage_t *p;		/* base B+-tree index page */
+	s64 bn;
+	int index;
+	dtsplit_t split;	/* split information */
+	ddata_t data;
+	dtlock_t *dtlck;
+	int n;
+	tlock_t *tlck;
+	lv_t *lv;
+
+	/*
+	 *      retrieve search result
+	 *
+	 * dtSearch() returns (leaf page pinned, index at which to insert).
+	 * n.b. dtSearch() may return index of (maxindex + 1) of
+	 * the full page.
+	 */
+	DT_GETSEARCH(ip, btstack->top, bn, mp, p, index);
+
+	/*
+	 *      insert entry for new key
+	 */
+	if (DO_INDEX(ip)) {
+		if (JFS_IP(ip)->next_index == -1) {
+			DT_PUTPAGE(mp);
+			return EMLINK;
+		}
+		n = NDTLEAF(name->namlen);
+		data.leaf.tid = tid;
+		data.leaf.ip = ip;
+	} else {
+		n = NDTLEAF_LEGACY(name->namlen);
+		data.leaf.ip = 0;	/* signifies legacy directory format */
+	}
+	data.leaf.ino = cpu_to_le32(*fsn);
+
+	/*
+	 *      leaf page does not have enough room for new entry:
+	 *
+	 *      extend/split the leaf page;
+	 *
+	 * dtSplitUp() will insert the entry and unpin the leaf page.
+	 */
+	if (n > p->header.freecnt) {
+		split.mp = mp;
+		split.index = index;
+		split.nslot = n;
+		split.key = name;
+		split.data = &data;
+		rc = dtSplitUp(tid, ip, &split, btstack);
+		return rc;
+	}
+
+	/*
+	 *      leaf page does have enough room for new entry:
+	 *
+	 *      insert the new data entry into the leaf page;
+	 */
+	BT_MARK_DIRTY(mp, ip);
+	/*
+	 * acquire a transaction lock on the leaf page
+	 */
+	tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+	dtlck = (dtlock_t *) & tlck->lock;
+	ASSERT(dtlck->index == 0);
+	lv = (lv_t *) & dtlck->lv[0];
+
+	/* linelock header */
+	lv->offset = 0;
+	lv->length = 1;
+	dtlck->index++;
+
+	dtInsertEntry(p, index, name, &data, &dtlck);
+
+	/* linelock stbl of non-root leaf page */
+	if (!(p->header.flag & BT_ROOT)) {
+		if (dtlck->index >= dtlck->maxcnt)
+			dtlck = (dtlock_t *) txLinelock(dtlck);
+		lv = (lv_t *) & dtlck->lv[dtlck->index];
+		n = index >> L2DTSLOTSIZE;
+		lv->offset = p->header.stblindex + n;
+		lv->length =
+		    ((p->header.nextindex - 1) >> L2DTSLOTSIZE) - n + 1;
+		dtlck->index++;
+	}
+
+	/* unpin the leaf page */
+	DT_PUTPAGE(mp);
+
+	return 0;
+}
+
+
+/*
+ *	dtSplitUp()
+ *
+ * function: propagate insertion bottom up;
+ *
+ * parameter:
+ *
+ * return: 0 - success;
+ *	   errno - failure;
+ * 	leaf page unpinned;
+ */
+static int dtSplitUp(tid_t tid,
+	  struct inode *ip, dtsplit_t * split, btstack_t * btstack)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+	int rc = 0;
+	metapage_t *smp;
+	dtpage_t *sp;		/* split page */
+	metapage_t *rmp;
+	dtpage_t *rp;		/* new right page split from sp */
+	pxd_t rpxd;		/* new right page extent descriptor */
+	metapage_t *lmp;
+	dtpage_t *lp;		/* left child page */
+	int skip;		/* index of entry of insertion */
+	btframe_t *parent;	/* parent page entry on traverse stack */
+	s64 xaddr, nxaddr;
+	int xlen, xsize;
+	pxdlist_t pxdlist;
+	pxd_t *pxd;
+	component_t key = { 0, 0 };
+	ddata_t *data = split->data;
+	int n;
+	dtlock_t *dtlck;
+	tlock_t *tlck;
+	lv_t *lv;
+
+	/* get split page */
+	smp = split->mp;
+	sp = DT_PAGE(ip, smp);
+
+	key.name =
+	    (wchar_t *) kmalloc((JFS_NAME_MAX + 2) * sizeof(wchar_t),
+				GFP_NOFS);
+	if (key.name == 0) {
+		DT_PUTPAGE(smp);
+		rc = ENOMEM;
+		goto dtSplitUp_Exit;
+	}
+
+	/*
+	 *      split leaf page
+	 *
+	 * The split routines insert the new entry, and
+	 * acquire txLock as appropriate.
+	 */
+	/*
+	 *      split root leaf page:
+	 */
+	if (sp->header.flag & BT_ROOT) {
+		/*
+		 * allocate a single extent child page
+		 */
+		xlen = 1;
+		n = sbi->bsize >> L2DTSLOTSIZE;
+		n -= (n + 31) >> L2DTSLOTSIZE;	/* stbl size */
+		n -= DTROOTMAXSLOT - sp->header.freecnt; /* header + entries */
+		if (n <= split->nslot)
+			xlen++;
+		if ((rc = dbAlloc(ip, 0, (s64) xlen, &xaddr)))
+			goto freeKeyName;
+
+		pxdlist.maxnpxd = 1;
+		pxdlist.npxd = 0;
+		pxd = &pxdlist.pxd[0];
+		PXDaddress(pxd, xaddr);
+		PXDlength(pxd, xlen);
+		split->pxdlist = &pxdlist;
+		rc = dtSplitRoot(tid, ip, split, &rmp);
+
+		DT_PUTPAGE(rmp);
+		DT_PUTPAGE(smp);
+
+		goto freeKeyName;
+	}
+
+	/*
+	 *      extend first leaf page
+	 *
+	 * extend the 1st extent if less than buffer page size
+	 * (dtExtendPage() reurns leaf page unpinned)
+	 */
+	pxd = &sp->header.self;
+	xlen = lengthPXD(pxd);
+	xsize = xlen << sbi->l2bsize;
+	if (xsize < PSIZE) {
+		xaddr = addressPXD(pxd);
+		n = xsize >> L2DTSLOTSIZE;
+		n -= (n + 31) >> L2DTSLOTSIZE;	/* stbl size */
+		if ((n + sp->header.freecnt) <= split->nslot)
+			n = xlen + (xlen << 1);
+		else
+			n = xlen;
+		if ((rc = dbReAlloc(sbi->ipbmap, xaddr, (s64) xlen,
+				    (s64) n, &nxaddr)))
+			goto extendOut;
+
+		pxdlist.maxnpxd = 1;
+		pxdlist.npxd = 0;
+		pxd = &pxdlist.pxd[0];
+		PXDaddress(pxd, nxaddr)
+		    PXDlength(pxd, xlen + n);
+		split->pxdlist = &pxdlist;
+		if ((rc = dtExtendPage(tid, ip, split, btstack))) {
+			nxaddr = addressPXD(pxd);
+			if (xaddr != nxaddr) {
+				/* free relocated extent */
+				xlen = lengthPXD(pxd);
+				dbFree(ip, nxaddr, (s64) xlen);
+			} else {
+				/* free extended delta */
+				xlen = lengthPXD(pxd) - n;
+				xaddr = addressPXD(pxd) + xlen;
+				dbFree(ip, xaddr, (s64) n);
+			}
+		}
+
+	      extendOut:
+		DT_PUTPAGE(smp);
+		goto freeKeyName;
+	}
+
+	/*
+	 *      split leaf page <sp> into <sp> and a new right page <rp>.
+	 *
+	 * return <rp> pinned and its extent descriptor <rpxd>
+	 */
+	/*
+	 * allocate new directory page extent and
+	 * new index page(s) to cover page split(s)
+	 *
+	 * allocation hint: ?
+	 */
+	n = btstack->nsplit;
+	pxdlist.maxnpxd = pxdlist.npxd = 0;
+	xlen = sbi->nbperpage;
+	for (pxd = pxdlist.pxd; n > 0; n--, pxd++) {
+		if ((rc = dbAlloc(ip, 0, (s64) xlen, &xaddr)) == 0) {
+			PXDaddress(pxd, xaddr);
+			PXDlength(pxd, xlen);
+			pxdlist.maxnpxd++;
+			continue;
+		}
+
+		DT_PUTPAGE(smp);
+
+		/* undo allocation */
+		goto splitOut;
+	}
+
+	split->pxdlist = &pxdlist;
+	if ((rc = dtSplitPage(tid, ip, split, &rmp, &rp, &rpxd))) {
+		DT_PUTPAGE(smp);
+
+		/* undo allocation */
+		goto splitOut;
+	}
+
+	/*
+	 * propagate up the router entry for the leaf page just split
+	 *
+	 * insert a router entry for the new page into the parent page,
+	 * propagate the insert/split up the tree by walking back the stack
+	 * of (bn of parent page, index of child page entry in parent page)
+	 * that were traversed during the search for the page that split.
+	 *
+	 * the propagation of insert/split up the tree stops if the root
+	 * splits or the page inserted into doesn't have to split to hold
+	 * the new entry.
+	 *
+	 * the parent entry for the split page remains the same, and
+	 * a new entry is inserted at its right with the first key and
+	 * block number of the new right page.
+	 *
+	 * There are a maximum of 4 pages pinned at any time:
+	 * two children, left parent and right parent (when the parent splits).
+	 * keep the child pages pinned while working on the parent.
+	 * make sure that all pins are released at exit.
+	 */
+	while ((parent = BT_POP(btstack)) != NULL) {
+		/* parent page specified by stack frame <parent> */
+
+		/* keep current child pages (<lp>, <rp>) pinned */
+		lmp = smp;
+		lp = sp;
+
+		/*
+		 * insert router entry in parent for new right child page <rp>
+		 */
+		/* get the parent page <sp> */
+		DT_GETPAGE(ip, parent->bn, smp, PSIZE, sp, rc);
+		if (rc) {
+			DT_PUTPAGE(lmp);
+			DT_PUTPAGE(rmp);
+			goto splitOut;
+		}
+
+		/*
+		 * The new key entry goes ONE AFTER the index of parent entry,
+		 * because the split was to the right.
+		 */
+		skip = parent->index + 1;
+
+		/*
+		 * compute the key for the router entry
+		 *
+		 * key suffix compression:
+		 * for internal pages that have leaf pages as children,
+		 * retain only what's needed to distinguish between
+		 * the new entry and the entry on the page to its left.
+		 * If the keys compare equal, retain the entire key.
+		 *
+		 * note that compression is performed only at computing
+		 * router key at the lowest internal level.
+		 * further compression of the key between pairs of higher
+		 * level internal pages loses too much information and
+		 * the search may fail.
+		 * (e.g., two adjacent leaf pages of {a, ..., x} {xx, ...,}
+		 * results in two adjacent parent entries (a)(xx).
+		 * if split occurs between these two entries, and
+		 * if compression is applied, the router key of parent entry
+		 * of right page (x) will divert search for x into right
+		 * subtree and miss x in the left subtree.)
+		 *
+		 * the entire key must be retained for the next-to-leftmost
+		 * internal key at any level of the tree, or search may fail
+		 * (e.g., ?)
+		 */
+		switch (rp->header.flag & BT_TYPE) {
+		case BT_LEAF:
+			/*
+			 * compute the length of prefix for suffix compression
+			 * between last entry of left page and first entry
+			 * of right page
+			 */
+			if ((sp->header.flag & BT_ROOT && skip > 1) ||
+			    sp->header.prev != 0 || skip > 1) {
+				/* compute uppercase router prefix key */
+				ciGetLeafPrefixKey(lp,
+						   lp->header.nextindex - 1,
+						   rp, 0, &key, sbi->mntflag);
+			} else {
+				/* next to leftmost entry of
+				   lowest internal level */
+
+				/* compute uppercase router key */
+				dtGetKey(rp, 0, &key, sbi->mntflag);
+				key.name[key.namlen] = 0;
+
+				if ((sbi->mntflag & JFS_OS2) == JFS_OS2)
+					ciToUpper(&key);
+			}
+
+			n = NDTINTERNAL(key.namlen);
+			break;
+
+		case BT_INTERNAL:
+			dtGetKey(rp, 0, &key, sbi->mntflag);
+			n = NDTINTERNAL(key.namlen);
+			break;
+
+		default:
+			jERROR(2, ("dtSplitUp(): UFO!\n"));
+			break;
+		}
+
+		/* unpin left child page */
+		DT_PUTPAGE(lmp);
+
+		/*
+		 * compute the data for the router entry
+		 */
+		data->xd = rpxd;	/* child page xd */
+
+		/*
+		 * parent page is full - split the parent page
+		 */
+		if (n > sp->header.freecnt) {
+			/* init for parent page split */
+			split->mp = smp;
+			split->index = skip;	/* index at insert */
+			split->nslot = n;
+			split->key = &key;
+			/* split->data = data; */
+
+			/* unpin right child page */
+			DT_PUTPAGE(rmp);
+
+			/* The split routines insert the new entry,
+			 * acquire txLock as appropriate.
+			 * return <rp> pinned and its block number <rbn>.
+			 */
+			rc = (sp->header.flag & BT_ROOT) ?
+			    dtSplitRoot(tid, ip, split, &rmp) :
+			    dtSplitPage(tid, ip, split, &rmp, &rp, &rpxd);
+			if (rc) {
+				DT_PUTPAGE(smp);
+				goto splitOut;
+			}
+
+			/* smp and rmp are pinned */
+		}
+		/*
+		 * parent page is not full - insert router entry in parent page
+		 */
+		else {
+			BT_MARK_DIRTY(smp, ip);
+			/*
+			 * acquire a transaction lock on the parent page
+			 */
+			tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY);
+			dtlck = (dtlock_t *) & tlck->lock;
+			ASSERT(dtlck->index == 0);
+			lv = (lv_t *) & dtlck->lv[0];
+
+			/* linelock header */
+			lv->offset = 0;
+			lv->length = 1;
+			dtlck->index++;
+
+			/* linelock stbl of non-root parent page */
+			if (!(sp->header.flag & BT_ROOT)) {
+				lv++;
+				n = skip >> L2DTSLOTSIZE;
+				lv->offset = sp->header.stblindex + n;
+				lv->length =
+				    ((sp->header.nextindex -
+				      1) >> L2DTSLOTSIZE) - n + 1;
+				dtlck->index++;
+			}
+
+			dtInsertEntry(sp, skip, &key, data, &dtlck);
+
+			/* exit propagate up */
+			break;
+		}
+	}
+
+	/* unpin current split and its right page */
+	DT_PUTPAGE(smp);
+	DT_PUTPAGE(rmp);
+
+	/*
+	 * free remaining extents allocated for split
+	 */
+      splitOut:
+	n = pxdlist.npxd;
+	pxd = &pxdlist.pxd[n];
+	for (; n < pxdlist.maxnpxd; n++, pxd++)
+		dbFree(ip, addressPXD(pxd), (s64) lengthPXD(pxd));
+
+      freeKeyName:
+	kfree(key.name);
+
+      dtSplitUp_Exit:
+
+	return rc;
+}
+
+
+/*
+ *	dtSplitPage()
+ *
+ * function: Split a non-root page of a btree.
+ *
+ * parameter:
+ *
+ * return: 0 - success;
+ *	   errno - failure;
+ *	return split and new page pinned;
+ */
+static int dtSplitPage(tid_t tid, struct inode *ip, dtsplit_t * split,
+	    metapage_t ** rmpp, dtpage_t ** rpp, pxd_t * rpxdp)
+{
+	struct super_block *sb = ip->i_sb;
+	int rc = 0;
+	metapage_t *smp;
+	dtpage_t *sp;
+	metapage_t *rmp;
+	dtpage_t *rp;		/* new right page allocated */
+	s64 rbn;		/* new right page block number */
+	metapage_t *mp;
+	dtpage_t *p;
+	s64 nextbn;
+	pxdlist_t *pxdlist;
+	pxd_t *pxd;
+	int skip, nextindex, half, left, nxt, off, si;
+	ldtentry_t *ldtentry;
+	idtentry_t *idtentry;
+	u8 *stbl;
+	dtslot_t *f;
+	int fsi, stblsize;
+	int n;
+	dtlock_t *sdtlck, *rdtlck;
+	tlock_t *tlck;
+	dtlock_t *dtlck;
+	lv_t *slv, *rlv, *lv;
+
+	/* get split page */
+	smp = split->mp;
+	sp = DT_PAGE(ip, smp);
+
+	/*
+	 * allocate the new right page for the split
+	 */
+	pxdlist = split->pxdlist;
+	pxd = &pxdlist->pxd[pxdlist->npxd];
+	pxdlist->npxd++;
+	rbn = addressPXD(pxd);
+	rmp = get_metapage(ip, rbn, PSIZE, 1);
+	if (rmp == NULL)
+		return EIO;
+
+	jEVENT(0,
+	       ("dtSplitPage: ip:0x%p smp:0x%p rmp:0x%p\n", ip, smp, rmp));
+
+	BT_MARK_DIRTY(rmp, ip);
+	/*
+	 * acquire a transaction lock on the new right page
+	 */
+	tlck = txLock(tid, ip, rmp, tlckDTREE | tlckNEW);
+	rdtlck = (dtlock_t *) & tlck->lock;
+
+	rp = (dtpage_t *) rmp->data;
+	*rpp = rp;
+	rp->header.self = *pxd;
+
+	BT_MARK_DIRTY(smp, ip);
+	/*
+	 * acquire a transaction lock on the split page
+	 *
+	 * action:
+	 */
+	tlck = txLock(tid, ip, smp, tlckDTREE | tlckENTRY);
+	sdtlck = (dtlock_t *) & tlck->lock;
+
+	/* linelock header of split page */
+	ASSERT(sdtlck->index == 0);
+	slv = (lv_t *) & sdtlck->lv[0];
+	slv->offset = 0;
+	slv->length = 1;
+	sdtlck->index++;
+
+	/*
+	 * initialize/update sibling pointers between sp and rp
+	 */
+	nextbn = le64_to_cpu(sp->header.next);
+	rp->header.next = cpu_to_le64(nextbn);
+	rp->header.prev = cpu_to_le64(addressPXD(&sp->header.self));
+	sp->header.next = cpu_to_le64(rbn);
+
+	/*
+	 * initialize new right page
+	 */
+	rp->header.flag = sp->header.flag;
+
+	/* compute sorted entry table at start of extent data area */
+	rp->header.nextindex = 0;
+	rp->header.stblindex = 1;
+
+	n = PSIZE >> L2DTSLOTSIZE;
+	rp->header.maxslot = n;
+	stblsize = (n + 31) >> L2DTSLOTSIZE;	/* in unit of slot */
+
+	/* init freelist */
+	fsi = rp->header.stblindex + stblsize;
+	rp->header.freelist = fsi;
+	rp->header.freecnt = rp->header.maxslot - fsi;
+
+	/*
+	 *      sequential append at tail: append without split
+	 *
+	 * If splitting the last page on a level because of appending
+	 * a entry to it (skip is maxentry), it's likely that the access is
+	 * sequential. Adding an empty page on the side of the level is less
+	 * work and can push the fill factor much higher than normal.
+	 * If we're wrong it's no big deal, we'll just do the split the right
+	 * way next time.
+	 * (It may look like it's equally easy to do a similar hack for
+	 * reverse sorted data, that is, split the tree left,
+	 * but it's not. Be my guest.)
+	 */
+	if (nextbn == 0 && split->index == sp->header.nextindex) {
+		/* linelock header + stbl (first slot) of new page */
+		rlv = (lv_t *) & rdtlck->lv[rdtlck->index];
+		rlv->offset = 0;
+		rlv->length = 2;
+		rdtlck->index++;
+
+		/*
+		 * initialize freelist of new right page
+		 */
+		f = &rp->slot[fsi];
+		for (fsi++; fsi < rp->header.maxslot; f++, fsi++)
+			f->next = fsi;
+		f->next = -1;
+
+		/* insert entry at the first entry of the new right page */
+		dtInsertEntry(rp, 0, split->key, split->data, &rdtlck);
+
+		goto out;
+	}
+
+	/*
+	 *      non-sequential insert (at possibly middle page)
+	 */
+
+	/*
+	 * update prev pointer of previous right sibling page;
+	 */
+	if (nextbn != 0) {
+		DT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		BT_MARK_DIRTY(mp, ip);
+		/*
+		 * acquire a transaction lock on the next page
+		 */
+		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);
+		jEVENT(0,
+		       ("dtSplitPage: tlck = 0x%p, ip = 0x%p, mp=0x%p\n",
+			tlck, ip, mp));
+		dtlck = (dtlock_t *) & tlck->lock;
+
+		/* linelock header of previous right sibling page */
+		lv = (lv_t *) & dtlck->lv[dtlck->index];
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+
+		p->header.prev = cpu_to_le64(rbn);
+
+		DT_PUTPAGE(mp);
+	}
+
+	/*
+	 * split the data between the split and right pages.
+	 */
+	skip = split->index;
+	half = (PSIZE >> L2DTSLOTSIZE) >> 1;	/* swag */
+	left = 0;
+
+	/*
+	 *      compute fill factor for split pages
+	 *
+	 * <nxt> traces the next entry to move to rp
+	 * <off> traces the next entry to stay in sp
+	 */
+	stbl = (u8 *) & sp->slot[sp->header.stblindex];
+	nextindex = sp->header.nextindex;
+	for (nxt = off = 0; nxt < nextindex; ++off) {
+		if (off == skip)
+			/* check for fill factor with new entry size */
+			n = split->nslot;
+		else {
+			si = stbl[nxt];
+			switch (sp->header.flag & BT_TYPE) {
+			case BT_LEAF:
+				ldtentry = (ldtentry_t *) & sp->slot[si];
+				if (DO_INDEX(ip))
+					n = NDTLEAF(ldtentry->namlen);
+				else
+					n = NDTLEAF_LEGACY(ldtentry->
+							   namlen);
+				break;
+
+			case BT_INTERNAL:
+				idtentry = (idtentry_t *) & sp->slot[si];
+				n = NDTINTERNAL(idtentry->namlen);
+				break;
+
+			default:
+				break;
+			}
+
+			++nxt;	/* advance to next entry to move in sp */
+		}
+
+		left += n;
+		if (left >= half)
+			break;
+	}
+
+	/* <nxt> poins to the 1st entry to move */
+
+	/*
+	 *      move entries to right page
+	 *
+	 * dtMoveEntry() initializes rp and reserves entry for insertion
+	 *
+	 * split page moved out entries are linelocked;
+	 * new/right page moved in entries are linelocked;
+	 */
+	/* linelock header + stbl of new right page */
+	rlv = (lv_t *) & rdtlck->lv[rdtlck->index];
+	rlv->offset = 0;
+	rlv->length = 5;
+	rdtlck->index++;
+
+	dtMoveEntry(sp, nxt, rp, &sdtlck, &rdtlck, DO_INDEX(ip));
+
+	sp->header.nextindex = nxt;
+
+	/*
+	 * finalize freelist of new right page
+	 */
+	fsi = rp->header.freelist;
+	f = &rp->slot[fsi];
+	for (fsi++; fsi < rp->header.maxslot; f++, fsi++)
+		f->next = fsi;
+	f->next = -1;
+
+	/*
+	 * Update directory index table for entries now in right page
+	 */
+	if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) {
+		mp = 0;
+		stbl = DT_GETSTBL(rp);
+		for (n = 0; n < rp->header.nextindex; n++) {
+			ldtentry = (ldtentry_t *) & rp->slot[stbl[n]];
+			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
+				     rbn, n, &mp);
+		}
+		if (mp)
+			release_metapage(mp);
+	}
+
+	/*
+	 * the skipped index was on the left page,
+	 */
+	if (skip <= off) {
+		/* insert the new entry in the split page */
+		dtInsertEntry(sp, skip, split->key, split->data, &sdtlck);
+
+		/* linelock stbl of split page */
+		if (sdtlck->index >= sdtlck->maxcnt)
+			sdtlck = (dtlock_t *) txLinelock(sdtlck);
+		slv = (lv_t *) & sdtlck->lv[sdtlck->index];
+		n = skip >> L2DTSLOTSIZE;
+		slv->offset = sp->header.stblindex + n;
+		slv->length =
+		    ((sp->header.nextindex - 1) >> L2DTSLOTSIZE) - n + 1;
+		sdtlck->index++;
+	}
+	/*
+	 * the skipped index was on the right page,
+	 */
+	else {
+		/* adjust the skip index to reflect the new position */
+		skip -= nxt;
+
+		/* insert the new entry in the right page */
+		dtInsertEntry(rp, skip, split->key, split->data, &rdtlck);
+	}
+
+      out:
+	*rmpp = rmp;
+	*rpxdp = *pxd;
+
+	ip->i_blocks += LBLK2PBLK(sb, lengthPXD(pxd));
+
+	jEVENT(0, ("dtSplitPage: ip:0x%p sp:0x%p rp:0x%p\n", ip, sp, rp));
+	return 0;
+}
+
+
+/*
+ *	dtExtendPage()
+ *
+ * function: extend 1st/only directory leaf page
+ *
+ * parameter:
+ *
+ * return: 0 - success;
+ *	   errno - failure;
+ *	return extended page pinned;
+ */
+static int dtExtendPage(tid_t tid,
+	     struct inode *ip, dtsplit_t * split, btstack_t * btstack)
+{
+	struct super_block *sb = ip->i_sb;
+	int rc;
+	metapage_t *smp, *pmp, *mp;
+	dtpage_t *sp, *pp;
+	pxdlist_t *pxdlist;
+	pxd_t *pxd, *tpxd;
+	int xlen, xsize;
+	int newstblindex, newstblsize;
+	int oldstblindex, oldstblsize;
+	int fsi, last;
+	dtslot_t *f;
+	btframe_t *parent;
+	int n;
+	dtlock_t *dtlck;
+	s64 xaddr, txaddr;
+	tlock_t *tlck;
+	pxdlock_t *pxdlock;
+	lv_t *lv;
+	uint type;
+	ldtentry_t *ldtentry;
+	u8 *stbl;
+
+	/* get page to extend */
+	smp = split->mp;
+	sp = DT_PAGE(ip, smp);
+
+	/* get parent/root page */
+	parent = BT_POP(btstack);
+	DT_GETPAGE(ip, parent->bn, pmp, PSIZE, pp, rc);
+	if (rc)
+		return (rc);
+
+	/*
+	 *      extend the extent
+	 */
+	pxdlist = split->pxdlist;
+	pxd = &pxdlist->pxd[pxdlist->npxd];
+	pxdlist->npxd++;
+
+	xaddr = addressPXD(pxd);
+	tpxd = &sp->header.self;
+	txaddr = addressPXD(tpxd);
+	/* in-place extension */
+	if (xaddr == txaddr) {
+		type = tlckEXTEND;
+	}
+	/* relocation */
+	else {
+		type = tlckNEW;
+
+		/* save moved extent descriptor for later free */
+		tlck = txMaplock(tid, ip, tlckDTREE | tlckRELOCATE);
+		pxdlock = (pxdlock_t *) & tlck->lock;
+		pxdlock->flag = mlckFREEPXD;
+		pxdlock->pxd = sp->header.self;
+		pxdlock->index = 1;
+
+		/*
+		 * Update directory index table to reflect new page address
+		 */
+		if (DO_INDEX(ip)) {
+			mp = 0;
+			stbl = DT_GETSTBL(sp);
+			for (n = 0; n < sp->header.nextindex; n++) {
+				ldtentry =
+				    (ldtentry_t *) & sp->slot[stbl[n]];
+				modify_index(tid, ip,
+					     le32_to_cpu(ldtentry->index),
+					     xaddr, n, &mp);
+			}
+			if (mp)
+				release_metapage(mp);
+		}
+	}
+
+	/*
+	 *      extend the page
+	 */
+	sp->header.self = *pxd;
+
+	jEVENT(0,
+	       ("dtExtendPage: ip:0x%p smp:0x%p sp:0x%p\n", ip, smp, sp));
+
+	BT_MARK_DIRTY(smp, ip);
+	/*
+	 * acquire a transaction lock on the extended/leaf page
+	 */
+	tlck = txLock(tid, ip, smp, tlckDTREE | type);
+	dtlck = (dtlock_t *) & tlck->lock;
+	lv = (lv_t *) & dtlck->lv[0];
+
+	/* update buffer extent descriptor of extended page */
+	xlen = lengthPXD(pxd);
+	xsize = xlen << JFS_SBI(sb)->l2bsize;
+#ifdef _STILL_TO_PORT
+	bmSetXD(smp, xaddr, xsize);
+#endif				/*  _STILL_TO_PORT */
+
+	/*
+	 * copy old stbl to new stbl at start of extended area
+	 */
+	oldstblindex = sp->header.stblindex;
+	oldstblsize = (sp->header.maxslot + 31) >> L2DTSLOTSIZE;
+	newstblindex = sp->header.maxslot;
+	n = xsize >> L2DTSLOTSIZE;
+	newstblsize = (n + 31) >> L2DTSLOTSIZE;
+	memcpy(&sp->slot[newstblindex], &sp->slot[oldstblindex],
+	       sp->header.nextindex);
+
+	/*
+	 * in-line extension: linelock old area of extended page
+	 */
+	if (type == tlckEXTEND) {
+		/* linelock header */
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+		lv++;
+
+		/* linelock new stbl of extended page */
+		lv->offset = newstblindex;
+		lv->length = newstblsize;
+	}
+	/*
+	 * relocation: linelock whole relocated area
+	 */
+	else {
+		lv->offset = 0;
+		lv->length = sp->header.maxslot + newstblsize;
+	}
+
+	dtlck->index++;
+
+	sp->header.maxslot = n;
+	sp->header.stblindex = newstblindex;
+	/* sp->header.nextindex remains the same */
+
+	/*
+	 * add old stbl region at head of freelist
+	 */
+	fsi = oldstblindex;
+	f = &sp->slot[fsi];
+	last = sp->header.freelist;
+	for (n = 0; n < oldstblsize; n++, fsi++, f++) {
+		f->next = last;
+		last = fsi;
+	}
+	sp->header.freelist = last;
+	sp->header.freecnt += oldstblsize;
+
+	/*
+	 * append free region of newly extended area at tail of freelist
+	 */
+	/* init free region of newly extended area */
+	fsi = n = newstblindex + newstblsize;
+	f = &sp->slot[fsi];
+	for (fsi++; fsi < sp->header.maxslot; f++, fsi++)
+		f->next = fsi;
+	f->next = -1;
+
+	/* append new free region at tail of old freelist */
+	fsi = sp->header.freelist;
+	if (fsi == -1)
+		sp->header.freelist = n;
+	else {
+		do {
+			f = &sp->slot[fsi];
+			fsi = f->next;
+		} while (fsi != -1);
+
+		f->next = n;
+	}
+
+	sp->header.freecnt += sp->header.maxslot - n;
+
+	/*
+	 * insert the new entry
+	 */
+	dtInsertEntry(sp, split->index, split->key, split->data, &dtlck);
+
+	BT_MARK_DIRTY(pmp, ip);
+	/*
+	 * linelock any freeslots residing in old extent
+	 */
+	if (type == tlckEXTEND) {
+		n = sp->header.maxslot >> 2;
+		if (sp->header.freelist < n)
+			dtLinelockFreelist(sp, n, &dtlck);
+	}
+
+	/*
+	 *      update parent entry on the parent/root page
+	 */
+	/*
+	 * acquire a transaction lock on the parent/root page
+	 */
+	tlck = txLock(tid, ip, pmp, tlckDTREE | tlckENTRY);
+	dtlck = (dtlock_t *) & tlck->lock;
+	lv = (lv_t *) & dtlck->lv[dtlck->index];
+
+	/* linelock parent entry - 1st slot */
+	lv->offset = 1;
+	lv->length = 1;
+	dtlck->index++;
+
+	/* update the parent pxd for page extension */
+	tpxd = (pxd_t *) & pp->slot[1];
+	*tpxd = *pxd;
+
+	/* Since the directory might have an EA and/or ACL associated with it
+	 * we need to make sure we take that into account when setting the
+	 * i_nblocks
+	 */
+	ip->i_blocks = LBLK2PBLK(ip->i_sb, xlen +
+				 ((JFS_IP(ip)->ea.flag & DXD_EXTENT) ?
+				  lengthDXD(&JFS_IP(ip)->ea) : 0) +
+				 ((JFS_IP(ip)->acl.flag & DXD_EXTENT) ?
+				  lengthDXD(&JFS_IP(ip)->acl) : 0));
+
+	jEVENT(0,
+	       ("dtExtendPage: ip:0x%p smp:0x%p sp:0x%p\n", ip, smp, sp));
+
+
+	DT_PUTPAGE(pmp);
+	return 0;
+}
+
+
+/*
+ *	dtSplitRoot()
+ *
+ * function:
+ *	split the full root page into
+ *	original/root/split page and new right page
+ *	i.e., root remains fixed in tree anchor (inode) and
+ *	the root is copied to a single new right child page
+ *	since root page << non-root page, and
+ *	the split root page contains a single entry for the
+ *	new right child page.
+ *
+ * parameter:
+ *
+ * return: 0 - success;
+ *	   errno - failure;
+ *	return new page pinned;
+ */
+static int dtSplitRoot(tid_t tid,
+	    struct inode *ip, dtsplit_t * split, metapage_t ** rmpp)
+{
+	struct super_block *sb = ip->i_sb;
+	metapage_t *smp;
+	dtroot_t *sp;
+	metapage_t *rmp;
+	dtpage_t *rp;
+	s64 rbn;
+	int xlen;
+	int xsize;
+	dtslot_t *f;
+	s8 *stbl;
+	int fsi, stblsize, n;
+	idtentry_t *s;
+	pxd_t *ppxd;
+	pxdlist_t *pxdlist;
+	pxd_t *pxd;
+	dtlock_t *dtlck;
+	tlock_t *tlck;
+	lv_t *lv;
+
+	/* get split root page */
+	smp = split->mp;
+	sp = &JFS_IP(ip)->i_dtroot;
+
+	/*
+	 *      allocate/initialize a single (right) child page
+	 *
+	 * N.B. at first split, a one (or two) block to fit new entry
+	 * is allocated; at subsequent split, a full page is allocated;
+	 */
+	pxdlist = split->pxdlist;
+	pxd = &pxdlist->pxd[pxdlist->npxd];
+	pxdlist->npxd++;
+	rbn = addressPXD(pxd);
+	xlen = lengthPXD(pxd);
+	xsize = xlen << JFS_SBI(sb)->l2bsize;
+	rmp = get_metapage(ip, rbn, xsize, 1);
+	rp = rmp->data;
+
+	BT_MARK_DIRTY(rmp, ip);
+	/*
+	 * acquire a transaction lock on the new right page
+	 */
+	tlck = txLock(tid, ip, rmp, tlckDTREE | tlckNEW);
+	dtlck = (dtlock_t *) & tlck->lock;
+
+	rp->header.flag =
+	    (sp->header.flag & BT_LEAF) ? BT_LEAF : BT_INTERNAL;
+	rp->header.self = *pxd;
+
+	/* initialize sibling pointers */
+	rp->header.next = 0;
+	rp->header.prev = 0;
+
+	/*
+	 *      move in-line root page into new right page extent
+	 */
+	/* linelock header + copied entries + new stbl (1st slot) in new page */
+	ASSERT(dtlck->index == 0);
+	lv = (lv_t *) & dtlck->lv[0];
+	lv->offset = 0;
+	lv->length = 10;	/* 1 + 8 + 1 */
+	dtlck->index++;
+
+	n = xsize >> L2DTSLOTSIZE;
+	rp->header.maxslot = n;
+	stblsize = (n + 31) >> L2DTSLOTSIZE;
+
+	/* copy old stbl to new stbl at start of extended area */
+	rp->header.stblindex = DTROOTMAXSLOT;
+	stbl = (s8 *) & rp->slot[DTROOTMAXSLOT];
+	memcpy(stbl, sp->header.stbl, sp->header.nextindex);
+	rp->header.nextindex = sp->header.nextindex;
+
+	/* copy old data area to start of new data area */
+	memcpy(&rp->slot[1], &sp->slot[1], IDATASIZE);
+
+	/*
+	 * append free region of newly extended area at tail of freelist
+	 */
+	/* init free region of newly extended area */
+	fsi = n = DTROOTMAXSLOT + stblsize;
+	f = &rp->slot[fsi];
+	for (fsi++; fsi < rp->header.maxslot; f++, fsi++)
+		f->next = fsi;
+	f->next = -1;
+
+	/* append new free region at tail of old freelist */
+	fsi = sp->header.freelist;
+	if (fsi == -1)
+		rp->header.freelist = n;
+	else {
+		rp->header.freelist = fsi;
+
+		do {
+			f = &rp->slot[fsi];
+			fsi = f->next;
+		} while (fsi != -1);
+
+		f->next = n;
+	}
+
+	rp->header.freecnt = sp->header.freecnt + rp->header.maxslot - n;
+
+	/*
+	 * Update directory index table for entries now in right page
+	 */
+	if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) {
+		metapage_t *mp = 0;
+		ldtentry_t *ldtentry;
+
+		stbl = DT_GETSTBL(rp);
+		for (n = 0; n < rp->header.nextindex; n++) {
+			ldtentry = (ldtentry_t *) & rp->slot[stbl[n]];
+			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
+				     rbn, n, &mp);
+		}
+		if (mp)
+			release_metapage(mp);
+	}
+	/*
+	 * Update directory index table for entries now in right page
+	 */
+	if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) {
+		metapage_t *mp = 0;
+		ldtentry_t *ldtentry;
+
+		stbl = DT_GETSTBL(rp);
+		for (n = 0; n < rp->header.nextindex; n++) {
+			ldtentry = (ldtentry_t *) & rp->slot[stbl[n]];
+			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
+				     rbn, n, &mp);
+		}
+		if (mp)
+			release_metapage(mp);
+	}
+	/*
+	 * insert the new entry into the new right/child page
+	 * (skip index in the new right page will not change)
+	 */
+	dtInsertEntry(rp, split->index, split->key, split->data, &dtlck);
+
+	/*
+	 *      reset parent/root page
+	 *
+	 * set the 1st entry offset to 0, which force the left-most key
+	 * at any level of the tree to be less than any search key.
+	 *
+	 * The btree comparison code guarantees that the left-most key on any
+	 * level of the tree is never used, so it doesn't need to be filled in.
+	 */
+	BT_MARK_DIRTY(smp, ip);
+	/*
+	 * acquire a transaction lock on the root page (in-memory inode)
+	 */
+	tlck = txLock(tid, ip, smp, tlckDTREE | tlckNEW | tlckBTROOT);
+	dtlck = (dtlock_t *) & tlck->lock;
+
+	/* linelock root */
+	ASSERT(dtlck->index == 0);
+	lv = (lv_t *) & dtlck->lv[0];
+	lv->offset = 0;
+	lv->length = DTROOTMAXSLOT;
+	dtlck->index++;
+
+	/* update page header of root */
+	if (sp->header.flag & BT_LEAF) {
+		sp->header.flag &= ~BT_LEAF;
+		sp->header.flag |= BT_INTERNAL;
+	}
+
+	/* init the first entry */
+	s = (idtentry_t *) & sp->slot[DTENTRYSTART];
+	ppxd = (pxd_t *) s;
+	*ppxd = *pxd;
+	s->next = -1;
+	s->namlen = 0;
+
+	stbl = sp->header.stbl;
+	stbl[0] = DTENTRYSTART;
+	sp->header.nextindex = 1;
+
+	/* init freelist */
+	fsi = DTENTRYSTART + 1;
+	f = &sp->slot[fsi];
+
+	/* init free region of remaining area */
+	for (fsi++; fsi < DTROOTMAXSLOT; f++, fsi++)
+		f->next = fsi;
+	f->next = -1;
+
+	sp->header.freelist = DTENTRYSTART + 1;
+	sp->header.freecnt = DTROOTMAXSLOT - (DTENTRYSTART + 1);
+
+	*rmpp = rmp;
+
+	ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd));
+	return 0;
+}
+
+
+/*
+ *	dtDelete()
+ *
+ * function: delete the entry(s) referenced by a key.
+ *
+ * parameter:
+ *
+ * return:
+ */
+int dtDelete(tid_t tid,
+	 struct inode *ip, component_t * key, ino_t * ino, int flag)
+{
+	int rc = 0;
+	s64 bn;
+	metapage_t *mp, *imp;
+	dtpage_t *p;
+	int index;
+	btstack_t btstack;
+	dtlock_t *dtlck;
+	tlock_t *tlck;
+	lv_t *lv;
+	int i;
+	ldtentry_t *ldtentry;
+	u8 *stbl;
+	u32 table_index, next_index;
+	metapage_t *nmp;
+	dtpage_t *np;
+
+	/*
+	 *      search for the entry to delete:
+	 *
+	 * dtSearch() returns (leaf page pinned, index at which to delete).
+	 */
+	if ((rc = dtSearch(ip, key, ino, &btstack, flag)))
+		return rc;
+
+	/* retrieve search result */
+	DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	/*
+	 * We need to find put the index of the next entry into the
+	 * directory index table in order to resume a readdir from this
+	 * entry.
+	 */
+	if (DO_INDEX(ip)) {
+		stbl = DT_GETSTBL(p);
+		ldtentry = (ldtentry_t *) & p->slot[stbl[index]];
+		table_index = le32_to_cpu(ldtentry->index);
+		if (index == (p->header.nextindex - 1)) {
+			/*
+			 * Last entry in this leaf page
+			 */
+			if ((p->header.flag & BT_ROOT)
+			    || (p->header.next == 0))
+				next_index = -1;
+			else {
+				/* Read next leaf page */
+				DT_GETPAGE(ip, le64_to_cpu(p->header.next),
+					   nmp, PSIZE, np, rc);
+				if (rc)
+					next_index = -1;
+				else {
+					stbl = DT_GETSTBL(np);
+					ldtentry =
+					    (ldtentry_t *) & np->
+					    slot[stbl[0]];
+					next_index =
+					    le32_to_cpu(ldtentry->index);
+					DT_PUTPAGE(nmp);
+				}
+			}
+		} else {
+			ldtentry =
+			    (ldtentry_t *) & p->slot[stbl[index + 1]];
+			next_index = le32_to_cpu(ldtentry->index);
+		}
+		free_index(tid, ip, table_index, next_index);
+	}
+	/*
+	 * the leaf page becomes empty, delete the page
+	 */
+	if (p->header.nextindex == 1) {
+		/* delete empty page */
+		rc = dtDeleteUp(tid, ip, mp, p, &btstack);
+	}
+	/*
+	 * the leaf page has other entries remaining:
+	 *
+	 * delete the entry from the leaf page.
+	 */
+	else {
+		BT_MARK_DIRTY(mp, ip);
+		/*
+		 * acquire a transaction lock on the leaf page
+		 */
+		tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+		dtlck = (dtlock_t *) & tlck->lock;
+
+		/*
+		 * Do not assume that dtlck->index will be zero.  During a
+		 * rename within a directory, this transaction may have
+		 * modified this page already when adding the new entry.
+		 */
+
+		/* linelock header */
+		if (dtlck->index >= dtlck->maxcnt)
+			dtlck = (dtlock_t *) txLinelock(dtlck);
+		lv = (lv_t *) & dtlck->lv[dtlck->index];
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+
+		/* linelock stbl of non-root leaf page */
+		if (!(p->header.flag & BT_ROOT)) {
+			if (dtlck->index >= dtlck->maxcnt)
+				dtlck = (dtlock_t *) txLinelock(dtlck);
+			lv = (lv_t *) & dtlck->lv[dtlck->index];
+			i = index >> L2DTSLOTSIZE;
+			lv->offset = p->header.stblindex + i;
+			lv->length =
+			    ((p->header.nextindex - 1) >> L2DTSLOTSIZE) -
+			    i + 1;
+			dtlck->index++;
+		}
+
+		/* free the leaf entry */
+		dtDeleteEntry(p, index, &dtlck);
+
+		/*
+		 * Update directory index table for entries moved in stbl
+		 */
+		if (DO_INDEX(ip) && index < p->header.nextindex) {
+			imp = 0;
+			stbl = DT_GETSTBL(p);
+			for (i = index; i < p->header.nextindex; i++) {
+				ldtentry =
+				    (ldtentry_t *) & p->slot[stbl[i]];
+				modify_index(tid, ip,
+					     le32_to_cpu(ldtentry->index),
+					     bn, i, &imp);
+			}
+			if (imp)
+				release_metapage(imp);
+		}
+
+		DT_PUTPAGE(mp);
+	}
+
+	return rc;
+}
+
+
+/*
+ *	dtDeleteUp()
+ *
+ * function:
+ *	free empty pages as propagating deletion up the tree
+ *
+ * parameter:
+ *
+ * return:
+ */
+static int dtDeleteUp(tid_t tid, struct inode *ip,
+	   metapage_t * fmp, dtpage_t * fp, btstack_t * btstack)
+{
+	int rc = 0;
+	metapage_t *mp;
+	dtpage_t *p;
+	int index, nextindex;
+	int xlen;
+	btframe_t *parent;
+	dtlock_t *dtlck;
+	tlock_t *tlck;
+	lv_t *lv;
+	pxdlock_t *pxdlock;
+	int i;
+
+	/*
+	 *      keep the root leaf page which has become empty
+	 */
+	if (BT_IS_ROOT(fmp)) {
+		/*
+		 * reset the root
+		 *
+		 * dtInitRoot() acquires txlock on the root
+		 */
+		dtInitRoot(tid, ip, PARENT(ip));
+
+		DT_PUTPAGE(fmp);
+
+		return 0;
+	}
+
+	/*
+	 *      free the non-root leaf page
+	 */
+	/*
+	 * acquire a transaction lock on the page
+	 *
+	 * write FREEXTENT|NOREDOPAGE log record
+	 * N.B. linelock is overlaid as freed extent descriptor, and
+	 * the buffer page is freed;
+	 */
+	tlck = txMaplock(tid, ip, tlckDTREE | tlckFREE);
+	pxdlock = (pxdlock_t *) & tlck->lock;
+	pxdlock->flag = mlckFREEPXD;
+	pxdlock->pxd = fp->header.self;
+	pxdlock->index = 1;
+
+	/* update sibling pointers */
+	if ((rc = dtRelink(tid, ip, fp)))
+		return rc;
+
+	xlen = lengthPXD(&fp->header.self);
+	ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen);
+
+	/* free/invalidate its buffer page */
+	discard_metapage(fmp);
+
+	/*
+	 *      propagate page deletion up the directory tree
+	 *
+	 * If the delete from the parent page makes it empty,
+	 * continue all the way up the tree.
+	 * stop if the root page is reached (which is never deleted) or
+	 * if the entry deletion does not empty the page.
+	 */
+	while ((parent = BT_POP(btstack)) != NULL) {
+		/* pin the parent page <sp> */
+		DT_GETPAGE(ip, parent->bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		/*
+		 * free the extent of the child page deleted
+		 */
+		index = parent->index;
+
+		/*
+		 * delete the entry for the child page from parent
+		 */
+		nextindex = p->header.nextindex;
+
+		/*
+		 * the parent has the single entry being deleted:
+		 *
+		 * free the parent page which has become empty.
+		 */
+		if (nextindex == 1) {
+			/*
+			 * keep the root internal page which has become empty
+			 */
+			if (p->header.flag & BT_ROOT) {
+				/*
+				 * reset the root
+				 *
+				 * dtInitRoot() acquires txlock on the root
+				 */
+				dtInitRoot(tid, ip, PARENT(ip));
+
+				DT_PUTPAGE(mp);
+
+				return 0;
+			}
+			/*
+			 * free the parent page
+			 */
+			else {
+				/*
+				 * acquire a transaction lock on the page
+				 *
+				 * write FREEXTENT|NOREDOPAGE log record
+				 */
+				tlck =
+				    txMaplock(tid, ip,
+					      tlckDTREE | tlckFREE);
+				pxdlock = (pxdlock_t *) & tlck->lock;
+				pxdlock->flag = mlckFREEPXD;
+				pxdlock->pxd = p->header.self;
+				pxdlock->index = 1;
+
+				/* update sibling pointers */
+				if ((rc = dtRelink(tid, ip, p)))
+					return rc;
+
+				xlen = lengthPXD(&p->header.self);
+				ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen);
+
+				/* free/invalidate its buffer page */
+				discard_metapage(mp);
+
+				/* propagate up */
+				continue;
+			}
+		}
+
+		/*
+		 * the parent has other entries remaining:
+		 *
+		 * delete the router entry from the parent page.
+		 */
+		BT_MARK_DIRTY(mp, ip);
+		/*
+		 * acquire a transaction lock on the page
+		 *
+		 * action: router entry deletion
+		 */
+		tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+		dtlck = (dtlock_t *) & tlck->lock;
+
+		/* linelock header */
+		if (dtlck->index >= dtlck->maxcnt)
+			dtlck = (dtlock_t *) txLinelock(dtlck);
+		lv = (lv_t *) & dtlck->lv[dtlck->index];
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+
+		/* linelock stbl of non-root leaf page */
+		if (!(p->header.flag & BT_ROOT)) {
+			if (dtlck->index < dtlck->maxcnt)
+				lv++;
+			else {
+				dtlck = (dtlock_t *) txLinelock(dtlck);
+				lv = (lv_t *) & dtlck->lv[0];
+			}
+			i = index >> L2DTSLOTSIZE;
+			lv->offset = p->header.stblindex + i;
+			lv->length =
+			    ((p->header.nextindex - 1) >> L2DTSLOTSIZE) -
+			    i + 1;
+			dtlck->index++;
+		}
+
+		/* free the router entry */
+		dtDeleteEntry(p, index, &dtlck);
+
+		/* reset key of new leftmost entry of level (for consistency) */
+		if (index == 0 &&
+		    ((p->header.flag & BT_ROOT) || p->header.prev == 0))
+			dtTruncateEntry(p, 0, &dtlck);
+
+		/* unpin the parent page */
+		DT_PUTPAGE(mp);
+
+		/* exit propagation up */
+		break;
+	}
+
+	return 0;
+}
+
+
+/*
+ * NAME:        dtRelocate()
+ *
+ * FUNCTION:    relocate dtpage (internal or leaf) of directory;
+ *              This function is mainly used by defragfs utility.
+ */
+int dtRelocate(tid_t tid, struct inode *ip, s64 lmxaddr, pxd_t * opxd,
+	       s64 nxaddr)
+{
+	int rc = 0;
+	metapage_t *mp, *pmp, *lmp, *rmp;
+	dtpage_t *p, *pp, *rp = 0, *lp= 0;
+	s64 bn;
+	int index;
+	btstack_t btstack;
+	pxd_t *pxd;
+	s64 oxaddr, nextbn, prevbn;
+	int xlen, xsize;
+	tlock_t *tlck;
+	dtlock_t *dtlck;
+	pxdlock_t *pxdlock;
+	s8 *stbl;
+	lv_t *lv;
+
+	oxaddr = addressPXD(opxd);
+	xlen = lengthPXD(opxd);
+
+	jEVENT(0, ("dtRelocate: lmxaddr:%Ld xaddr:%Ld:%Ld xlen:%d\n",
+		   lmxaddr, oxaddr, nxaddr, xlen));
+
+	/*
+	 *      1. get the internal parent dtpage covering
+	 *      router entry for the tartget page to be relocated;
+	 */
+	rc = dtSearchNode(ip, lmxaddr, opxd, &btstack);
+	if (rc)
+		return rc;
+
+	/* retrieve search result */
+	DT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
+	jEVENT(0, ("dtRelocate: parent router entry validated.\n"));
+
+	/*
+	 *      2. relocate the target dtpage
+	 */
+	/* read in the target page from src extent */
+	DT_GETPAGE(ip, oxaddr, mp, PSIZE, p, rc);
+	if (rc) {
+		/* release the pinned parent page */
+		DT_PUTPAGE(pmp);
+		return rc;
+	}
+
+	/*
+	 * read in sibling pages if any to update sibling pointers;
+	 */
+	rmp = NULL;
+	if (p->header.next) {
+		nextbn = le64_to_cpu(p->header.next);
+		DT_GETPAGE(ip, nextbn, rmp, PSIZE, rp, rc);
+		if (rc) {
+			DT_PUTPAGE(mp);
+			DT_PUTPAGE(pmp);
+			return (rc);
+		}
+	}
+
+	lmp = NULL;
+	if (p->header.prev) {
+		prevbn = le64_to_cpu(p->header.prev);
+		DT_GETPAGE(ip, prevbn, lmp, PSIZE, lp, rc);
+		if (rc) {
+			DT_PUTPAGE(mp);
+			DT_PUTPAGE(pmp);
+			if (rmp)
+				DT_PUTPAGE(rmp);
+			return (rc);
+		}
+	}
+
+	/* at this point, all xtpages to be updated are in memory */
+
+	/*
+	 * update sibling pointers of sibling dtpages if any;
+	 */
+	if (lmp) {
+		tlck = txLock(tid, ip, lmp, tlckDTREE | tlckRELINK);
+		dtlck = (dtlock_t *) & tlck->lock;
+		/* linelock header */
+		ASSERT(dtlck->index == 0);
+		lv = (lv_t *) & dtlck->lv[0];
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+
+		lp->header.next = cpu_to_le64(nxaddr);
+		DT_PUTPAGE(lmp);
+	}
+
+	if (rmp) {
+		tlck = txLock(tid, ip, rmp, tlckDTREE | tlckRELINK);
+		dtlck = (dtlock_t *) & tlck->lock;
+		/* linelock header */
+		ASSERT(dtlck->index == 0);
+		lv = (lv_t *) & dtlck->lv[0];
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+
+		rp->header.prev = cpu_to_le64(nxaddr);
+		DT_PUTPAGE(rmp);
+	}
+
+	/*
+	 * update the target dtpage to be relocated
+	 *
+	 * write LOG_REDOPAGE of LOG_NEW type for dst page
+	 * for the whole target page (logredo() will apply
+	 * after image and update bmap for allocation of the
+	 * dst extent), and update bmap for allocation of
+	 * the dst extent;
+	 */
+	tlck = txLock(tid, ip, mp, tlckDTREE | tlckNEW);
+	dtlck = (dtlock_t *) & tlck->lock;
+	/* linelock header */
+	ASSERT(dtlck->index == 0);
+	lv = (lv_t *) & dtlck->lv[0];
+
+	/* update the self address in the dtpage header */
+	pxd = &p->header.self;
+	PXDaddress(pxd, nxaddr);
+
+	/* the dst page is the same as the src page, i.e.,
+	 * linelock for afterimage of the whole page;
+	 */
+	lv->offset = 0;
+	lv->length = p->header.maxslot;
+	dtlck->index++;
+
+	/* update the buffer extent descriptor of the dtpage */
+	xsize = xlen << JFS_SBI(ip->i_sb)->l2bsize;
+#ifdef _STILL_TO_PORT
+	bmSetXD(mp, nxaddr, xsize);
+#endif /* _STILL_TO_PORT */
+	/* unpin the relocated page */
+	DT_PUTPAGE(mp);
+	jEVENT(0, ("dtRelocate: target dtpage relocated.\n"));
+
+	/* the moved extent is dtpage, then a LOG_NOREDOPAGE log rec
+	 * needs to be written (in logredo(), the LOG_NOREDOPAGE log rec
+	 * will also force a bmap update ).
+	 */
+
+	/*
+	 *      3. acquire maplock for the source extent to be freed;
+	 */
+	/* for dtpage relocation, write a LOG_NOREDOPAGE record
+	 * for the source dtpage (logredo() will init NoRedoPage
+	 * filter and will also update bmap for free of the source
+	 * dtpage), and upadte bmap for free of the source dtpage;
+	 */
+	tlck = txMaplock(tid, ip, tlckDTREE | tlckFREE);
+	pxdlock = (pxdlock_t *) & tlck->lock;
+	pxdlock->flag = mlckFREEPXD;
+	PXDaddress(&pxdlock->pxd, oxaddr);
+	PXDlength(&pxdlock->pxd, xlen);
+	pxdlock->index = 1;
+
+	/*
+	 *      4. update the parent router entry for relocation;
+	 *
+	 * acquire tlck for the parent entry covering the target dtpage;
+	 * write LOG_REDOPAGE to apply after image only;
+	 */
+	jEVENT(0, ("dtRelocate: update parent router entry.\n"));
+	tlck = txLock(tid, ip, pmp, tlckDTREE | tlckENTRY);
+	dtlck = (dtlock_t *) & tlck->lock;
+	lv = (lv_t *) & dtlck->lv[dtlck->index];
+
+	/* update the PXD with the new address */
+	stbl = DT_GETSTBL(pp);
+	pxd = (pxd_t *) & pp->slot[stbl[index]];
+	PXDaddress(pxd, nxaddr);
+	lv->offset = stbl[index];
+	lv->length = 1;
+	dtlck->index++;
+
+	/* unpin the parent dtpage */
+	DT_PUTPAGE(pmp);
+
+	return rc;
+}
+
+
+/*
+ * NAME:	dtSearchNode()
+ *
+ * FUNCTION:	Search for an dtpage containing a specified address
+ *              This function is mainly used by defragfs utility.
+ *
+ * NOTE:	Search result on stack, the found page is pinned at exit.
+ *		The result page must be an internal dtpage.
+ *		lmxaddr give the address of the left most page of the
+ *		dtree level, in which the required dtpage resides.
+ */
+static int dtSearchNode(struct inode *ip, s64 lmxaddr, pxd_t * kpxd,
+			btstack_t * btstack)
+{
+	int rc = 0;
+	s64 bn;
+	metapage_t *mp;
+	dtpage_t *p;
+	int psize = 288;	/* initial in-line directory */
+	s8 *stbl;
+	int i;
+	pxd_t *pxd;
+	btframe_t *btsp;
+
+	BT_CLR(btstack);	/* reset stack */
+
+	/*
+	 *      descend tree to the level with specified leftmost page
+	 *
+	 *  by convention, root bn = 0.
+	 */
+	for (bn = 0;;) {
+		/* get/pin the page to search */
+		DT_GETPAGE(ip, bn, mp, psize, p, rc);
+		if (rc)
+			return rc;
+
+		/* does the xaddr of leftmost page of the levevl
+		 * matches levevl search key ?
+		 */
+		if (p->header.flag & BT_ROOT) {
+			if (lmxaddr == 0)
+				break;
+		} else if (addressPXD(&p->header.self) == lmxaddr)
+			break;
+
+		/*
+		 * descend down to leftmost child page
+		 */
+		if (p->header.flag & BT_LEAF)
+			return ESTALE;
+
+		/* get the leftmost entry */
+		stbl = DT_GETSTBL(p);
+		pxd = (pxd_t *) & p->slot[stbl[0]];
+
+		/* get the child page block address */
+		bn = addressPXD(pxd);
+		psize = lengthPXD(pxd) << JFS_SBI(ip->i_sb)->l2bsize;
+		/* unpin the parent page */
+		DT_PUTPAGE(mp);
+	}
+
+	/*
+	 *      search each page at the current levevl
+	 */
+      loop:
+	stbl = DT_GETSTBL(p);
+	for (i = 0; i < p->header.nextindex; i++) {
+		pxd = (pxd_t *) & p->slot[stbl[i]];
+
+		/* found the specified router entry */
+		if (addressPXD(pxd) == addressPXD(kpxd) &&
+		    lengthPXD(pxd) == lengthPXD(kpxd)) {
+			btsp = btstack->top;
+			btsp->bn = bn;
+			btsp->index = i;
+			btsp->mp = mp;
+
+			return 0;
+		}
+	}
+
+	/* get the right sibling page if any */
+	if (p->header.next)
+		bn = le64_to_cpu(p->header.next);
+	else {
+		DT_PUTPAGE(mp);
+		return ESTALE;
+	}
+
+	/* unpin current page */
+	DT_PUTPAGE(mp);
+
+	/* get the right sibling page */
+	DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	goto loop;
+}
+
+
+/*
+ *	dtRelink()
+ *
+ * function:
+ *	link around a freed page.
+ *
+ * parameter:
+ *	fp:	page to be freed
+ *
+ * return:
+ */
+static int dtRelink(tid_t tid, struct inode *ip, dtpage_t * p)
+{
+	int rc;
+	metapage_t *mp;
+	s64 nextbn, prevbn;
+	tlock_t *tlck;
+	dtlock_t *dtlck;
+	lv_t *lv;
+
+	nextbn = le64_to_cpu(p->header.next);
+	prevbn = le64_to_cpu(p->header.prev);
+
+	/* update prev pointer of the next page */
+	if (nextbn != 0) {
+		DT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		BT_MARK_DIRTY(mp, ip);
+		/*
+		 * acquire a transaction lock on the next page
+		 *
+		 * action: update prev pointer;
+		 */
+		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);
+		jEVENT(0,
+		       ("dtRelink nextbn: tlck = 0x%p, ip = 0x%p, mp=0x%p\n",
+			tlck, ip, mp));
+		dtlck = (dtlock_t *) & tlck->lock;
+
+		/* linelock header */
+		if (dtlck->index >= dtlck->maxcnt)
+			dtlck = (dtlock_t *) txLinelock(dtlck);
+		lv = (lv_t *) & dtlck->lv[dtlck->index];
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+
+		p->header.prev = cpu_to_le64(prevbn);
+		DT_PUTPAGE(mp);
+	}
+
+	/* update next pointer of the previous page */
+	if (prevbn != 0) {
+		DT_GETPAGE(ip, prevbn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		BT_MARK_DIRTY(mp, ip);
+		/*
+		 * acquire a transaction lock on the prev page
+		 *
+		 * action: update next pointer;
+		 */
+		tlck = txLock(tid, ip, mp, tlckDTREE | tlckRELINK);
+		jEVENT(0,
+		       ("dtRelink prevbn: tlck = 0x%p, ip = 0x%p, mp=0x%p\n",
+			tlck, ip, mp));
+		dtlck = (dtlock_t *) & tlck->lock;
+
+		/* linelock header */
+		if (dtlck->index >= dtlck->maxcnt)
+			dtlck = (dtlock_t *) txLinelock(dtlck);
+		lv = (lv_t *) & dtlck->lv[dtlck->index];
+		lv->offset = 0;
+		lv->length = 1;
+		dtlck->index++;
+
+		p->header.next = cpu_to_le64(nextbn);
+		DT_PUTPAGE(mp);
+	}
+
+	return 0;
+}
+
+
+/*
+ *	dtInitRoot()
+ *
+ * initialize directory root (inline in inode)
+ */
+void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	dtroot_t *p;
+	int fsi;
+	dtslot_t *f;
+	tlock_t *tlck;
+	dtlock_t *dtlck;
+	lv_t *lv;
+	u16 xflag_save;
+
+	/*
+	 * If this was previously an non-empty directory, we need to remove
+	 * the old directory table.
+	 */
+	if (DO_INDEX(ip)) {
+		if (jfs_ip->next_index > (MAX_INLINE_DIRTABLE_ENTRY + 1)) {
+			tblock_t *tblk = tid_to_tblock(tid);
+			/*
+			 * We're playing games with the tid's xflag.  If
+			 * we're removing a regular file, the file's xtree
+			 * is committed with COMMIT_PMAP, but we always
+			 * commit the directories xtree with COMMIT_PWMAP.
+			 */
+			xflag_save = tblk->xflag;
+			tblk->xflag = 0;
+			/*
+			 * xtTruncate isn't guaranteed to fully truncate
+			 * the xtree.  The caller needs to check i_size
+			 * after committing the transaction to see if
+			 * additional truncation is needed.  The
+			 * COMMIT_Stale flag tells caller that we
+			 * initiated the truncation.
+			 */
+			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
+			set_cflag(COMMIT_Stale, ip);
+
+			tblk->xflag = xflag_save;
+			/*
+			 * Tells jfs_metapage code that the metadata pages
+			 * for the index table are no longer useful, and
+			 * remove them from page cache.
+			 */
+			invalidate_inode_metapages(ip);
+		} else
+			ip->i_size = 1;
+
+		jfs_ip->next_index = 2;
+	} else
+		ip->i_size = IDATASIZE;
+
+	/*
+	 * acquire a transaction lock on the root
+	 *
+	 * action: directory initialization;
+	 */
+	tlck = txLock(tid, ip, (metapage_t *) & jfs_ip->bxflag,
+		      tlckDTREE | tlckENTRY | tlckBTROOT);
+	dtlck = (dtlock_t *) & tlck->lock;
+
+	/* linelock root */
+	ASSERT(dtlck->index == 0);
+	lv = (lv_t *) & dtlck->lv[0];
+	lv->offset = 0;
+	lv->length = DTROOTMAXSLOT;
+	dtlck->index++;
+
+	p = &jfs_ip->i_dtroot;
+
+	p->header.flag = DXD_INDEX | BT_ROOT | BT_LEAF;
+
+	p->header.nextindex = 0;
+
+	/* init freelist */
+	fsi = 1;
+	f = &p->slot[fsi];
+
+	/* init data area of root */
+	for (fsi++; fsi < DTROOTMAXSLOT; f++, fsi++)
+		f->next = fsi;
+	f->next = -1;
+
+	p->header.freelist = 1;
+	p->header.freecnt = 8;
+
+	/* init '..' entry */
+	p->header.idotdot = cpu_to_le32(idotdot);
+
+#if 0
+	ip->i_blocks = LBLK2PBLK(ip->i_sb,
+				 ((jfs_ip->ea.flag & DXD_EXTENT) ?
+				  lengthDXD(&jfs_ip->ea) : 0) +
+				 ((jfs_ip->acl.flag & DXD_EXTENT) ?
+				  lengthDXD(&jfs_ip->acl) : 0));
+#endif
+
+	return;
+}
+
+/*
+ *	jfs_readdir()
+ *
+ * function: read directory entries sequentially
+ *	from the specified entry offset
+ *
+ * parameter:
+ *
+ * return: offset = (pn, index) of start entry
+ *	of next jfs_readdir()/dtRead()
+ */
+int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+	struct inode *ip = filp->f_dentry->d_inode;
+	struct nls_table *codepage = JFS_SBI(ip->i_sb)->nls_tab;
+	int rc = 0;
+	struct dtoffset {
+		s16 pn;
+		s16 index;
+		s32 unused;
+	} *dtoffset = (struct dtoffset *) &filp->f_pos;
+	s64 bn;
+	metapage_t *mp;
+	dtpage_t *p;
+	int index;
+	s8 *stbl;
+	btstack_t btstack;
+	int i, next;
+	ldtentry_t *d;
+	dtslot_t *t;
+	int d_namleft, d_namlen, len, outlen;
+	char *d_name, *name_ptr;
+	int dtlhdrdatalen;
+	u32 dir_index;
+	int do_index = 0;
+	uint loop_count = 0;
+
+	if (filp->f_pos == -1)
+		return 0;
+
+	if (DO_INDEX(ip)) {
+		/*
+		 * persistent index is stored in directory entries.
+		 * Special cases:        0 = .
+		 *                       1 = ..
+		 *                      -1 = End of directory
+		 */
+		do_index = 1;
+		dtlhdrdatalen = DTLHDRDATALEN;
+
+		dir_index = (u32) filp->f_pos;
+
+		if (dir_index > 1) {
+			dir_table_slot_t dirtab_slot;
+
+			if (dtEmpty(ip)) {
+				filp->f_pos = -1;
+				return 0;
+			}
+		      repeat:
+			rc = get_index(ip, dir_index, &dirtab_slot);
+			if (rc) {
+				filp->f_pos = -1;
+				return rc;
+			}
+			if (dirtab_slot.flag == DIR_INDEX_FREE) {
+				if (loop_count++ > JFS_IP(ip)->next_index) {
+					jERROR(1, ("jfs_readdir detected "
+						   "infinite loop!\n"));
+					filp->f_pos = -1;
+					return 0;
+				}
+				dir_index = le32_to_cpu(dirtab_slot.addr2);
+				if (dir_index == -1) {
+					filp->f_pos = -1;
+					return 0;
+				}
+				goto repeat;
+			}
+			bn = addressDTS(&dirtab_slot);
+			index = dirtab_slot.slot;
+			DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+			if (rc) {
+				filp->f_pos = -1;
+				return 0;
+			}
+			if (p->header.flag & BT_INTERNAL) {
+				jERROR(1,("jfs_readdir: bad index table\n"));
+				DT_PUTPAGE(mp);
+				filp->f_pos = -1;
+				return 0;
+			}
+			if (p->header.flag & BT_INTERNAL) {
+				jERROR(1,("jfs_readdir: bad index table\n"));
+				DT_PUTPAGE(mp);
+				filp->f_pos = -1;
+				return 0;
+			}
+		} else {
+			if (dir_index == 0) {
+				/*
+				 * self "."
+				 */
+				filp->f_pos = 0;
+				if (filldir(dirent, ".", 1, 0, ip->i_ino,
+					    DT_DIR))
+					return 0;
+			}
+			/*
+			 * parent ".."
+			 */
+			filp->f_pos = 1;
+			if (filldir
+			    (dirent, "..", 2, 1, PARENT(ip), DT_DIR))
+				return 0;
+
+			/*
+			 * Find first entry of left-most leaf
+			 */
+			if (dtEmpty(ip)) {
+				filp->f_pos = -1;
+				return 0;
+			}
+
+			if ((rc = dtReadFirst(ip, &btstack)))
+				return -rc;
+
+			DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+		}
+	} else {
+		/*
+		 * Legacy filesystem - OS/2 & Linux JFS < 0.3.6
+		 *
+		 * pn = index = 0:      First entry "."
+		 * pn = 0; index = 1:   Second entry ".."
+		 * pn > 0:              Real entries, pn=1 -> leftmost page
+		 * pn = index = -1:     No more entries
+		 */
+		dtlhdrdatalen = DTLHDRDATALEN_LEGACY;
+
+		if (filp->f_pos == 0) {
+			/* build "." entry */
+
+			if (filldir(dirent, ".", 1, filp->f_pos, ip->i_ino,
+				    DT_DIR))
+				return 0;
+			dtoffset->index = 1;
+		}
+
+		if (dtoffset->pn == 0) {
+			if (dtoffset->index == 1) {
+				/* build ".." entry */
+
+				if (filldir(dirent, "..", 2, filp->f_pos,
+					    PARENT(ip), DT_DIR))
+					return 0;
+			} else {
+				jERROR(1,
+				       ("jfs_readdir called with invalid offset!\n"));
+			}
+			dtoffset->pn = 1;
+			dtoffset->index = 0;
+		}
+
+		if (dtEmpty(ip)) {
+			filp->f_pos = -1;
+			return 0;
+		}
+
+		if ((rc = dtReadNext(ip, &filp->f_pos, &btstack))) {
+			jERROR(1,
+			       ("jfs_readdir: unexpected rc = %d from dtReadNext\n",
+				rc));
+			filp->f_pos = -1;
+			return 0;
+		}
+		/* get start leaf page and index */
+		DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+		/* offset beyond directory eof ? */
+		if (bn < 0) {
+			filp->f_pos = -1;
+			return 0;
+		}
+	}
+
+	d_name = kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t), GFP_NOFS);
+	if (d_name == NULL) {
+		DT_PUTPAGE(mp);
+		jERROR(1, ("jfs_readdir: kmalloc failed!\n"));
+		filp->f_pos = -1;
+		return 0;
+	}
+	while (1) {
+		stbl = DT_GETSTBL(p);
+
+		for (i = index; i < p->header.nextindex; i++) {
+			d = (ldtentry_t *) & p->slot[stbl[i]];
+
+			d_namleft = d->namlen;
+			name_ptr = d_name;
+
+			if (do_index) {
+				filp->f_pos = le32_to_cpu(d->index);
+				len = min(d_namleft, DTLHDRDATALEN);
+			} else
+				len = min(d_namleft, DTLHDRDATALEN_LEGACY);
+
+			/* copy the name of head/only segment */
+			outlen = jfs_strfromUCS_le(name_ptr, d->name, len,
+						   codepage);
+			d_namlen = outlen;
+
+			/* copy name in the additional segment(s) */
+			next = d->next;
+			while (next >= 0) {
+				t = (dtslot_t *) & p->slot[next];
+				name_ptr += outlen;
+				d_namleft -= len;
+				len = min(d_namleft, DTSLOTDATALEN);
+				outlen = jfs_strfromUCS_le(name_ptr, t->name,
+							   len, codepage);
+				d_namlen+= outlen;
+
+				next = t->next;
+			}
+
+			if (filldir(dirent, d_name, d_namlen, filp->f_pos,
+				    le32_to_cpu(d->inumber), DT_UNKNOWN))
+				goto out;
+			if (!do_index)
+				dtoffset->index++;
+		}
+
+		/*
+		 * get next leaf page
+		 */
+
+		if (p->header.flag & BT_ROOT) {
+			filp->f_pos = -1;
+			break;
+		}
+
+		bn = le64_to_cpu(p->header.next);
+		if (bn == 0) {
+			filp->f_pos = -1;
+			break;
+		}
+
+		/* unpin previous leaf page */
+		DT_PUTPAGE(mp);
+
+		/* get next leaf page */
+		DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc) {
+			kfree(d_name);
+			return -rc;
+		}
+
+		/* update offset (pn:index) for new page */
+		index = 0;
+		if (!do_index) {
+			dtoffset->pn++;
+			dtoffset->index = 0;
+		}
+
+	}
+
+      out:
+	kfree(d_name);
+	DT_PUTPAGE(mp);
+
+	return rc;
+}
+
+
+/*
+ *	dtReadFirst()
+ *
+ * function: get the leftmost page of the directory
+ */
+static int dtReadFirst(struct inode *ip, btstack_t * btstack)
+{
+	int rc = 0;
+	s64 bn;
+	int psize = 288;	/* initial in-line directory */
+	metapage_t *mp;
+	dtpage_t *p;
+	s8 *stbl;
+	btframe_t *btsp;
+	pxd_t *xd;
+
+	BT_CLR(btstack);	/* reset stack */
+
+	/*
+	 *      descend leftmost path of the tree
+	 *
+	 * by convention, root bn = 0.
+	 */
+	for (bn = 0;;) {
+		DT_GETPAGE(ip, bn, mp, psize, p, rc);
+		if (rc)
+			return rc;
+
+		/*
+		 * leftmost leaf page
+		 */
+		if (p->header.flag & BT_LEAF) {
+			/* return leftmost entry */
+			btsp = btstack->top;
+			btsp->bn = bn;
+			btsp->index = 0;
+			btsp->mp = mp;
+
+			return 0;
+		}
+
+		/*
+		 * descend down to leftmost child page
+		 */
+		/* push (bn, index) of the parent page/entry */
+		BT_PUSH(btstack, bn, 0);
+
+		/* get the leftmost entry */
+		stbl = DT_GETSTBL(p);
+		xd = (pxd_t *) & p->slot[stbl[0]];
+
+		/* get the child page block address */
+		bn = addressPXD(xd);
+		psize = lengthPXD(xd) << JFS_SBI(ip->i_sb)->l2bsize;
+
+		/* unpin the parent page */
+		DT_PUTPAGE(mp);
+	}
+}
+
+
+/*
+ *	dtReadNext()
+ *
+ * function: get the page of the specified offset (pn:index)
+ *
+ * return: if (offset > eof), bn = -1;
+ *
+ * note: if index > nextindex of the target leaf page,
+ * start with 1st entry of next leaf page;
+ */
+static int dtReadNext(struct inode *ip, loff_t * offset, btstack_t * btstack)
+{
+	int rc = 0;
+	struct dtoffset {
+		s16 pn;
+		s16 index;
+		s32 unused;
+	} *dtoffset = (struct dtoffset *) offset;
+	s64 bn;
+	metapage_t *mp;
+	dtpage_t *p;
+	int index;
+	int pn;
+	s8 *stbl;
+	btframe_t *btsp, *parent;
+	pxd_t *xd;
+
+	/*
+	 * get leftmost leaf page pinned
+	 */
+	if ((rc = dtReadFirst(ip, btstack)))
+		return rc;
+
+	/* get leaf page */
+	DT_GETSEARCH(ip, btstack->top, bn, mp, p, index);
+
+	/* get the start offset (pn:index) */
+	pn = dtoffset->pn - 1;	/* Now pn = 0 represents leftmost leaf */
+	index = dtoffset->index;
+
+	/* start at leftmost page ? */
+	if (pn == 0) {
+		/* offset beyond eof ? */
+		if (index < p->header.nextindex)
+			goto out;
+
+		if (p->header.flag & BT_ROOT) {
+			bn = -1;
+			goto out;
+		}
+
+		/* start with 1st entry of next leaf page */
+		dtoffset->pn++;
+		dtoffset->index = index = 0;
+		goto a;
+	}
+
+	/* start at non-leftmost page: scan parent pages for large pn */
+	if (p->header.flag & BT_ROOT) {
+		bn = -1;
+		goto out;
+	}
+
+	/* start after next leaf page ? */
+	if (pn > 1)
+		goto b;
+
+	/* get leaf page pn = 1 */
+      a:
+	bn = le64_to_cpu(p->header.next);
+
+	/* unpin leaf page */
+	DT_PUTPAGE(mp);
+
+	/* offset beyond eof ? */
+	if (bn == 0) {
+		bn = -1;
+		goto out;
+	}
+
+	goto c;
+
+	/*
+	 * scan last internal page level to get target leaf page
+	 */
+      b:
+	/* unpin leftmost leaf page */
+	DT_PUTPAGE(mp);
+
+	/* get left most parent page */
+	btsp = btstack->top;
+	parent = btsp - 1;
+	bn = parent->bn;
+	DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	/* scan parent pages at last internal page level */
+	while (pn >= p->header.nextindex) {
+		pn -= p->header.nextindex;
+
+		/* get next parent page address */
+		bn = le64_to_cpu(p->header.next);
+
+		/* unpin current parent page */
+		DT_PUTPAGE(mp);
+
+		/* offset beyond eof ? */
+		if (bn == 0) {
+			bn = -1;
+			goto out;
+		}
+
+		/* get next parent page */
+		DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		/* update parent page stack frame */
+		parent->bn = bn;
+	}
+
+	/* get leaf page address */
+	stbl = DT_GETSTBL(p);
+	xd = (pxd_t *) & p->slot[stbl[pn]];
+	bn = addressPXD(xd);
+
+	/* unpin parent page */
+	DT_PUTPAGE(mp);
+
+	/*
+	 * get target leaf page
+	 */
+      c:
+	DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	/*
+	 * leaf page has been completed:
+	 * start with 1st entry of next leaf page
+	 */
+	if (index >= p->header.nextindex) {
+		bn = le64_to_cpu(p->header.next);
+
+		/* unpin leaf page */
+		DT_PUTPAGE(mp);
+
+		/* offset beyond eof ? */
+		if (bn == 0) {
+			bn = -1;
+			goto out;
+		}
+
+		/* get next leaf page */
+		DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		/* start with 1st entry of next leaf page */
+		dtoffset->pn++;
+		dtoffset->index = 0;
+	}
+
+      out:
+	/* return target leaf page pinned */
+	btsp = btstack->top;
+	btsp->bn = bn;
+	btsp->index = dtoffset->index;
+	btsp->mp = mp;
+
+	return 0;
+}
+
+
+/*
+ *	dtCompare()
+ *
+ * function: compare search key with an internal entry
+ *
+ * return:
+ *	< 0 if k is < record
+ *	= 0 if k is = record
+ *	> 0 if k is > record
+ */
+static int dtCompare(component_t * key,	/* search key */
+		     dtpage_t * p,	/* directory page */
+		     int si)
+{				/* entry slot index */
+	register int rc;
+	register wchar_t *kname, *name;
+	register int klen, namlen, len;
+	idtentry_t *ih;
+	dtslot_t *t;
+
+	/*
+	 * force the left-most key on internal pages, at any level of
+	 * the tree, to be less than any search key.
+	 * this obviates having to update the leftmost key on an internal
+	 * page when the user inserts a new key in the tree smaller than
+	 * anything that has been stored.
+	 *
+	 * (? if/when dtSearch() narrows down to 1st entry (index = 0),
+	 * at any internal page at any level of the tree,
+	 * it descends to child of the entry anyway -
+	 * ? make the entry as min size dummy entry)
+	 *
+	 * if (e->index == 0 && h->prevpg == P_INVALID && !(h->flags & BT_LEAF))
+	 * return (1);
+	 */
+
+	kname = key->name;
+	klen = key->namlen;
+
+	ih = (idtentry_t *) & p->slot[si];
+	si = ih->next;
+	name = ih->name;
+	namlen = ih->namlen;
+	len = min(namlen, DTIHDRDATALEN);
+
+	/* compare with head/only segment */
+	len = min(klen, len);
+	if ((rc = UniStrncmp_le(kname, name, len)))
+		return rc;
+
+	klen -= len;
+	namlen -= len;
+
+	/* compare with additional segment(s) */
+	kname += len;
+	while (klen > 0 && namlen > 0) {
+		/* compare with next name segment */
+		t = (dtslot_t *) & p->slot[si];
+		len = min(namlen, DTSLOTDATALEN);
+		len = min(klen, len);
+		name = t->name;
+		if ((rc = UniStrncmp_le(kname, name, len)))
+			return rc;
+
+		klen -= len;
+		namlen -= len;
+		kname += len;
+		si = t->next;
+	}
+
+	return (klen - namlen);
+}
+
+
+
+
+/*
+ *	ciCompare()
+ *
+ * function: compare search key with an (leaf/internal) entry
+ *
+ * return:
+ *	< 0 if k is < record
+ *	= 0 if k is = record
+ *	> 0 if k is > record
+ */
+static int ciCompare(component_t * key,	/* search key */
+		     dtpage_t * p,	/* directory page */
+		     int si,	/* entry slot index */
+		     int flag)
+{
+	register int rc;
+	register wchar_t *kname, *name, x;
+	register int klen, namlen, len;
+	ldtentry_t *lh;
+	idtentry_t *ih;
+	dtslot_t *t;
+	int i;
+
+	/*
+	 * force the left-most key on internal pages, at any level of
+	 * the tree, to be less than any search key.
+	 * this obviates having to update the leftmost key on an internal
+	 * page when the user inserts a new key in the tree smaller than
+	 * anything that has been stored.
+	 *
+	 * (? if/when dtSearch() narrows down to 1st entry (index = 0),
+	 * at any internal page at any level of the tree,
+	 * it descends to child of the entry anyway -
+	 * ? make the entry as min size dummy entry)
+	 *
+	 * if (e->index == 0 && h->prevpg == P_INVALID && !(h->flags & BT_LEAF))
+	 * return (1);
+	 */
+
+	kname = key->name;
+	klen = key->namlen;
+
+	/*
+	 * leaf page entry
+	 */
+	if (p->header.flag & BT_LEAF) {
+		lh = (ldtentry_t *) & p->slot[si];
+		si = lh->next;
+		name = lh->name;
+		namlen = lh->namlen;
+		if (flag & JFS_DIR_INDEX)
+			len = min(namlen, DTLHDRDATALEN);
+		else
+			len = min(namlen, DTLHDRDATALEN_LEGACY);
+	}
+	/*
+	 * internal page entry
+	 */
+	else {
+		ih = (idtentry_t *) & p->slot[si];
+		si = ih->next;
+		name = ih->name;
+		namlen = ih->namlen;
+		len = min(namlen, DTIHDRDATALEN);
+	}
+
+	/* compare with head/only segment */
+	len = min(klen, len);
+	for (i = 0; i < len; i++, kname++, name++) {
+		/* only uppercase if case-insensitive support is on */
+		if ((flag & JFS_OS2) == JFS_OS2)
+			x = UniToupper(le16_to_cpu(*name));
+		else
+			x = le16_to_cpu(*name);
+		if ((rc = *kname - x))
+			return rc;
+	}
+
+	klen -= len;
+	namlen -= len;
+
+	/* compare with additional segment(s) */
+	while (klen > 0 && namlen > 0) {
+		/* compare with next name segment */
+		t = (dtslot_t *) & p->slot[si];
+		len = min(namlen, DTSLOTDATALEN);
+		len = min(klen, len);
+		name = t->name;
+		for (i = 0; i < len; i++, kname++, name++) {
+			/* only uppercase if case-insensitive support is on */
+			if ((flag & JFS_OS2) == JFS_OS2)
+				x = UniToupper(le16_to_cpu(*name));
+			else
+				x = le16_to_cpu(*name);
+
+			if ((rc = *kname - x))
+				return rc;
+		}
+
+		klen -= len;
+		namlen -= len;
+		si = t->next;
+	}
+
+	return (klen - namlen);
+}
+
+
+/*
+ *	ciGetLeafPrefixKey()
+ *
+ * function: compute prefix of suffix compression
+ *	     from two adjacent leaf entries
+ *	     across page boundary
+ *
+ * return:
+ *	Number of prefix bytes needed to distinguish b from a.
+ */
+static void ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
+			       int ri, component_t * key, int flag)
+{
+	register int klen, namlen;
+	register wchar_t *pl, *pr, *kname;
+	wchar_t lname[JFS_NAME_MAX + 1];
+	component_t lkey = { 0, lname };
+	wchar_t rname[JFS_NAME_MAX + 1];
+	component_t rkey = { 0, rname };
+
+	/* get left and right key */
+	dtGetKey(lp, li, &lkey, flag);
+	lkey.name[lkey.namlen] = 0;
+
+	if ((flag & JFS_OS2) == JFS_OS2)
+		ciToUpper(&lkey);
+
+	dtGetKey(rp, ri, &rkey, flag);
+	rkey.name[rkey.namlen] = 0;
+
+
+	if ((flag & JFS_OS2) == JFS_OS2)
+		ciToUpper(&rkey);
+
+	/* compute prefix */
+	klen = 0;
+	kname = key->name;
+	namlen = min(lkey.namlen, rkey.namlen);
+	for (pl = lkey.name, pr = rkey.name;
+	     namlen; pl++, pr++, namlen--, klen++, kname++) {
+		*kname = *pr;
+		if (*pl != *pr) {
+			key->namlen = klen + 1;
+			return;
+		}
+	}
+
+	/* l->namlen <= r->namlen since l <= r */
+	if (lkey.namlen < rkey.namlen) {
+		*kname = *pr;
+		key->namlen = klen + 1;
+	} else			/* l->namelen == r->namelen */
+		key->namlen = klen;
+
+	return;
+}
+
+
+
+/*
+ *	dtGetKey()
+ *
+ * function: get key of the entry
+ */
+static void dtGetKey(dtpage_t * p, int i,	/* entry index */
+		     component_t * key, int flag)
+{
+	int si;
+	s8 *stbl;
+	ldtentry_t *lh;
+	idtentry_t *ih;
+	dtslot_t *t;
+	int namlen, len;
+	wchar_t *name, *kname;
+
+	/* get entry */
+	stbl = DT_GETSTBL(p);
+	si = stbl[i];
+	if (p->header.flag & BT_LEAF) {
+		lh = (ldtentry_t *) & p->slot[si];
+		si = lh->next;
+		namlen = lh->namlen;
+		name = lh->name;
+		if (flag & JFS_DIR_INDEX)
+			len = min(namlen, DTLHDRDATALEN);
+		else
+			len = min(namlen, DTLHDRDATALEN_LEGACY);
+	} else {
+		ih = (idtentry_t *) & p->slot[si];
+		si = ih->next;
+		namlen = ih->namlen;
+		name = ih->name;
+		len = min(namlen, DTIHDRDATALEN);
+	}
+
+	key->namlen = namlen;
+	kname = key->name;
+
+	/*
+	 * move head/only segment
+	 */
+	UniStrncpy_le(kname, name, len);
+
+	/*
+	 * move additional segment(s)
+	 */
+	while (si >= 0) {
+		/* get next segment */
+		t = &p->slot[si];
+		kname += len;
+		namlen -= len;
+		len = min(namlen, DTSLOTDATALEN);
+		UniStrncpy_le(kname, t->name, len);
+
+		si = t->next;
+	}
+}
+
+
+/*
+ *	dtInsertEntry()
+ *
+ * function: allocate free slot(s) and
+ *	     write a leaf/internal entry
+ *
+ * return: entry slot index
+ */
+static void dtInsertEntry(dtpage_t * p, int index, component_t * key,
+			  ddata_t * data, dtlock_t ** dtlock)
+{
+	dtslot_t *h, *t;
+	ldtentry_t *lh = 0;
+	idtentry_t *ih = 0;
+	int hsi, fsi, klen, len, nextindex;
+	wchar_t *kname, *name;
+	s8 *stbl;
+	pxd_t *xd;
+	dtlock_t *dtlck = *dtlock;
+	lv_t *lv;
+	int xsi, n;
+	s64 bn = 0;
+	metapage_t *mp = 0;
+
+	klen = key->namlen;
+	kname = key->name;
+
+	/* allocate a free slot */
+	hsi = fsi = p->header.freelist;
+	h = &p->slot[fsi];
+	p->header.freelist = h->next;
+	--p->header.freecnt;
+
+	/* open new linelock */
+	if (dtlck->index >= dtlck->maxcnt)
+		dtlck = (dtlock_t *) txLinelock(dtlck);
+
+	lv = (lv_t *) & dtlck->lv[dtlck->index];
+	lv->offset = hsi;
+
+	/* write head/only segment */
+	if (p->header.flag & BT_LEAF) {
+		lh = (ldtentry_t *) h;
+		lh->next = h->next;
+		lh->inumber = data->leaf.ino;	/* little-endian */
+		lh->namlen = klen;
+		name = lh->name;
+		if (data->leaf.ip) {
+			len = min(klen, DTLHDRDATALEN);
+			if (!(p->header.flag & BT_ROOT))
+				bn = addressPXD(&p->header.self);
+			lh->index = cpu_to_le32(add_index(data->leaf.tid,
+							  data->leaf.ip,
+							  bn, index));
+		} else
+			len = min(klen, DTLHDRDATALEN_LEGACY);
+	} else {
+		ih = (idtentry_t *) h;
+		ih->next = h->next;
+		xd = (pxd_t *) ih;
+		*xd = data->xd;
+		ih->namlen = klen;
+		name = ih->name;
+		len = min(klen, DTIHDRDATALEN);
+	}
+
+	UniStrncpy_le(name, kname, len);
+
+	n = 1;
+	xsi = hsi;
+
+	/* write additional segment(s) */
+	t = h;
+	klen -= len;
+	while (klen) {
+		/* get free slot */
+		fsi = p->header.freelist;
+		t = &p->slot[fsi];
+		p->header.freelist = t->next;
+		--p->header.freecnt;
+
+		/* is next slot contiguous ? */
+		if (fsi != xsi + 1) {
+			/* close current linelock */
+			lv->length = n;
+			dtlck->index++;
+
+			/* open new linelock */
+			if (dtlck->index < dtlck->maxcnt)
+				lv++;
+			else {
+				dtlck = (dtlock_t *) txLinelock(dtlck);
+				lv = (lv_t *) & dtlck->lv[0];
+			}
+
+			lv->offset = fsi;
+			n = 0;
+		}
+
+		kname += len;
+		len = min(klen, DTSLOTDATALEN);
+		UniStrncpy_le(t->name, kname, len);
+
+		n++;
+		xsi = fsi;
+		klen -= len;
+	}
+
+	/* close current linelock */
+	lv->length = n;
+	dtlck->index++;
+
+	*dtlock = dtlck;
+
+	/* terminate last/only segment */
+	if (h == t) {
+		/* single segment entry */
+		if (p->header.flag & BT_LEAF)
+			lh->next = -1;
+		else
+			ih->next = -1;
+	} else
+		/* multi-segment entry */
+		t->next = -1;
+
+	/* if insert into middle, shift right succeeding entries in stbl */
+	stbl = DT_GETSTBL(p);
+	nextindex = p->header.nextindex;
+	if (index < nextindex) {
+		memmove(stbl + index + 1, stbl + index, nextindex - index);
+
+		if ((p->header.flag & BT_LEAF) && data->leaf.ip) {
+			/*
+			 * Need to update slot number for entries that moved
+			 * in the stbl
+			 */
+			mp = 0;
+			for (n = index + 1; n <= nextindex; n++) {
+				lh = (ldtentry_t *) & (p->slot[stbl[n]]);
+				modify_index(data->leaf.tid, data->leaf.ip,
+					     le32_to_cpu(lh->index), bn, n,
+					     &mp);
+			}
+			if (mp)
+				release_metapage(mp);
+		}
+	}
+
+	stbl[index] = hsi;
+
+	/* advance next available entry index of stbl */
+	++p->header.nextindex;
+}
+
+
+/*
+ *	dtMoveEntry()
+ *
+ * function: move entries from split/left page to new/right page
+ *
+ *	nextindex of dst page and freelist/freecnt of both pages
+ *	are updated.
+ */
+static void dtMoveEntry(dtpage_t * sp, int si, dtpage_t * dp,
+			dtlock_t ** sdtlock, dtlock_t ** ddtlock,
+			int do_index)
+{
+	int ssi, next;		/* src slot index */
+	int di;			/* dst entry index */
+	int dsi;		/* dst slot index */
+	s8 *sstbl, *dstbl;	/* sorted entry table */
+	int snamlen, len;
+	ldtentry_t *slh, *dlh = 0;
+	idtentry_t *sih, *dih = 0;
+	dtslot_t *h, *s, *d;
+	dtlock_t *sdtlck = *sdtlock, *ddtlck = *ddtlock;
+	lv_t *slv, *dlv;
+	int xssi, ns, nd;
+	int sfsi;
+
+	sstbl = (s8 *) & sp->slot[sp->header.stblindex];
+	dstbl = (s8 *) & dp->slot[dp->header.stblindex];
+
+	dsi = dp->header.freelist;	/* first (whole page) free slot */
+	sfsi = sp->header.freelist;
+
+	/* linelock destination entry slot */
+	dlv = (lv_t *) & ddtlck->lv[ddtlck->index];
+	dlv->offset = dsi;
+
+	/* linelock source entry slot */
+	slv = (lv_t *) & sdtlck->lv[sdtlck->index];
+	slv->offset = sstbl[si];
+	xssi = slv->offset - 1;
+
+	/*
+	 * move entries
+	 */
+	ns = nd = 0;
+	for (di = 0; si < sp->header.nextindex; si++, di++) {
+		ssi = sstbl[si];
+		dstbl[di] = dsi;
+
+		/* is next slot contiguous ? */
+		if (ssi != xssi + 1) {
+			/* close current linelock */
+			slv->length = ns;
+			sdtlck->index++;
+
+			/* open new linelock */
+			if (sdtlck->index < sdtlck->maxcnt)
+				slv++;
+			else {
+				sdtlck = (dtlock_t *) txLinelock(sdtlck);
+				slv = (lv_t *) & sdtlck->lv[0];
+			}
+
+			slv->offset = ssi;
+			ns = 0;
+		}
+
+		/*
+		 * move head/only segment of an entry
+		 */
+		/* get dst slot */
+		h = d = &dp->slot[dsi];
+
+		/* get src slot and move */
+		s = &sp->slot[ssi];
+		if (sp->header.flag & BT_LEAF) {
+			/* get source entry */
+			slh = (ldtentry_t *) s;
+			dlh = (ldtentry_t *) h;
+			snamlen = slh->namlen;
+
+			if (do_index) {
+				len = min(snamlen, DTLHDRDATALEN);
+				dlh->index = slh->index; /* little-endian */
+			} else
+				len = min(snamlen, DTLHDRDATALEN_LEGACY);
+
+			memcpy(dlh, slh, 6 + len * 2);
+
+			next = slh->next;
+
+			/* update dst head/only segment next field */
+			dsi++;
+			dlh->next = dsi;
+		} else {
+			sih = (idtentry_t *) s;
+			snamlen = sih->namlen;
+
+			len = min(snamlen, DTIHDRDATALEN);
+			dih = (idtentry_t *) h;
+			memcpy(dih, sih, 10 + len * 2);
+			next = sih->next;
+
+			dsi++;
+			dih->next = dsi;
+		}
+
+		/* free src head/only segment */
+		s->next = sfsi;
+		s->cnt = 1;
+		sfsi = ssi;
+
+		ns++;
+		nd++;
+		xssi = ssi;
+
+		/*
+		 * move additional segment(s) of the entry
+		 */
+		snamlen -= len;
+		while ((ssi = next) >= 0) {
+			/* is next slot contiguous ? */
+			if (ssi != xssi + 1) {
+				/* close current linelock */
+				slv->length = ns;
+				sdtlck->index++;
+
+				/* open new linelock */
+				if (sdtlck->index < sdtlck->maxcnt)
+					slv++;
+				else {
+					sdtlck =
+					    (dtlock_t *)
+					    txLinelock(sdtlck);
+					slv = (lv_t *) & sdtlck->lv[0];
+				}
+
+				slv->offset = ssi;
+				ns = 0;
+			}
+
+			/* get next source segment */
+			s = &sp->slot[ssi];
+
+			/* get next destination free slot */
+			d++;
+
+			len = min(snamlen, DTSLOTDATALEN);
+			UniStrncpy(d->name, s->name, len);
+
+			ns++;
+			nd++;
+			xssi = ssi;
+
+			dsi++;
+			d->next = dsi;
+
+			/* free source segment */
+			next = s->next;
+			s->next = sfsi;
+			s->cnt = 1;
+			sfsi = ssi;
+
+			snamlen -= len;
+		}		/* end while */
+
+		/* terminate dst last/only segment */
+		if (h == d) {
+			/* single segment entry */
+			if (dp->header.flag & BT_LEAF)
+				dlh->next = -1;
+			else
+				dih->next = -1;
+		} else
+			/* multi-segment entry */
+			d->next = -1;
+	}			/* end for */
+
+	/* close current linelock */
+	slv->length = ns;
+	sdtlck->index++;
+	*sdtlock = sdtlck;
+
+	dlv->length = nd;
+	ddtlck->index++;
+	*ddtlock = ddtlck;
+
+	/* update source header */
+	sp->header.freelist = sfsi;
+	sp->header.freecnt += nd;
+
+	/* update destination header */
+	dp->header.nextindex = di;
+
+	dp->header.freelist = dsi;
+	dp->header.freecnt -= nd;
+}
+
+
+/*
+ *	dtDeleteEntry()
+ *
+ * function: free a (leaf/internal) entry
+ *
+ * log freelist header, stbl, and each segment slot of entry
+ * (even though last/only segment next field is modified,
+ * physical image logging requires all segment slots of
+ * the entry logged to avoid applying previous updates
+ * to the same slots)
+ */
+static void dtDeleteEntry(dtpage_t * p, int fi, dtlock_t ** dtlock)
+{
+	int fsi;		/* free entry slot index */
+	s8 *stbl;
+	dtslot_t *t;
+	int si, freecnt;
+	dtlock_t *dtlck = *dtlock;
+	lv_t *lv;
+	int xsi, n;
+
+	/* get free entry slot index */
+	stbl = DT_GETSTBL(p);
+	fsi = stbl[fi];
+
+	/* open new linelock */
+	if (dtlck->index >= dtlck->maxcnt)
+		dtlck = (dtlock_t *) txLinelock(dtlck);
+	lv = (lv_t *) & dtlck->lv[dtlck->index];
+
+	lv->offset = fsi;
+
+	/* get the head/only segment */
+	t = &p->slot[fsi];
+	if (p->header.flag & BT_LEAF)
+		si = ((ldtentry_t *) t)->next;
+	else
+		si = ((idtentry_t *) t)->next;
+	t->next = si;
+	t->cnt = 1;
+
+	n = freecnt = 1;
+	xsi = fsi;
+
+	/* find the last/only segment */
+	while (si >= 0) {
+		/* is next slot contiguous ? */
+		if (si != xsi + 1) {
+			/* close current linelock */
+			lv->length = n;
+			dtlck->index++;
+
+			/* open new linelock */
+			if (dtlck->index < dtlck->maxcnt)
+				lv++;
+			else {
+				dtlck = (dtlock_t *) txLinelock(dtlck);
+				lv = (lv_t *) & dtlck->lv[0];
+			}
+
+			lv->offset = si;
+			n = 0;
+		}
+
+		n++;
+		xsi = si;
+		freecnt++;
+
+		t = &p->slot[si];
+		t->cnt = 1;
+		si = t->next;
+	}
+
+	/* close current linelock */
+	lv->length = n;
+	dtlck->index++;
+
+	*dtlock = dtlck;
+
+	/* update freelist */
+	t->next = p->header.freelist;
+	p->header.freelist = fsi;
+	p->header.freecnt += freecnt;
+
+	/* if delete from middle,
+	 * shift left the succedding entries in the stbl
+	 */
+	si = p->header.nextindex;
+	if (fi < si - 1)
+		memmove(&stbl[fi], &stbl[fi + 1], si - fi - 1);
+
+	p->header.nextindex--;
+}
+
+
+/*
+ *	dtTruncateEntry()
+ *
+ * function: truncate a (leaf/internal) entry
+ *
+ * log freelist header, stbl, and each segment slot of entry
+ * (even though last/only segment next field is modified,
+ * physical image logging requires all segment slots of
+ * the entry logged to avoid applying previous updates
+ * to the same slots)
+ */
+static void dtTruncateEntry(dtpage_t * p, int ti, dtlock_t ** dtlock)
+{
+	int tsi;		/* truncate entry slot index */
+	s8 *stbl;
+	dtslot_t *t;
+	int si, freecnt;
+	dtlock_t *dtlck = *dtlock;
+	lv_t *lv;
+	int fsi, xsi, n;
+
+	/* get free entry slot index */
+	stbl = DT_GETSTBL(p);
+	tsi = stbl[ti];
+
+	/* open new linelock */
+	if (dtlck->index >= dtlck->maxcnt)
+		dtlck = (dtlock_t *) txLinelock(dtlck);
+	lv = (lv_t *) & dtlck->lv[dtlck->index];
+
+	lv->offset = tsi;
+
+	/* get the head/only segment */
+	t = &p->slot[tsi];
+	ASSERT(p->header.flag & BT_INTERNAL);
+	((idtentry_t *) t)->namlen = 0;
+	si = ((idtentry_t *) t)->next;
+	((idtentry_t *) t)->next = -1;
+
+	n = 1;
+	freecnt = 0;
+	fsi = si;
+	xsi = tsi;
+
+	/* find the last/only segment */
+	while (si >= 0) {
+		/* is next slot contiguous ? */
+		if (si != xsi + 1) {
+			/* close current linelock */
+			lv->length = n;
+			dtlck->index++;
+
+			/* open new linelock */
+			if (dtlck->index < dtlck->maxcnt)
+				lv++;
+			else {
+				dtlck = (dtlock_t *) txLinelock(dtlck);
+				lv = (lv_t *) & dtlck->lv[0];
+			}
+
+			lv->offset = si;
+			n = 0;
+		}
+
+		n++;
+		xsi = si;
+		freecnt++;
+
+		t = &p->slot[si];
+		t->cnt = 1;
+		si = t->next;
+	}
+
+	/* close current linelock */
+	lv->length = n;
+	dtlck->index++;
+
+	*dtlock = dtlck;
+
+	/* update freelist */
+	if (freecnt == 0)
+		return;
+	t->next = p->header.freelist;
+	p->header.freelist = fsi;
+	p->header.freecnt += freecnt;
+}
+
+
+/*
+ *	dtLinelockFreelist()
+ */
+static void dtLinelockFreelist(dtpage_t * p,	/* directory page */
+			       int m,	/* max slot index */
+			       dtlock_t ** dtlock)
+{
+	int fsi;		/* free entry slot index */
+	dtslot_t *t;
+	int si;
+	dtlock_t *dtlck = *dtlock;
+	lv_t *lv;
+	int xsi, n;
+
+	/* get free entry slot index */
+	fsi = p->header.freelist;
+
+	/* open new linelock */
+	if (dtlck->index >= dtlck->maxcnt)
+		dtlck = (dtlock_t *) txLinelock(dtlck);
+	lv = (lv_t *) & dtlck->lv[dtlck->index];
+
+	lv->offset = fsi;
+
+	n = 1;
+	xsi = fsi;
+
+	t = &p->slot[fsi];
+	si = t->next;
+
+	/* find the last/only segment */
+	while (si < m && si >= 0) {
+		/* is next slot contiguous ? */
+		if (si != xsi + 1) {
+			/* close current linelock */
+			lv->length = n;
+			dtlck->index++;
+
+			/* open new linelock */
+			if (dtlck->index < dtlck->maxcnt)
+				lv++;
+			else {
+				dtlck = (dtlock_t *) txLinelock(dtlck);
+				lv = (lv_t *) & dtlck->lv[0];
+			}
+
+			lv->offset = si;
+			n = 0;
+		}
+
+		n++;
+		xsi = si;
+
+		t = &p->slot[si];
+		si = t->next;
+	}
+
+	/* close current linelock */
+	lv->length = n;
+	dtlck->index++;
+
+	*dtlock = dtlck;
+}
+
+
+/*
+ * NAME: dtModify
+ *
+ * FUNCTION: Modify the inode number part of a directory entry
+ *
+ * PARAMETERS:
+ *	tid	- Transaction id
+ *	ip	- Inode of parent directory
+ *	key	- Name of entry to be modified
+ *	orig_ino	- Original inode number expected in entry
+ *	new_ino	- New inode number to put into entry
+ *	flag	- JFS_RENAME
+ *
+ * RETURNS:
+ *	ESTALE	- If entry found does not match orig_ino passed in
+ *	ENOENT	- If no entry can be found to match key
+ *	0	- If successfully modified entry
+ */
+int dtModify(tid_t tid, struct inode *ip,
+	 component_t * key, ino_t * orig_ino, ino_t new_ino, int flag)
+{
+	int rc;
+	s64 bn;
+	metapage_t *mp;
+	dtpage_t *p;
+	int index;
+	btstack_t btstack;
+	tlock_t *tlck;
+	dtlock_t *dtlck;
+	lv_t *lv;
+	s8 *stbl;
+	int entry_si;		/* entry slot index */
+	ldtentry_t *entry;
+
+	/*
+	 *      search for the entry to modify:
+	 *
+	 * dtSearch() returns (leaf page pinned, index at which to modify).
+	 */
+	if ((rc = dtSearch(ip, key, orig_ino, &btstack, flag)))
+		return rc;
+
+	/* retrieve search result */
+	DT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	BT_MARK_DIRTY(mp, ip);
+	/*
+	 * acquire a transaction lock on the leaf page of named entry
+	 */
+	tlck = txLock(tid, ip, mp, tlckDTREE | tlckENTRY);
+	dtlck = (dtlock_t *) & tlck->lock;
+
+	/* get slot index of the entry */
+	stbl = DT_GETSTBL(p);
+	entry_si = stbl[index];
+
+	/* linelock entry */
+	ASSERT(dtlck->index == 0);
+	lv = (lv_t *) & dtlck->lv[0];
+	lv->offset = entry_si;
+	lv->length = 1;
+	dtlck->index++;
+
+	/* get the head/only segment */
+	entry = (ldtentry_t *) & p->slot[entry_si];
+
+	/* substitute the inode number of the entry */
+	entry->inumber = cpu_to_le32(new_ino);
+
+	/* unpin the leaf page */
+	DT_PUTPAGE(mp);
+
+	return 0;
+}
+
+#ifdef _JFS_DEBUG_DTREE
+/*
+ *	dtDisplayTree()
+ *
+ * function: traverse forward
+ */
+int dtDisplayTree(struct inode *ip)
+{
+	int rc;
+	metapage_t *mp;
+	dtpage_t *p;
+	s64 bn, pbn;
+	int index, lastindex, v, h;
+	pxd_t *xd;
+	btstack_t btstack;
+	btframe_t *btsp;
+	btframe_t *parent;
+	u8 *stbl;
+	int psize = 256;
+
+	printk("display B+-tree.\n");
+
+	/* clear stack */
+	btsp = btstack.stack;
+
+	/*
+	 * start with root
+	 *
+	 * root resides in the inode
+	 */
+	bn = 0;
+	v = h = 0;
+
+	/*
+	 * first access of each page:
+	 */
+      newPage:
+	DT_GETPAGE(ip, bn, mp, psize, p, rc);
+	if (rc)
+		return rc;
+
+	/* process entries forward from first index */
+	index = 0;
+	lastindex = p->header.nextindex - 1;
+
+	if (p->header.flag & BT_INTERNAL) {
+		/*
+		 * first access of each internal page
+		 */
+		printf("internal page ");
+		dtDisplayPage(ip, bn, p);
+
+		goto getChild;
+	} else {		/* (p->header.flag & BT_LEAF) */
+
+		/*
+		 * first access of each leaf page
+		 */
+		printf("leaf page ");
+		dtDisplayPage(ip, bn, p);
+
+		/*
+		 * process leaf page entries
+		 *
+		 for ( ; index <= lastindex; index++)
+		 {
+		 }
+		 */
+
+		/* unpin the leaf page */
+		DT_PUTPAGE(mp);
+	}
+
+	/*
+	 * go back up to the parent page
+	 */
+      getParent:
+	/* pop/restore parent entry for the current child page */
+	if ((parent = (btsp == btstack.stack ? NULL : --btsp)) == NULL)
+		/* current page must have been root */
+		return;
+
+	/*
+	 * parent page scan completed
+	 */
+	if ((index = parent->index) == (lastindex = parent->lastindex)) {
+		/* go back up to the parent page */
+		goto getParent;
+	}
+
+	/*
+	 * parent page has entries remaining
+	 */
+	/* get back the parent page */
+	bn = parent->bn;
+	/* v = parent->level; */
+	DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	/* get next parent entry */
+	index++;
+
+	/*
+	 * internal page: go down to child page of current entry
+	 */
+      getChild:
+	/* push/save current parent entry for the child page */
+	btsp->bn = pbn = bn;
+	btsp->index = index;
+	btsp->lastindex = lastindex;
+	/* btsp->level = v; */
+	/* btsp->node = h; */
+	++btsp;
+
+	/* get current entry for the child page */
+	stbl = DT_GETSTBL(p);
+	xd = (pxd_t *) & p->slot[stbl[index]];
+
+	/*
+	 * first access of each internal entry:
+	 */
+
+	/* get child page */
+	bn = addressPXD(xd);
+	psize = lengthPXD(xd) << ip->i_ipmnt->i_l2bsize;
+
+	printk("traverse down 0x%Lx[%d]->0x%Lx\n", pbn, index, bn);
+	v++;
+	h = index;
+
+	/* release parent page */
+	DT_PUTPAGE(mp);
+
+	/* process the child page */
+	goto newPage;
+}
+
+
+/*
+ *	dtDisplayPage()
+ *
+ * function: display page
+ */
+int dtDisplayPage(struct inode *ip, s64 bn, dtpage_t * p)
+{
+	int rc;
+	metapage_t *mp;
+	ldtentry_t *lh;
+	idtentry_t *ih;
+	pxd_t *xd;
+	int i, j;
+	u8 *stbl;
+	wchar_t name[JFS_NAME_MAX + 1];
+	component_t key = { 0, name };
+	int freepage = 0;
+
+	if (p == NULL) {
+		freepage = 1;
+		DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+	}
+
+	/* display page control */
+	printk("bn:0x%Lx flag:0x%08x nextindex:%d\n",
+	       bn, p->header.flag, p->header.nextindex);
+
+	/* display entries */
+	stbl = DT_GETSTBL(p);
+	for (i = 0, j = 1; i < p->header.nextindex; i++, j++) {
+		dtGetKey(p, i, &key, JFS_SBI(ip->i_sb)->mntflag);
+		key.name[key.namlen] = '\0';
+		if (p->header.flag & BT_LEAF) {
+			lh = (ldtentry_t *) & p->slot[stbl[i]];
+			printf("\t[%d] %s:%d", i, key.name,
+			       le32_to_cpu(lh->inumber));
+		} else {
+			ih = (idtentry_t *) & p->slot[stbl[i]];
+			xd = (pxd_t *) ih;
+			bn = addressPXD(xd);
+			printf("\t[%d] %s:0x%Lx", i, key.name, bn);
+		}
+
+		if (j == 4) {
+			printf("\n");
+			j = 0;
+		}
+	}
+
+	printf("\n");
+
+	if (freepage)
+		DT_PUTPAGE(mp);
+
+	return 0;
+}
+#endif				/* _JFS_DEBUG_DTREE */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_dtree.h linux-2.5.6-pre2/fs/jfs/jfs_dtree.h
--- linux-2.5.6-pre1/fs/jfs/jfs_dtree.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_dtree.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,284 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Change History :
+ *
+ */
+
+#ifndef _H_JFS_DTREE
+#define	_H_JFS_DTREE
+
+/*
+ *	jfs_dtree.h: directory B+-tree manager
+ */
+
+#include "jfs_btree.h"
+
+typedef union {
+	struct {
+		tid_t tid;
+		struct inode *ip;
+		u32 ino;
+	} leaf;
+	pxd_t xd;
+} ddata_t;
+
+
+/*
+ *      entry segment/slot
+ *
+ * an entry consists of type dependent head/only segment/slot and
+ * additional segments/slots linked vi next field;
+ * N.B. last/only segment of entry is terminated by next = -1;
+ */
+/*
+ *	directory page slot
+ */
+typedef struct {
+	s8 next;		/* 1: */
+	s8 cnt;			/* 1: */
+	wchar_t name[15];	/* 30: */
+} dtslot_t;			/* (32) */
+
+
+#define DATASLOTSIZE	16
+#define L2DATASLOTSIZE	4
+#define	DTSLOTSIZE	32
+#define	L2DTSLOTSIZE	5
+#define DTSLOTHDRSIZE	2
+#define DTSLOTDATASIZE	30
+#define DTSLOTDATALEN	15
+
+/*
+ *	 internal node entry head/only segment
+ */
+typedef struct {
+	pxd_t xd;		/* 8: child extent descriptor */
+
+	s8 next;		/* 1: */
+	u8 namlen;		/* 1: */
+	wchar_t name[11];	/* 22: 2-byte aligned */
+} idtentry_t;			/* (32) */
+
+#define DTIHDRSIZE	10
+#define DTIHDRDATALEN	11
+
+/* compute number of slots for entry */
+#define	NDTINTERNAL(klen) ( ((4 + (klen)) + (15 - 1)) / 15 )
+
+
+/*
+ *	leaf node entry head/only segment
+ *
+ * 	For legacy filesystems, name contains 13 wchars -- no index field
+ */
+typedef struct {
+	u32 inumber;		/* 4: 4-byte aligned */
+	s8 next;		/* 1: */
+	u8 namlen;		/* 1: */
+	wchar_t name[11];	/* 22: 2-byte aligned */
+	u32 index;		/* 4: index into dir_table */
+} ldtentry_t;			/* (32) */
+
+#define DTLHDRSIZE	6
+#define DTLHDRDATALEN_LEGACY	13	/* Old (OS/2) format */
+#define DTLHDRDATALEN	11
+
+/*
+ * dir_table used for directory traversal during readdir
+ */
+
+/*
+ * Keep persistent index for directory entries
+ */
+#define DO_INDEX(INODE) (JFS_SBI((INODE)->i_sb)->mntflag & JFS_DIR_INDEX)
+
+/*
+ * Maximum entry in inline directory table
+ */
+#define MAX_INLINE_DIRTABLE_ENTRY 13
+
+typedef struct dir_table_slot {
+	u8 rsrvd;		/* 1: */
+	u8 flag;		/* 1: 0 if free */
+	u8 slot;		/* 1: slot within leaf page of entry */
+	u8 addr1;		/* 1: upper 8 bits of leaf page address */
+	u32 addr2;		/* 4: lower 32 bits of leaf page address -OR-
+				   index of next entry when this entry was deleted */
+} dir_table_slot_t;		/* (8) */
+
+/*
+ * flag values
+ */
+#define DIR_INDEX_VALID 1
+#define DIR_INDEX_FREE 0
+
+#define DTSaddress(dir_table_slot, address64)\
+{\
+	(dir_table_slot)->addr1 = ((u64)address64) >> 32;\
+	(dir_table_slot)->addr2 = __cpu_to_le32((address64) & 0xffffffff);\
+}
+
+#define addressDTS(dts)\
+	( ((s64)((dts)->addr1)) << 32 | __le32_to_cpu((dts)->addr2) )
+
+/* compute number of slots for entry */
+#define	NDTLEAF_LEGACY(klen)	( ((2 + (klen)) + (15 - 1)) / 15 )
+#define	NDTLEAF	NDTINTERNAL
+
+
+/*
+ *	directory root page (in-line in on-disk inode):
+ *
+ * cf. dtpage_t below.
+ */
+typedef union {
+	struct {
+		dasd_t DASD;	/* 16: DASD limit/usage info  F226941 */
+
+		u8 flag;	/* 1: */
+		u8 nextindex;	/* 1: next free entry in stbl */
+		s8 freecnt;	/* 1: free count */
+		s8 freelist;	/* 1: freelist header */
+
+		u32 idotdot;	/* 4: parent inode number */
+
+		s8 stbl[8];	/* 8: sorted entry index table */
+	} header;		/* (32) */
+
+	dtslot_t slot[9];
+} dtroot_t;
+
+#define PARENT(IP) \
+	(le32_to_cpu(JFS_IP(IP)->i_dtroot.header.idotdot))
+
+#define DTROOTMAXSLOT	9
+
+#define	dtEmpty(IP) (JFS_IP(IP)->i_dtroot.header.nextindex == 0)
+
+
+/*
+ *	directory regular page:
+ *
+ *	entry slot array of 32 byte slot
+ *
+ * sorted entry slot index table (stbl):
+ * contiguous slots at slot specified by stblindex,
+ * 1-byte per entry
+ *   512 byte block:  16 entry tbl (1 slot)
+ *  1024 byte block:  32 entry tbl (1 slot)
+ *  2048 byte block:  64 entry tbl (2 slot)
+ *  4096 byte block: 128 entry tbl (4 slot)
+ *
+ * data area:
+ *   512 byte block:  16 - 2 =  14 slot
+ *  1024 byte block:  32 - 2 =  30 slot
+ *  2048 byte block:  64 - 3 =  61 slot
+ *  4096 byte block: 128 - 5 = 123 slot
+ *
+ * N.B. index is 0-based; index fields refer to slot index
+ * except nextindex which refers to entry index in stbl;
+ * end of entry stot list or freelist is marked with -1.
+ */
+typedef union {
+	struct {
+		s64 next;	/* 8: next sibling */
+		s64 prev;	/* 8: previous sibling */
+
+		u8 flag;	/* 1: */
+		u8 nextindex;	/* 1: next entry index in stbl */
+		s8 freecnt;	/* 1: */
+		s8 freelist;	/* 1: slot index of head of freelist */
+
+		u8 maxslot;	/* 1: number of slots in page slot[] */
+		u8 stblindex;	/* 1: slot index of start of stbl */
+		u8 rsrvd[2];	/* 2: */
+
+		pxd_t self;	/* 8: self pxd */
+	} header;		/* (32) */
+
+	dtslot_t slot[128];
+} dtpage_t;
+
+#define DTPAGEMAXSLOT        128
+
+#define DT8THPGNODEBYTES     512
+#define DT8THPGNODETSLOTS      1
+#define DT8THPGNODESLOTS      16
+
+#define DTQTRPGNODEBYTES    1024
+#define DTQTRPGNODETSLOTS      1
+#define DTQTRPGNODESLOTS      32
+
+#define DTHALFPGNODEBYTES   2048
+#define DTHALFPGNODETSLOTS     2
+#define DTHALFPGNODESLOTS     64
+
+#define DTFULLPGNODEBYTES   4096
+#define DTFULLPGNODETSLOTS     4
+#define DTFULLPGNODESLOTS    128
+
+#define DTENTRYSTART	1
+
+/* get sorted entry table of the page */
+#define DT_GETSTBL(p) ( ((p)->header.flag & BT_ROOT) ?\
+	((dtroot_t *)(p))->header.stbl : \
+	(s8 *)&(p)->slot[(p)->header.stblindex] )
+
+/*
+ * Flags for dtSearch
+ */
+#define JFS_CREATE 1
+#define JFS_LOOKUP 2
+#define JFS_REMOVE 3
+#define JFS_RENAME 4
+
+#define DIRENTSIZ(namlen) \
+    ( (sizeof(struct dirent) - 2*(JFS_NAME_MAX+1) + 2*((namlen)+1) + 3) &~ 3 )
+
+
+/*
+ *	external declarations
+ */
+extern void dtInitRoot(tid_t tid, struct inode *ip, u32 idotdot);
+
+extern int dtSearch(struct inode *ip, component_t * key,
+		    ino_t * data, btstack_t * btstack, int flag);
+
+extern int dtInsert(tid_t tid, struct inode *ip,
+		    component_t * key, ino_t * ino, btstack_t * btstack);
+
+extern int dtDelete(tid_t tid,
+		    struct inode *ip, component_t * key, ino_t * data, int flag);
+
+extern int dtRelocate(tid_t tid,
+		      struct inode *ip, s64 lmxaddr, pxd_t * opxd, s64 nxaddr);
+
+extern int dtModify(tid_t tid, struct inode *ip,
+		    component_t * key, ino_t * orig_ino, ino_t new_ino, int flag);
+
+extern int jfs_readdir(struct file *filp, void *dirent, filldir_t filldir);
+
+#ifdef  _JFS_DEBUG_DTREE
+extern int dtDisplayTree(struct inode *ip);
+
+extern int dtDisplayPage(struct inode *ip, s64 bn, dtpage_t * p);
+#endif				/* _JFS_DEBUG_DTREE */
+
+#endif				/* !_H_JFS_DTREE */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_extendfs.h linux-2.5.6-pre2/fs/jfs/jfs_extendfs.h
--- linux-2.5.6-pre1/fs/jfs/jfs_extendfs.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_extendfs.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,39 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef	_H_JFS_EXTENDFS
+#define _H_JFS_EXTENDFS
+
+/*
+ *	jfs_extendfs.h
+ */
+/*
+ *	extendfs parameter list
+ */
+typedef struct {
+	u32 flag;		/* 4: */
+	u8 dev;			/* 1: */
+	u8 pad[3];		/* 3: */
+	s64 LVSize;		/* 8: LV size in LV block */
+	s64 FSSize;		/* 8: FS size in LV block */
+	s32 LogSize;		/* 4: inlinelog size in LV block */
+} extendfs_t;			/* (28) */
+
+/* plist flag */
+#define EXTENDFS_QUERY		0x00000001
+
+#endif				/* _H_JFS_EXTENDFS */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_extent.c linux-2.5.6-pre2/fs/jfs/jfs_extent.c
--- linux-2.5.6-pre1/fs/jfs/jfs_extent.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_extent.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,637 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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
+ *
+ *
+ *
+ * Module: jfs_extent.c:
+ */
+
+#include <linux/fs.h>
+#include "jfs_incore.h"
+#include "jfs_dmap.h"
+#include "jfs_extent.h"
+#include "jfs_debug.h"
+
+/*
+ * forward references
+ */
+static int extBalloc(struct inode *, s64, s64 *, s64 *);
+static int extBrealloc(struct inode *, s64, s64, s64 *, s64 *);
+int extRecord(struct inode *, xad_t *);
+static s64 extRoundDown(s64 nb);
+
+/*
+ * external references
+ */
+extern int dbExtend(struct inode *, s64, s64, s64);
+extern int jfs_commit_inode(struct inode *, int);
+
+
+#define DPD(a)          (printk("(a): %d\n",(a)))
+#define DPC(a)          (printk("(a): %c\n",(a)))
+#define DPL1(a)					\
+{						\
+	if ((a) >> 32)				\
+		printk("(a): %x%08x  ",(a));	\
+	else					\
+		printk("(a): %x  ",(a) << 32);	\
+}
+#define DPL(a)					\
+{						\
+	if ((a) >> 32)				\
+		printk("(a): %x%08x\n",(a));	\
+	else					\
+		printk("(a): %x\n",(a) << 32);	\
+}
+
+#define DPD1(a)         (printk("(a): %d  ",(a)))
+#define DPX(a)          (printk("(a): %08x\n",(a)))
+#define DPX1(a)         (printk("(a): %08x  ",(a)))
+#define DPS(a)          (printk("%s\n",(a)))
+#define DPE(a)          (printk("\nENTERING: %s\n",(a)))
+#define DPE1(a)          (printk("\nENTERING: %s",(a)))
+#define DPS1(a)         (printk("  %s  ",(a)))
+
+
+/*
+ * NAME:	extAlloc()
+ *
+ * FUNCTION:    allocate an extent for a specified page range within a
+ *		file.
+ *
+ * PARAMETERS:
+ *	ip	- the inode of the file.
+ *	xlen	- requested extent length.
+ *	pno	- the starting page number with the file.
+ *	xp	- pointer to an xad.  on entry, xad describes an
+ *		  extent that is used as an allocation hint if the
+ *		  xaddr of the xad is non-zero.  on successful exit,
+ *		  the xad describes the newly allocated extent.
+ *	abnr	- boolean_t indicating whether the newly allocated extent
+ *		  should be marked as allocated but not recorded.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO	- i/o error.
+ *      ENOSPC	- insufficient disk resources.
+ */
+int
+extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+	s64 nxlen, nxaddr, xoff, hint, xaddr = 0;
+	int rc, nbperpage;
+	int xflag;
+
+	/* This blocks if we are low on resources */
+	txBeginAnon(ip->i_sb);
+
+	/* validate extent length */
+	if (xlen > MAXXLEN)
+		xlen = MAXXLEN;
+
+	/* get the number of blocks per page */
+	nbperpage = sbi->nbperpage;
+
+	/* get the page's starting extent offset */
+	xoff = pno << sbi->l2nbperpage;
+
+	/* check if an allocation hint was provided */
+	if ((hint = addressXAD(xp))) {
+		/* get the size of the extent described by the hint */
+		nxlen = lengthXAD(xp);
+
+		/* check if the hint is for the portion of the file
+		 * immediately previous to the current allocation
+		 * request and if hint extent has the same abnr
+		 * value as the current request.  if so, we can
+		 * extend the hint extent to include the current
+		 * extent if we can allocate the blocks immediately
+		 * following the hint extent.
+		 */
+		if (offsetXAD(xp) + nxlen == xoff &&
+		    abnr == ((xp->flag & XAD_NOTRECORDED) ? TRUE : FALSE))
+			xaddr = hint + nxlen;
+
+		/* adjust the hint to the last block of the extent */
+		hint += (nxlen - 1);
+	}
+
+	/* allocate the disk blocks for the extent.  initially, extBalloc()
+	 * will try to allocate disk blocks for the requested size (xlen). 
+	 * if this fails (xlen contigious free blocks not avaliable), it'll
+	 * try to allocate a smaller number of blocks (producing a smaller
+	 * extent), with this smaller number of blocks consisting of the
+	 * requested number of blocks rounded down to the next smaller
+	 * power of 2 number (i.e. 16 -> 8).  it'll continue to round down
+	 * and retry the allocation until the number of blocks to allocate
+	 * is smaller than the number of blocks per page.
+	 */
+	nxlen = xlen;
+	if ((rc =
+	     extBalloc(ip, hint ? hint : INOHINT(ip), &nxlen, &nxaddr))) {
+		return (rc);
+	}
+
+	/* determine the value of the extent flag */
+	xflag = (abnr == TRUE) ? XAD_NOTRECORDED : 0;
+
+	/* if we can extend the hint extent to cover the current request, 
+	 * extend it.  otherwise, insert a new extent to
+	 * cover the current request.
+	 */
+	if (xaddr && xaddr == nxaddr)
+		rc = xtExtend(0, ip, xoff, (int) nxlen, 0);
+	else
+		rc = xtInsert(0, ip, xflag, xoff, (int) nxlen, &nxaddr, 0);
+
+	/* if the extend or insert failed, 
+	 * free the newly allocated blocks and return the error.
+	 */
+	if (rc) {
+		dbFree(ip, nxaddr, nxlen);
+		return (rc);
+	}
+
+	/* update the number of blocks allocated to the file */
+	ip->i_blocks += LBLK2PBLK(ip->i_sb, nxlen);
+
+	/* set the results of the extent allocation */
+	XADaddress(xp, nxaddr);
+	XADlength(xp, nxlen);
+	XADoffset(xp, xoff);
+	xp->flag = xflag;
+
+	mark_inode_dirty(ip);
+
+	/*
+	 * COMMIT_SyncList flags an anonymous tlock on page that is on
+	 * sync list.
+	 * We need to commit the inode to get the page written disk.
+	 */
+	if (test_and_clear_cflag(COMMIT_Synclist,ip))
+		jfs_commit_inode(ip, 0);
+
+	return (0);
+}
+
+
+/*
+ * NAME:        extRealloc()
+ *
+ * FUNCTION:    extend the allocation of a file extent containing a
+ *		partial back last page.
+ *
+ * PARAMETERS:
+ *	ip	- the inode of the file.
+ *	cp	- cbuf for the partial backed last page.
+ *	xlen	- request size of the resulting extent.
+ *	xp	- pointer to an xad. on successful exit, the xad
+ *		  describes the newly allocated extent.
+ *	abnr	- boolean_t indicating whether the newly allocated extent
+ *		  should be marked as allocated but not recorded.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO	- i/o error.
+ *      ENOSPC	- insufficient disk resources.
+ */
+int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr)
+{
+	struct super_block *sb = ip->i_sb;
+	s64 xaddr, xlen, nxaddr, delta, xoff;
+	s64 ntail, nextend, ninsert;
+	int rc, nbperpage = JFS_SBI(sb)->nbperpage;
+	int xflag;
+
+	/* This blocks if we are low on resources */
+	txBeginAnon(ip->i_sb);
+
+	/* validate extent length */
+	if (nxlen > MAXXLEN)
+		nxlen = MAXXLEN;
+
+	/* get the extend (partial) page's disk block address and
+	 * number of blocks.
+	 */
+	xaddr = addressXAD(xp);
+	xlen = lengthXAD(xp);
+	xoff = offsetXAD(xp);
+
+	/* if the extend page is abnr and if the request is for
+	 * the extent to be allocated and recorded, 
+	 * make the page allocated and recorded.
+	 */
+	if ((xp->flag & XAD_NOTRECORDED) && !abnr) {
+		xp->flag = 0;
+		if ((rc = xtUpdate(0, ip, xp)))
+			return (rc);
+	}
+
+	/* try to allocated the request number of blocks for the
+	 * extent.  dbRealloc() first tries to satisfy the request
+	 * by extending the allocation in place. otherwise, it will
+	 * try to allocate a new set of blocks large enough for the
+	 * request.  in satisfying a request, dbReAlloc() may allocate
+	 * less than what was request but will always allocate enough
+	 * space as to satisfy the extend page.
+	 */
+	if ((rc = extBrealloc(ip, xaddr, xlen, &nxlen, &nxaddr)))
+		return (rc);
+
+	delta = nxlen - xlen;
+
+	/* check if the extend page is not abnr but the request is abnr
+	 * and the allocated disk space is for more than one page.  if this
+	 * is the case, there is a miss match of abnr between the extend page
+	 * and the one or more pages following the extend page.  as a result,
+	 * two extents will have to be manipulated. the first will be that
+	 * of the extent of the extend page and will be manipulated thru
+	 * an xtExtend() or an xtTailgate(), depending upon whether the
+	 * disk allocation occurred as an inplace extension.  the second
+	 * extent will be manipulated (created) through an xtInsert() and
+	 * will be for the pages following the extend page.
+	 */
+	if (abnr && (!(xp->flag & XAD_NOTRECORDED)) && (nxlen > nbperpage)) {
+		ntail = nbperpage;
+		nextend = ntail - xlen;
+		ninsert = nxlen - nbperpage;
+
+		xflag = XAD_NOTRECORDED;
+	} else {
+		ntail = nxlen;
+		nextend = delta;
+		ninsert = 0;
+
+		xflag = xp->flag;
+	}
+
+	/* if we were able to extend the disk allocation in place,
+	 * extend the extent.  otherwise, move the extent to a
+	 * new disk location.
+	 */
+	if (xaddr == nxaddr) {
+		/* extend the extent */
+		if ((rc = xtExtend(0, ip, xoff + xlen, (int) nextend, 0))) {
+			dbFree(ip, xaddr + xlen, delta);
+			return (rc);
+		}
+	} else {
+		/*
+		 * move the extent to a new location:
+		 *
+		 * xtTailgate() accounts for relocated tail extent;
+		 */
+		if ((rc = xtTailgate(0, ip, xoff, (int) ntail, nxaddr, 0))) {
+			dbFree(ip, nxaddr, nxlen);
+			return (rc);
+		}
+	}
+
+
+	/* check if we need to also insert a new extent */
+	if (ninsert) {
+		/* perform the insert.  if it fails, free the blocks
+		 * to be inserted and make it appear that we only did
+		 * the xtExtend() or xtTailgate() above.
+		 */
+		xaddr = nxaddr + ntail;
+		if (xtInsert (0, ip, xflag, xoff + ntail, (int) ninsert,
+			      &xaddr, 0)) {
+			dbFree(ip, xaddr, (s64) ninsert);
+			delta = nextend;
+			nxlen = ntail;
+			xflag = 0;
+		}
+	}
+
+	/* update the inode with the number of blocks allocated */
+	ip->i_blocks += LBLK2PBLK(sb, delta);
+
+	/* set the return results */
+	XADaddress(xp, nxaddr);
+	XADlength(xp, nxlen);
+	XADoffset(xp, xoff);
+	xp->flag = xflag;
+
+	mark_inode_dirty(ip);
+
+	return (0);
+}
+
+
+/*
+ * NAME:        extHint()
+ *
+ * FUNCTION:    produce an extent allocation hint for a file offset.
+ *
+ * PARAMETERS:
+ *	ip	- the inode of the file.
+ *	offset  - file offset for which the hint is needed.
+ *	xp	- pointer to the xad that is to be filled in with
+ *		  the hint.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO	- i/o error.
+ */
+int extHint(struct inode *ip, s64 offset, xad_t * xp)
+{
+	struct super_block *sb = ip->i_sb;
+	xadlist_t xadl;
+	lxdlist_t lxdl;
+	lxd_t lxd;
+	s64 prev;
+	int rc, nbperpage = JFS_SBI(sb)->nbperpage;
+
+	/* init the hint as "no hint provided" */
+	XADaddress(xp, 0);
+
+	/* determine the starting extent offset of the page previous
+	 * to the page containing the offset.
+	 */
+	prev = ((offset & ~POFFSET) >> JFS_SBI(sb)->l2bsize) - nbperpage;
+
+	/* if the offsets in the first page of the file,
+	 * no hint provided.
+	 */
+	if (prev < 0)
+		return (0);
+
+	/* prepare to lookup the previous page's extent info */
+	lxdl.maxnlxd = 1;
+	lxdl.nlxd = 1;
+	lxdl.lxd = &lxd;
+	LXDoffset(&lxd, prev)
+	    LXDlength(&lxd, nbperpage);
+
+	xadl.maxnxad = 1;
+	xadl.nxad = 0;
+	xadl.xad = xp;
+
+	/* perform the lookup */
+	if ((rc = xtLookupList(ip, &lxdl, &xadl, 0)))
+		return (rc);
+
+	/* check if not extent exists for the previous page.  
+	 * this is possible for sparse files.
+	 */
+	if (xadl.nxad == 0) {
+//              assert(ISSPARSE(ip));
+		return (0);
+	}
+
+	/* only preserve the abnr flag within the xad flags
+	 * of the returned hint.
+	 */
+	xp->flag &= XAD_NOTRECORDED;
+
+	assert(xadl.nxad == 1);
+	assert(lengthXAD(xp) == nbperpage);
+
+	return (0);
+}
+
+
+/*
+ * NAME:        extRecord()
+ *
+ * FUNCTION:    change a page with a file from not recorded to recorded.
+ *
+ * PARAMETERS:
+ *	ip	- inode of the file.
+ *	cp	- cbuf of the file page.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO	- i/o error.
+ *      ENOSPC	- insufficient disk resources.
+ */
+int extRecord(struct inode *ip, xad_t * xp)
+{
+	int rc;
+
+	txBeginAnon(ip->i_sb);
+
+	/* update the extent */
+	if ((rc = xtUpdate(0, ip, xp)))
+		return (rc);
+
+#ifdef _STILL_TO_PORT
+	/* no longer abnr */
+	cp->cm_abnr = FALSE;
+
+	/* mark the cbuf as modified */
+	cp->cm_modified = TRUE;
+#endif				/*  _STILL_TO_PORT */
+
+	return (0);
+}
+
+
+/*
+ * NAME:        extFill()
+ *
+ * FUNCTION:    allocate disk space for a file page that represents
+ *		a file hole.
+ *
+ * PARAMETERS:
+ *	ip	- the inode of the file.
+ *	cp	- cbuf of the file page represent the hole.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO	- i/o error.
+ *      ENOSPC	- insufficient disk resources.
+ */
+int extFill(struct inode *ip, xad_t * xp)
+{
+	int rc, nbperpage = JFS_SBI(ip->i_sb)->nbperpage;
+	s64 blkno = offsetXAD(xp) >> ip->i_blksize;
+
+//      assert(ISSPARSE(ip));
+
+	/* initialize the extent allocation hint */
+	XADaddress(xp, 0);
+
+	/* allocate an extent to fill the hole */
+	if ((rc = extAlloc(ip, nbperpage, blkno, xp, FALSE)))
+		return (rc);
+
+	assert(lengthPXD(xp) == nbperpage);
+
+	return (0);
+}
+
+
+/*
+ * NAME:	extBalloc()
+ *
+ * FUNCTION:    allocate disk blocks to form an extent.
+ *
+ *		initially, we will try to allocate disk blocks for the
+ *		requested size (nblocks).  if this fails (nblocks 
+ *		contigious free blocks not avaliable), we'll try to allocate
+ *		a smaller number of blocks (producing a smaller extent), with
+ *		this smaller number of blocks consisting of the requested
+ *		number of blocks rounded down to the next smaller power of 2
+ *		number (i.e. 16 -> 8).  we'll continue to round down and
+ *		retry the allocation until the number of blocks to allocate
+ *		is smaller than the number of blocks per page.
+ *		
+ * PARAMETERS:
+ *	ip	 - the inode of the file.
+ *	hint	 - disk block number to be used as an allocation hint.
+ *	*nblocks - pointer to an s64 value.  on entry, this value specifies
+ *		   the desired number of block to be allocated. on successful
+ *		   exit, this value is set to the number of blocks actually
+ *		   allocated.
+ *	blkno	 - pointer to a block address that is filled in on successful
+ *		   return with the starting block number of the newly 
+ *		   allocated block range.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO	- i/o error.
+ *      ENOSPC	- insufficient disk resources.
+ */
+static int
+extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno)
+{
+	s64 nb, nblks, daddr, max;
+	int rc, nbperpage = JFS_SBI(ip->i_sb)->nbperpage;
+	bmap_t *mp = JFS_SBI(ip->i_sb)->bmap;
+
+	/* get the number of blocks to initially attempt to allocate.
+	 * we'll first try the number of blocks requested unless this
+	 * number is greater than the maximum number of contigious free
+	 * blocks in the map. in that case, we'll start off with the 
+	 * maximum free.
+	 */
+	max = (s64) 1 << mp->db_maxfreebud;
+	if (*nblocks >= max && *nblocks > nbperpage)
+		nb = nblks = (max > nbperpage) ? max : nbperpage;
+	else
+		nb = nblks = *nblocks;
+
+	/* try to allocate blocks */
+	while ((rc = dbAlloc(ip, hint, nb, &daddr))) {
+		/* if something other than an out of space error,
+		 * stop and return this error.
+		 */
+		if (rc != ENOSPC)
+			return (rc);
+
+		/* decrease the allocation request size */
+		nb = min(nblks, extRoundDown(nb));
+
+		/* give up if we cannot cover a page */
+		if (nb < nbperpage)
+			return (rc);
+	}
+
+	*nblocks = nb;
+	*blkno = daddr;
+
+	return (0);
+}
+
+
+/*
+ * NAME:	extBrealloc()
+ *
+ * FUNCTION:    attempt to extend an extent's allocation.
+ *
+ *		initially, we will try to extend the extent's allocation
+ *		in place.  if this fails, we'll try to move the extent
+ *		to a new set of blocks. if moving the extent, we initially
+ *		will try to allocate disk blocks for the requested size
+ *		(nnew).  if this fails 	(nnew contigious free blocks not
+ *		avaliable), we'll try  to allocate a smaller number of
+ *		blocks (producing a smaller extent), with this smaller
+ *		number of blocks consisting of the requested number of
+ *		blocks rounded down to the next smaller power of 2
+ *		number (i.e. 16 -> 8).  we'll continue to round down and
+ *		retry the allocation until the number of blocks to allocate
+ *		is smaller than the number of blocks per page.
+ *		
+ * PARAMETERS:
+ *	ip	 - the inode of the file.
+ *	blkno    - starting block number of the extents current allocation.
+ *	nblks    - number of blocks within the extents current allocation.
+ *	newnblks - pointer to a s64 value.  on entry, this value is the
+ *		   the new desired extent size (number of blocks).  on
+ *		   successful exit, this value is set to the extent's actual
+ *		   new size (new number of blocks).
+ *	newblkno - the starting block number of the extents new allocation.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO	- i/o error.
+ *      ENOSPC	- insufficient disk resources.
+ */
+static int
+extBrealloc(struct inode *ip,
+	    s64 blkno, s64 nblks, s64 * newnblks, s64 * newblkno)
+{
+	int rc;
+
+	/* try to extend in place */
+	if ((rc = dbExtend(ip, blkno, nblks, *newnblks - nblks)) == 0) {
+		*newblkno = blkno;
+		return (0);
+	} else {
+		if (rc != ENOSPC)
+			return (rc);
+	}
+
+	/* in place extension not possible.  
+	 * try to move the extent to a new set of blocks.
+	 */
+	return (extBalloc(ip, blkno, newnblks, newblkno));
+}
+
+
+/*
+ * NAME:        extRoundDown()
+ *
+ * FUNCTION:    round down a specified number of blocks to the next
+ *		smallest power of 2 number.
+ *
+ * PARAMETERS:
+ *	nb	- the inode of the file.
+ *
+ * RETURN VALUES:
+ *      next smallest power of 2 number.
+ */
+static s64 extRoundDown(s64 nb)
+{
+	int i;
+	u64 m, k;
+
+	for (i = 0, m = (u64) 1 << 63; i < 64; i++, m >>= 1) {
+		if (m & nb)
+			break;
+	}
+
+	i = 63 - i;
+	k = (u64) 1 << i;
+	k = ((k - 1) & nb) ? k : k >> 1;
+
+	return (k);
+}
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_extent.h linux-2.5.6-pre2/fs/jfs/jfs_extent.h
--- linux-2.5.6-pre1/fs/jfs/jfs_extent.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_extent.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,31 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef	_H_JFS_EXTENT
+#define _H_JFS_EXTENT
+
+/*  get block allocation allocation hint as location of disk inode */
+#define	INOHINT(ip)	\
+	(addressPXD(&(JFS_IP(ip)->ixpxd)) + lengthPXD(&(JFS_IP(ip)->ixpxd)) - 1)
+
+extern int	extAlloc(struct inode *, s64, s64, xad_t *, boolean_t);
+extern int	extFill(struct inode *, xad_t *);
+extern int	extHint(struct inode *, s64, xad_t *);
+extern int	extRealloc(struct inode *, s64, xad_t *, boolean_t);
+extern int	extRecord(struct inode *, xad_t *);
+
+#endif	/* _H_JFS_EXTENT */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_filsys.h linux-2.5.6-pre2/fs/jfs/jfs_filsys.h
--- linux-2.5.6-pre1/fs/jfs/jfs_filsys.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_filsys.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,274 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+
+#ifndef _H_JFS_FILSYS
+#define _H_JFS_FILSYS
+
+/*
+ *	jfs_filsys.h
+ *
+ * file system (implementation-dependent) constants 
+ *
+ * refer to <limits.h> for system wide implementation-dependent constants 
+ */
+
+/*
+ *	 file system option (superblock flag)
+ */
+/* platform option (conditional compilation) */
+#define JFS_AIX		0x80000000	/* AIX support */
+/*	POSIX name/directory  support */
+
+#define JFS_OS2		0x40000000	/* OS/2 support */
+/*	case-insensitive name/directory support */
+
+#define JFS_DFS		0x20000000	/* DCE DFS LFS support */
+
+#define JFS_LINUX      	0x10000000	/* Linux support */
+/*	case-sensitive name/directory support */
+
+/* directory option */
+#define JFS_UNICODE	0x00000001	/* unicode name */
+
+/* commit option */
+#define	JFS_COMMIT	0x00000f00	/* commit option mask */
+#define	JFS_GROUPCOMMIT	0x00000100	/* group (of 1) commit */
+#define	JFS_LAZYCOMMIT	0x00000200	/* lazy commit */
+#define	JFS_TMPFS	0x00000400	/* temporary file system - 
+					 * do not log/commit:
+					 */
+
+/* log logical volume option */
+#define	JFS_INLINELOG	0x00000800	/* inline log within file system */
+#define JFS_INLINEMOVE	0x00001000	/* inline log being moved */
+
+/* Secondary aggregate inode table */
+#define JFS_BAD_SAIT	0x00010000	/* current secondary ait is bad */
+
+/* sparse regular file support */
+#define JFS_SPARSE	0x00020000	/* sparse regular file */
+
+/* DASD Limits		F226941 */
+#define JFS_DASD_ENABLED	0x00040000	/* DASD limits enabled */
+#define	JFS_DASD_PRIME		0x00080000	/* Prime DASD usage on boot */
+
+/* big endian flag */
+#define	JFS_SWAP_BYTES		0x00100000	/* running on big endian computer */
+
+/* Directory index */
+#define JFS_DIR_INDEX		0x00200000	/* Persistant index for */
+						/* directory entries    */
+
+
+/*
+ *	buffer cache configuration
+ */
+/* page size */
+#ifdef PSIZE
+#undef PSIZE
+#endif
+#define	PSIZE		4096	/* page size (in byte) */
+#define	L2PSIZE		12	/* log2(PSIZE) */
+#define	POFFSET		4095	/* offset within page */
+
+/* buffer page size */
+#define BPSIZE	PSIZE
+
+/*
+ *	fs fundamental size
+ *
+ * PSIZE >= file system block size >= PBSIZE >= DISIZE
+ */
+#define	PBSIZE		512	/* physical block size (in byte) */
+#define	L2PBSIZE	9	/* log2(PBSIZE) */
+
+#define DISIZE		512	/* on-disk inode size (in byte) */
+#define L2DISIZE	9	/* log2(DISIZE) */
+
+#define IDATASIZE	256	/* inode inline data size */
+#define	IXATTRSIZE	128	/* inode inline extended attribute size */
+
+#define XTPAGE_SIZE     4096
+#define log2_PAGESIZE     12
+
+#define IAG_SIZE        4096
+#define IAG_EXTENT_SIZE 4096
+#define	INOSPERIAG	4096	/* number of disk inodes per iag */
+#define	L2INOSPERIAG	12	/* l2 number of disk inodes per iag */
+#define INOSPEREXT	32	/* number of disk inode per extent */
+#define L2INOSPEREXT	5	/* l2 number of disk inode per extent */
+#define	IXSIZE		(DISIZE * INOSPEREXT)	/* inode extent size */
+#define	INOSPERPAGE	8	/* number of disk inodes per 4K page */
+#define	L2INOSPERPAGE	3	/* log2(INOSPERPAGE) */
+
+#define	IAGFREELIST_LWM	64
+
+#define INODE_EXTENT_SIZE	IXSIZE	/* inode extent size */
+#define NUM_INODE_PER_EXTENT	INOSPEREXT
+#define NUM_INODE_PER_IAG	INOSPERIAG
+
+#define MINBLOCKSIZE		512
+#define MAXBLOCKSIZE		4096
+#define	MAXFILESIZE		((s64)1 << 52)
+
+#define JFS_LINK_MAX		65535	/* nlink_t is unsigned short */
+
+/* Minimum number of bytes supported for a JFS partition */
+#define MINJFS			(0x1000000)
+#define MINJFSTEXT		"16"
+
+/*
+ * file system block size -> physical block size
+ */
+#define LBOFFSET(x)	((x) & (PBSIZE - 1))
+#define LBNUMBER(x)	((x) >> L2PBSIZE)
+#define	LBLK2PBLK(sb,b)	((b) << (sb->s_blocksize_bits - L2PBSIZE))
+#define	PBLK2LBLK(sb,b)	((b) >> (sb->s_blocksize_bits - L2PBSIZE))
+/* size in byte -> last page number */
+#define	SIZE2PN(size)	( ((s64)((size) - 1)) >> (L2PSIZE) )
+/* size in byte -> last file system block number */
+#define	SIZE2BN(size, l2bsize) ( ((s64)((size) - 1)) >> (l2bsize) )
+
+/*
+ * fixed physical block address (physical block size = 512 byte)
+ *
+ * NOTE: since we can't guarantee a physical block size of 512 bytes the use of
+ *	 these macros should be removed and the byte offset macros used instead.
+ */
+#define SUPER1_B	64	/* primary superblock */
+#define	AIMAP_B		(SUPER1_B + 8)	/* 1st extent of aggregate inode map */
+#define	AITBL_B		(AIMAP_B + 16)	/*
+					 * 1st extent of aggregate inode table
+					 */
+#define	SUPER2_B	(AITBL_B + 32)	/* 2ndary superblock pbn */
+#define	BMAP_B		(SUPER2_B + 8)	/* block allocation map */
+
+/*
+ * SIZE_OF_SUPER defines the total amount of space reserved on disk for the
+ * superblock.  This is not the same as the superblock structure, since all of
+ * this space is not currently being used.
+ */
+#define SIZE_OF_SUPER	PSIZE
+
+/*
+ * SIZE_OF_AG_TABLE defines the amount of space reserved to hold the AG table
+ */
+#define SIZE_OF_AG_TABLE	PSIZE
+
+/*
+ * SIZE_OF_MAP_PAGE defines the amount of disk space reserved for each page of
+ * the inode allocation map (to hold iag)
+ */
+#define SIZE_OF_MAP_PAGE	PSIZE
+
+/*
+ * fixed byte offset address
+ */
+#define SUPER1_OFF	0x8000	/* primary superblock */
+#define AIMAP_OFF	(SUPER1_OFF + SIZE_OF_SUPER)
+					/*
+					 * Control page of aggregate inode map
+					 * followed by 1st extent of map
+					 */
+#define AITBL_OFF	(AIMAP_OFF + (SIZE_OF_MAP_PAGE << 1))
+					/* 
+					 * 1st extent of aggregate inode table
+					 */
+#define SUPER2_OFF	(AITBL_OFF + INODE_EXTENT_SIZE)
+					/*
+					 * secondary superblock
+					 */
+#define BMAP_OFF	(SUPER2_OFF + SIZE_OF_SUPER)
+					/*
+					 * block allocation map
+					 */
+
+/*
+ * The following macro is used to indicate the number of reserved disk blocks at
+ * the front of an aggregate, in terms of physical blocks.  This value is
+ * currently defined to be 32K.  This turns out to be the same as the primary
+ * superblock's address, since it directly follows the reserved blocks.
+ */
+#define AGGR_RSVD_BLOCKS	SUPER1_B
+
+/*
+ * The following macro is used to indicate the number of reserved bytes at the
+ * front of an aggregate.  This value is currently defined to be 32K.  This
+ * turns out to be the same as the primary superblock's byte offset, since it
+ * directly follows the reserved blocks.
+ */
+#define AGGR_RSVD_BYTES	SUPER1_OFF
+
+/*
+ * The following macro defines the byte offset for the first inode extent in
+ * the aggregate inode table.  This allows us to find the self inode to find the
+ * rest of the table.  Currently this value is 44K.
+ */
+#define AGGR_INODE_TABLE_START	AITBL_OFF
+
+/*
+ *	fixed reserved inode number
+ */
+/* aggregate inode */
+#define AGGR_RESERVED_I	0	/* aggregate inode (reserved) */
+#define	AGGREGATE_I	1	/* aggregate inode map inode */
+#define	BMAP_I		2	/* aggregate block allocation map inode */
+#define	LOG_I		3	/* aggregate inline log inode */
+#define BADBLOCK_I	4	/* aggregate bad block inode */
+#define	FILESYSTEM_I	16	/* 1st/only fileset inode in ait:
+				 * fileset inode map inode
+				 */
+
+/* per fileset inode */
+#define FILESET_RSVD_I	0	/* fileset inode (reserved) */
+#define FILESET_EXT_I	1	/* fileset inode extension */
+#define	ROOT_I		2	/* fileset root inode */
+#define ACL_I		3	/* fileset ACL inode */
+
+#define FILESET_OBJECT_I 4	/* the first fileset inode available for a file
+				 * or directory or link...
+				 */
+#define FIRST_FILESET_INO 16	/* the first aggregate inode which describes
+				 * an inode.  (To fsck this is also the first
+				 * inode in part 2 of the agg inode table.)
+				 */
+
+/*
+ *	directory configuration
+ */
+#define JFS_NAME_MAX	255
+#define JFS_PATH_MAX	BPSIZE
+
+
+/*
+ *	file system state (superblock state)
+ */
+#define FM_CLEAN 0x00000000	/* file system is unmounted and clean */
+#define FM_MOUNT 0x00000001	/* file system is mounted cleanly */
+#define FM_DIRTY 0x00000002	/* file system was not unmounted and clean 
+				 * when mounted or 
+				 * commit failure occurred while being mounted:
+				 * fsck() must be run to repair 
+				 */
+#define	FM_LOGREDO 0x00000004	/* log based recovery (logredo()) failed:
+				 * fsck() must be run to repair 
+				 */
+#define	FM_EXTENDFS 0x00000008	/* file system extendfs() in progress */
+
+#endif				/* _H_JFS_FILSYS */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_imap.c linux-2.5.6-pre2/fs/jfs/jfs_imap.c
--- linux-2.5.6-pre1/fs/jfs/jfs_imap.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_imap.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,3212 @@
+/*
+
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/*
+ * Change History :
+ *
+ */
+
+/*
+ *	jfs_imap.c: inode allocation map manager
+ *
+ * Serialization:
+ *   Each AG has a simple lock which is used to control the serialization of
+ *	the AG level lists.  This lock should be taken first whenever an AG
+ *	level list will be modified or accessed.
+ *
+ *   Each IAG is locked by obtaining the buffer for the IAG page.
+ *
+ *   There is also a inode lock for the inode map inode.  A read lock needs to
+ *	be taken whenever an IAG is read from the map or the global level
+ *	information is read.  A write lock needs to be taken whenever the global
+ *	level information is modified or an atomic operation needs to be used.
+ *
+ *	If more than one IAG is read at one time, the read lock may not
+ *	be given up until all of the IAG's are read.  Otherwise, a deadlock
+ *	may occur when trying to obtain the read lock while another thread
+ *	holding the read lock is waiting on the IAG already being held.
+ *
+ *   The control page of the inode map is read into memory by diMount().
+ *	Thereafter it should only be modified in memory and then it will be
+ *	written out when the filesystem is unmounted by diUnmount().
+ */
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/locks.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_dinode.h"
+#include "jfs_dmap.h"
+#include "jfs_imap.h"
+#include "jfs_metapage.h"
+#include "jfs_superblock.h"
+#include "jfs_debug.h"
+
+/*
+ * imap locks
+ */
+/* iag free list lock */
+#define IAGFREE_LOCK_INIT(imap)		init_MUTEX(&imap->im_freelock)
+#define IAGFREE_LOCK(imap)		down(&imap->im_freelock)
+#define IAGFREE_UNLOCK(imap)		up(&imap->im_freelock)
+
+/* per ag iag list locks */
+#define AG_LOCK_INIT(imap,index)	init_MUTEX(&(imap->im_aglock[index]))
+#define AG_LOCK(imap,agno)		down(&imap->im_aglock[agno])
+#define AG_UNLOCK(imap,agno)		up(&imap->im_aglock[agno])
+
+/*
+ * external references
+ */
+extern struct address_space_operations jfs_aops;
+
+/*
+ * forward references
+ */
+static int diAllocAG(imap_t *, int, boolean_t, struct inode *);
+static int diAllocAny(imap_t *, int, boolean_t, struct inode *);
+static int diAllocBit(imap_t *, iag_t *, int);
+static int diAllocExt(imap_t *, int, struct inode *);
+static int diAllocIno(imap_t *, int, struct inode *);
+static int diFindFree(u32, int);
+static int diNewExt(imap_t *, iag_t *, int);
+static int diNewIAG(imap_t *, int *, int, metapage_t **);
+static void duplicateIXtree(struct super_block *, s64, int, s64 *);
+
+static int diIAGRead(imap_t * imap, int, metapage_t **);
+static int copy_from_dinode(dinode_t *, struct inode *);
+static void copy_to_dinode(dinode_t *, struct inode *);
+
+/*
+ *	debug code for double-checking inode map
+ */
+/* #define	_JFS_DEBUG_IMAP	1 */
+
+#ifdef	_JFS_DEBUG_IMAP
+#define DBG_DIINIT(imap)	DBGdiInit(imap)
+#define DBG_DIALLOC(imap, ino)	DBGdiAlloc(imap, ino)
+#define DBG_DIFREE(imap, ino)	DBGdiFree(imap, ino)
+
+static void *DBGdiInit(imap_t * imap);
+static void DBGdiAlloc(imap_t * imap, ino_t ino);
+static void DBGdiFree(imap_t * imap, ino_t ino);
+#else
+#define DBG_DIINIT(imap)
+#define DBG_DIALLOC(imap, ino)
+#define DBG_DIFREE(imap, ino)
+#endif				/* _JFS_DEBUG_IMAP */
+
+/*
+ * NAME:        diMount()
+ *
+ * FUNCTION:    initialize the incore inode map control structures for
+ *		a fileset or aggregate init time.
+ *
+ *              the inode map's control structure (dinomap_t) is 
+ *              brought in from disk and placed in virtual memory.
+ *
+ * PARAMETERS:
+ *      ipimap  - pointer to inode map inode for the aggregate or fileset.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      ENOMEM  - insufficient free virtual memory.
+ *      EIO  	- i/o error.
+ */
+int diMount(struct inode *ipimap)
+{
+	imap_t *imap;
+	metapage_t *mp;
+	int index;
+	dinomap_t *dinom_le;
+
+	/*
+	 * allocate/initialize the in-memory inode map control structure
+	 */
+	/* allocate the in-memory inode map control structure. */
+	imap = (imap_t *) kmalloc(sizeof(imap_t), GFP_KERNEL);
+	if (imap == NULL) {
+		jERROR(1, ("diMount: kmalloc returned NULL!\n"));
+		return (ENOMEM);
+	}
+
+	/* read the on-disk inode map control structure. */
+
+	mp = read_metapage(ipimap,
+			   IMAPBLKNO << JFS_SBI(ipimap->i_sb)->l2nbperpage,
+			   PSIZE, 0);
+	if (mp == NULL) {
+		kfree(imap);
+		return (EIO);
+	}
+
+	/* copy the on-disk version to the in-memory version. */
+	dinom_le = (dinomap_t *) mp->data;
+	imap->im_freeiag = le32_to_cpu(dinom_le->in_freeiag);
+	imap->im_nextiag = le32_to_cpu(dinom_le->in_nextiag);
+	atomic_set(&imap->im_numinos, le32_to_cpu(dinom_le->in_numinos));
+	atomic_set(&imap->im_numfree, le32_to_cpu(dinom_le->in_numfree));
+	imap->im_nbperiext = le32_to_cpu(dinom_le->in_nbperiext);
+	imap->im_l2nbperiext = le32_to_cpu(dinom_le->in_l2nbperiext);
+	for (index = 0; index < MAXAG; index++) {
+		imap->im_agctl[index].inofree =
+		    le32_to_cpu(dinom_le->in_agctl[index].inofree);
+		imap->im_agctl[index].extfree =
+		    le32_to_cpu(dinom_le->in_agctl[index].extfree);
+		imap->im_agctl[index].numinos =
+		    le32_to_cpu(dinom_le->in_agctl[index].numinos);
+		imap->im_agctl[index].numfree =
+		    le32_to_cpu(dinom_le->in_agctl[index].numfree);
+	}
+
+	/* release the buffer. */
+	release_metapage(mp);
+
+	/*
+	 * allocate/initialize inode allocation map locks
+	 */
+	/* allocate and init iag free list lock */
+	IAGFREE_LOCK_INIT(imap);
+
+	/* allocate and init ag list locks */
+	for (index = 0; index < MAXAG; index++) {
+		AG_LOCK_INIT(imap, index);
+	}
+
+	/* bind the inode map inode and inode map control structure
+	 * to each other.
+	 */
+	imap->im_ipimap = ipimap;
+	JFS_IP(ipimap)->i_imap = imap;
+
+//      DBG_DIINIT(imap);
+
+	return (0);
+}
+
+
+/*
+ * NAME:        diUnmount()
+ *
+ * FUNCTION:    write to disk the incore inode map control structures for
+ *		a fileset or aggregate at unmount time.
+ *
+ * PARAMETERS:
+ *      ipimap  - pointer to inode map inode for the aggregate or fileset.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      ENOMEM  - insufficient free virtual memory.
+ *      EIO  	- i/o error.
+ */
+int diUnmount(struct inode *ipimap, int mounterror)
+{
+	imap_t *imap = JFS_IP(ipimap)->i_imap;
+
+	/*
+	 * update the on-disk inode map control structure
+	 */
+
+	if (!(mounterror || isReadOnly(ipimap)))
+		diSync(ipimap);
+
+	/*
+	 * Invalidate the page cache buffers
+	 */
+	truncate_inode_pages(ipimap->i_mapping, 0);
+
+	/*
+	 * free in-memory control structure
+	 */
+	kfree(imap);
+
+	return (0);
+}
+
+
+/*
+ *	diSync()
+ */
+int diSync(struct inode *ipimap)
+{
+	dinomap_t *dinom_le;
+	imap_t *imp = JFS_IP(ipimap)->i_imap;
+	metapage_t *mp;
+	int index;
+
+	/*
+	 * write imap global conrol page
+	 */
+	/* read the on-disk inode map control structure */
+	mp = get_metapage(ipimap,
+			  IMAPBLKNO << JFS_SBI(ipimap->i_sb)->l2nbperpage,
+			  PSIZE, 0);
+	if (mp == NULL) {
+		jERROR(1,("diSync: get_metapage failed!\n"));
+		return EIO;
+	}
+
+	/* copy the in-memory version to the on-disk version */
+	//memcpy(mp->data, &imp->im_imap,sizeof(dinomap_t));
+	dinom_le = (dinomap_t *) mp->data;
+	dinom_le->in_freeiag = cpu_to_le32(imp->im_freeiag);
+	dinom_le->in_nextiag = cpu_to_le32(imp->im_nextiag);
+	dinom_le->in_numinos = cpu_to_le32(atomic_read(&imp->im_numinos));
+	dinom_le->in_numfree = cpu_to_le32(atomic_read(&imp->im_numfree));
+	dinom_le->in_nbperiext = cpu_to_le32(imp->im_nbperiext);
+	dinom_le->in_l2nbperiext = cpu_to_le32(imp->im_l2nbperiext);
+	for (index = 0; index < MAXAG; index++) {
+		dinom_le->in_agctl[index].inofree =
+		    cpu_to_le32(imp->im_agctl[index].inofree);
+		dinom_le->in_agctl[index].extfree =
+		    cpu_to_le32(imp->im_agctl[index].extfree);
+		dinom_le->in_agctl[index].numinos =
+		    cpu_to_le32(imp->im_agctl[index].numinos);
+		dinom_le->in_agctl[index].numfree =
+		    cpu_to_le32(imp->im_agctl[index].numfree);
+	}
+
+	/* write out the control structure */
+	write_metapage(mp);
+
+	/*
+	 * write out dirty pages of imap
+	 */
+	fsync_inode_data_buffers(ipimap);
+
+	diWriteSpecial(ipimap);
+
+	return (0);
+}
+
+
+/*
+ * NAME:        diRead()
+ *
+ * FUNCTION:    initialize an incore inode from disk.
+ *
+ *		on entry, the specifed incore inode should itself
+ *		specify the disk inode number corresponding to the
+ *		incore inode (i.e. i_number should be initialized).
+ *		
+ *		this routine handles incore inode initialization for
+ *		both "special" and "regular" inodes.  special inodes
+ *		are those required early in the mount process and
+ *	        require special handling since much of the file system
+ *		is not yet initialized.  these "special" inodes are
+ *		identified by a NULL inode map inode pointer and are
+ *		actually initialized by a call to diReadSpecial().
+ *		
+ *		for regular inodes, the iag describing the disk inode
+ *		is read from disk to determine the inode extent address
+ *		for the disk inode.  with the inode extent address in
+ *		hand, the page of the extent that contains the disk
+ *		inode is read and the disk inode is copied to the
+ *		incore inode.
+ *
+ * PARAMETERS:
+ *      ip  -  pointer to incore inode to be initialized from disk.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO  	- i/o error.
+ *      ENOMEM	- insufficient memory
+ *      
+ */
+int diRead(struct inode *ip)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+	int iagno, ino, extno, rc;
+	struct inode *ipimap;
+	dinode_t *dp;
+	iag_t *iagp;
+	metapage_t *mp;
+	s64 blkno, agstart;
+	imap_t *imap;
+	int block_offset;
+	int inodes_left;
+	uint pageno;
+	int rel_inode;
+
+	jFYI(1, ("diRead: ino = %ld\n", ip->i_ino));
+
+	ipimap = sbi->ipimap;
+	JFS_IP(ip)->ipimap = ipimap;
+
+	/* determine the iag number for this inode (number) */
+	iagno = INOTOIAG(ip->i_ino);
+
+	/* read the iag */
+	imap = JFS_IP(ipimap)->i_imap;
+	IREAD_LOCK(ipimap);
+	rc = diIAGRead(imap, iagno, &mp);
+	IREAD_UNLOCK(ipimap);
+	if (rc) {
+		jERROR(1, ("diRead: diIAGRead returned %d\n", rc));
+		return (rc);
+	}
+
+	iagp = (iag_t *) mp->data;
+
+	/* determine inode extent that holds the disk inode */
+	ino = ip->i_ino & (INOSPERIAG - 1);
+	extno = ino >> L2INOSPEREXT;
+
+	if ((lengthPXD(&iagp->inoext[extno]) != imap->im_nbperiext) ||
+	    (addressPXD(&iagp->inoext[extno]) == 0)) {
+		jERROR(1, ("diRead: Bad inoext: 0x%lx, 0x%lx\n",
+			   (ulong) addressPXD(&iagp->inoext[extno]),
+			   (ulong) lengthPXD(&iagp->inoext[extno])));
+		release_metapage(mp);
+		updateSuper(ip->i_sb, FM_DIRTY);
+		return ESTALE;
+	}
+
+	/* get disk block number of the page within the inode extent
+	 * that holds the disk inode.
+	 */
+	blkno = INOPBLK(&iagp->inoext[extno], ino, sbi->l2nbperpage);
+
+	/* get the ag for the iag */
+	agstart = le64_to_cpu(iagp->agstart);
+
+	release_metapage(mp);
+
+	rel_inode = (ino & (INOSPERPAGE - 1));
+	pageno = blkno >> sbi->l2nbperpage;
+
+	if ((block_offset = ((u32) blkno & (sbi->nbperpage - 1)))) {
+		/*
+		 * OS/2 didn't always align inode extents on page boundaries
+		 */
+		inodes_left =
+		     (sbi->nbperpage - block_offset) << sbi->l2niperblk;
+
+		if (rel_inode < inodes_left)
+			rel_inode += block_offset << sbi->l2niperblk;
+		else {
+			pageno += 1;
+			rel_inode -= inodes_left;
+		}
+	}
+
+	/* read the page of disk inode */
+	mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1);
+	if (mp == 0) {
+		jERROR(1, ("diRead: read_metapage failed\n"));
+		return EIO;
+	}
+
+	/* locate the the disk inode requested */
+	dp = (dinode_t *) mp->data;
+	dp += rel_inode;
+
+	if (ip->i_ino != le32_to_cpu(dp->di_number)) {
+		jERROR(1, ("diRead: i_ino != di_number\n"));
+		updateSuper(ip->i_sb, FM_DIRTY);
+		rc = EIO;
+	} else if (le32_to_cpu(dp->di_nlink) == 0) {
+		jERROR(1,
+		       ("diRead: di_nlink is zero. ino=%ld\n", ip->i_ino));
+		updateSuper(ip->i_sb, FM_DIRTY);
+		rc = ESTALE;
+	} else
+		/* copy the disk inode to the in-memory inode */
+		rc = copy_from_dinode(dp, ip);
+
+	release_metapage(mp);
+
+	/* set the ag for the inode */
+	JFS_IP(ip)->agno = BLKTOAG(agstart, sbi);
+
+	return (rc);
+}
+
+
+/*
+ * NAME:        diReadSpecial()
+ *
+ * FUNCTION:    initialize a 'special' inode from disk.
+ *
+ *		this routines handles aggregate level inodes.  The
+ *		inode cache cannot differentiate between the
+ *		aggregate inodes and the filesystem inodes, so we
+ *		handle these here.  We don't actually use the aggregate
+ *	        inode map, since these inodes are at a fixed location
+ *		and in some cases the aggregate inode map isn't initialized
+ *		yet.
+ *
+ * PARAMETERS:
+ *      sb - filesystem superblock
+ *	inum - aggregate inode number
+ *
+ * RETURN VALUES:
+ *      new inode	- success
+ *      NULL		- i/o error.
+ */
+struct inode *diReadSpecial(struct super_block *sb, ino_t inum)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	uint address;
+	dinode_t *dp;
+	struct inode *ip;
+	metapage_t *mp;
+
+	ip = new_inode(sb);
+	if (ip == NULL) {
+		jERROR(1,
+		       ("diReadSpecial: new_inode returned NULL!\n"));
+		return ip;
+	}
+
+	/*
+	 * If ip->i_number >= 32 (INOSPEREXT), then read from secondary
+	 * aggregate inode table.
+	 */
+
+	if (inum >= INOSPEREXT) {
+		address =
+		    addressPXD(&sbi->ait2) >> sbi->l2nbperpage;
+		inum -= INOSPEREXT;
+		ASSERT(inum < INOSPEREXT);
+		JFS_IP(ip)->ipimap = sbi->ipaimap2;
+	} else {
+		address = AITBL_OFF >> L2PSIZE;
+		JFS_IP(ip)->ipimap = sbi->ipaimap;
+	}
+	ip->i_ino = inum;
+
+	address += inum >> 3;	/* 8 inodes per 4K page */
+
+	/* read the page of fixed disk inode (AIT) in raw mode */
+	jEVENT(0,
+	       ("Reading aggregate inode %d from block %d\n", (uint) inum,
+		address));
+	mp = read_metapage(ip, address << sbi->l2nbperpage, PSIZE, 1);
+	if (mp == NULL) {
+		ip->i_sb = NULL;
+		ip->i_nlink = 1;	/* Don't want iput() deleting it */
+		iput(ip);
+		return (NULL);
+	}
+
+	/* get the pointer to the disk inode of interest */
+	dp = (dinode_t *) (mp->data);
+	dp += inum % 8;		/* 8 inodes per 4K page */
+
+	/* copy on-disk inode to in-memory inode */
+	if ((copy_from_dinode(dp, ip)) != 0) {
+		/* handle bad return by returning NULL for ip */
+		ip->i_sb = NULL;
+		ip->i_nlink = 1;	/* Don't want iput() deleting it */
+		iput(ip);
+		/* release the page */
+		release_metapage(mp);
+		return (NULL);
+
+	}
+
+	ip->i_mapping->a_ops = &jfs_aops;
+	ip->i_mapping->gfp_mask = GFP_NOFS;
+
+	if ((inum == FILESYSTEM_I) && (JFS_IP(ip)->ipimap == sbi->ipaimap)) {
+		sbi->gengen = le32_to_cpu(dp->di_gengen);
+		sbi->inostamp = le32_to_cpu(dp->di_inostamp);
+	}
+
+	/* release the page */
+	release_metapage(mp);
+
+	return (ip);
+}
+
+/*
+ * NAME:        diWriteSpecial()
+ *
+ * FUNCTION:    Write the special inode to disk
+ *
+ * PARAMETERS:
+ *      ip - special inode
+ *
+ * RETURN VALUES: none
+ */
+
+void diWriteSpecial(struct inode *ip)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+	uint address;
+	dinode_t *dp;
+	ino_t inum = ip->i_ino;
+	metapage_t *mp;
+
+	/*
+	 * If ip->i_number >= 32 (INOSPEREXT), then write to secondary
+	 * aggregate inode table.
+	 */
+
+	if (!(ip->i_state & I_DIRTY))
+		return;
+
+	ip->i_state &= ~I_DIRTY;
+
+	if (inum >= INOSPEREXT) {
+		address =
+		    addressPXD(&sbi->ait2) >> sbi->l2nbperpage;
+		inum -= INOSPEREXT;
+		ASSERT(inum < INOSPEREXT);
+	} else {
+		address = AITBL_OFF >> L2PSIZE;
+	}
+
+	address += inum >> 3;	/* 8 inodes per 4K page */
+
+	/* read the page of fixed disk inode (AIT) in raw mode */
+	jEVENT(0,
+	       ("Reading aggregate inode %d from block %d\n", (uint) inum,
+		address));
+	mp = read_metapage(ip, address << sbi->l2nbperpage, PSIZE, 1);
+	if (mp == NULL) {
+		jERROR(1,
+		       ("diWriteSpecial: failed to read aggregate inode extent!\n"));
+		return;
+	}
+
+	/* get the pointer to the disk inode of interest */
+	dp = (dinode_t *) (mp->data);
+	dp += inum % 8;		/* 8 inodes per 4K page */
+
+	/* copy on-disk inode to in-memory inode */
+	copy_to_dinode(dp, ip);
+	memcpy(&dp->di_xtroot, &JFS_IP(ip)->i_xtroot, 288);
+
+	if (inum == FILESYSTEM_I)
+		dp->di_gengen = cpu_to_le32(sbi->gengen);
+
+	/* write the page */
+	write_metapage(mp);
+}
+
+/*
+ * NAME:        diFreeSpecial()
+ *
+ * FUNCTION:    Free allocated space for special inode
+ */
+void diFreeSpecial(struct inode *ip)
+{
+	if (ip == NULL) {
+		jERROR(1, ("diFreeSpecial called with NULL ip!\n"));
+		return;
+	}
+	fsync_inode_data_buffers(ip);
+	truncate_inode_pages(ip->i_mapping, 0);
+	iput(ip);
+}
+
+
+
+/*
+ * NAME:        diWrite()
+ *
+ * FUNCTION:    write the on-disk inode portion of the in-memory inode
+ *		to its corresponding on-disk inode.
+ *
+ *		on entry, the specifed incore inode should itself
+ *		specify the disk inode number corresponding to the
+ *		incore inode (i.e. i_number should be initialized).
+ *
+ *		the inode contains the inode extent address for the disk
+ *		inode.  with the inode extent address in hand, the
+ *		page of the extent that contains the disk inode is
+ *		read and the disk inode portion of the incore inode
+ *		is copied to the disk inode.
+ *		
+ * PARAMETERS:
+ *	tid -  transacation id
+ *      ip  -  pointer to incore inode to be written to the inode extent.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO  	- i/o error.
+ */
+int diWrite(tid_t tid, struct inode *ip)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	int rc = 0;
+	s32 ino;
+	dinode_t *dp;
+	s64 blkno;
+	int block_offset;
+	int inodes_left;
+	metapage_t *mp;
+	uint pageno;
+	int rel_inode;
+	int dioffset;
+	struct inode *ipimap;
+	uint type;
+	lid_t lid;
+	tlock_t *ditlck, *tlck;
+	linelock_t *dilinelock, *ilinelock;
+	lv_t *lv;
+	int n;
+
+	ipimap = jfs_ip->ipimap;
+
+	ino = ip->i_ino & (INOSPERIAG - 1);
+
+	assert(lengthPXD(&(jfs_ip->ixpxd)) ==
+	       JFS_IP(ipimap)->i_imap->im_nbperiext);
+	assert(addressPXD(&(jfs_ip->ixpxd)));
+
+	/*
+	 * read the page of disk inode containing the specified inode:
+	 */
+	/* compute the block address of the page */
+	blkno = INOPBLK(&(jfs_ip->ixpxd), ino, sbi->l2nbperpage);
+
+	rel_inode = (ino & (INOSPERPAGE - 1));
+	pageno = blkno >> sbi->l2nbperpage;
+
+	if ((block_offset = ((u32) blkno & (sbi->nbperpage - 1)))) {
+		/*
+		 * OS/2 didn't always align inode extents on page boundaries
+		 */
+		inodes_left =
+		    (sbi->nbperpage - block_offset) << sbi->l2niperblk;
+
+		if (rel_inode < inodes_left)
+			rel_inode += block_offset << sbi->l2niperblk;
+		else {
+			pageno += 1;
+			rel_inode -= inodes_left;
+		}
+	}
+	/* read the page of disk inode */
+      retry:
+	mp = read_metapage(ipimap, pageno << sbi->l2nbperpage, PSIZE, 1);
+	if (mp == 0)
+		return (EIO);
+
+	/* get the pointer to the disk inode */
+	dp = (dinode_t *) mp->data;
+	dp += rel_inode;
+
+	dioffset = (ino & (INOSPERPAGE - 1)) << L2DISIZE;
+
+	/*
+	 * acquire transaction lock on the on-disk inode;
+	 * N.B. tlock is acquired on ipimap not ip;
+	 */
+	if ((ditlck =
+	     txLock(tid, ipimap, mp, tlckINODE | tlckENTRY)) == NULL)
+		goto retry;
+	dilinelock = (linelock_t *) & ditlck->lock;
+
+	/*
+	 * copy btree root from in-memory inode to on-disk inode
+	 *
+	 * (tlock is taken from inline B+-tree root in in-memory
+	 * inode when the B+-tree root is updated, which is pointed 
+	 * by jfs_ip->blid as well as being on tx tlock list)
+	 *
+	 * further processing of btree root is based on the copy 
+	 * in in-memory inode, where txLog() will log from, and, 
+	 * for xtree root, txUpdateMap() will update map and reset
+	 * XAD_NEW bit;
+	 */
+
+	if (S_ISDIR(ip->i_mode) && (lid = jfs_ip->xtlid)) {
+		/*
+		 * This is the special xtree inside the directory for storing
+		 * the directory table
+		 */
+		xtpage_t *p, *xp;
+		xad_t *xad;
+
+		jfs_ip->xtlid = 0;
+		tlck = lid_to_tlock(lid);
+		assert(tlck->type & tlckXTREE);
+		tlck->type |= tlckBTROOT;
+		tlck->mp = mp;
+		ilinelock = (linelock_t *) & tlck->lock;
+
+		/*
+		 * copy xtree root from inode to dinode:
+		 */
+		p = &jfs_ip->i_xtroot;
+		xp = (xtpage_t *) &dp->di_dirtable;
+		lv = (lv_t *) & ilinelock->lv;
+		for (n = 0; n < ilinelock->index; n++, lv++) {
+			memcpy(&xp->xad[lv->offset], &p->xad[lv->offset],
+			       lv->length << L2XTSLOTSIZE);
+		}
+
+		/* reset on-disk (metadata page) xtree XAD_NEW bit */
+		xad = &xp->xad[XTENTRYSTART];
+		for (n = XTENTRYSTART;
+		     n < le16_to_cpu(xp->header.nextindex); n++, xad++)
+			if (xad->flag & (XAD_NEW | XAD_EXTENDED))
+				xad->flag &= ~(XAD_NEW | XAD_EXTENDED);
+	}
+
+	if ((lid = jfs_ip->blid) == 0)
+		goto inlineData;
+	jfs_ip->blid = 0;
+
+	tlck = lid_to_tlock(lid);
+	type = tlck->type;
+	tlck->type |= tlckBTROOT;
+	tlck->mp = mp;
+	ilinelock = (linelock_t *) & tlck->lock;
+
+	/*
+	 *      regular file: 16 byte (XAD slot) granularity
+	 */
+	if (type & tlckXTREE) {
+		xtpage_t *p, *xp;
+		xad_t *xad;
+
+		/*
+		 * copy xtree root from inode to dinode:
+		 */
+		p = &jfs_ip->i_xtroot;
+		xp = &dp->di_xtroot;
+		lv = (lv_t *) & ilinelock->lv;
+		for (n = 0; n < ilinelock->index; n++, lv++) {
+			memcpy(&xp->xad[lv->offset], &p->xad[lv->offset],
+			       lv->length << L2XTSLOTSIZE);
+		}
+
+		/* reset on-disk (metadata page) xtree XAD_NEW bit */
+		xad = &xp->xad[XTENTRYSTART];
+		for (n = XTENTRYSTART;
+		     n < le16_to_cpu(xp->header.nextindex); n++, xad++)
+			if (xad->flag & (XAD_NEW | XAD_EXTENDED))
+				xad->flag &= ~(XAD_NEW | XAD_EXTENDED);
+	}
+	/*
+	 *      directory: 32 byte (directory entry slot) granularity
+	 */
+	else if (type & tlckDTREE) {
+		dtpage_t *p, *xp;
+
+		/*
+		 * copy dtree root from inode to dinode:
+		 */
+		p = (dtpage_t *) &jfs_ip->i_dtroot;
+		xp = (dtpage_t *) & dp->di_dtroot;
+		lv = (lv_t *) & ilinelock->lv;
+		for (n = 0; n < ilinelock->index; n++, lv++) {
+			memcpy(&xp->slot[lv->offset], &p->slot[lv->offset],
+			       lv->length << L2DTSLOTSIZE);
+		}
+	} else {
+		jERROR(1, ("diWrite: UFO tlock\n"));
+	}
+
+      inlineData:
+	/*
+	 * copy inline symlink from in-memory inode to on-disk inode
+	 */
+	if (S_ISLNK(ip->i_mode) && ip->i_size < IDATASIZE) {
+		lv = (lv_t *) & dilinelock->lv[dilinelock->index];
+		lv->offset = (dioffset + 2 * 128) >> L2INODESLOTSIZE;
+		lv->length = 2;
+		memcpy(&dp->di_fastsymlink, jfs_ip->i_inline, IDATASIZE);
+		dilinelock->index++;
+	}
+#ifdef _STILL_TO_PORT
+	/*
+	 * copy inline data from in-memory inode to on-disk inode:
+	 * 128 byte slot granularity
+	 */
+	if (test_cflag(COMMIT_Inlineea, ip))
+		lv = (lv_t *) & dilinelock->lv[dilinelock->index];
+		lv->offset = (dioffset + 3 * 128) >> L2INODESLOTSIZE;
+		lv->length = 1;
+		memcpy(&dp->di_inlineea, &ip->i_inlineea, INODESLOTSIZE);
+		dilinelock->index++;
+
+		clear_cflag(COMMIT_Inlineea, ip);
+	}
+#endif				/* _STILL_TO_PORT */
+
+	/*
+	 *      lock/copy inode base: 128 byte slot granularity
+	 */
+// baseDinode:
+	lv = (lv_t *) & dilinelock->lv[dilinelock->index];
+	lv->offset = dioffset >> L2INODESLOTSIZE;
+	copy_to_dinode(dp, ip);
+	if (test_and_clear_cflag(COMMIT_Dirtable, ip)) {
+		lv->length = 2;
+		memcpy(&dp->di_dirtable, &jfs_ip->i_dirtable, 96);
+	} else
+		lv->length = 1;
+	dilinelock->index++;
+
+#ifdef _JFS_FASTDASD
+	/*
+	 * We aren't logging changes to the DASD used in directory inodes,
+	 * but we need to write them to disk.  If we don't unmount cleanly,
+	 * mount will recalculate the DASD used.
+	 */
+	if (S_ISDIR(ip->i_mode)
+	    && (ip->i_ipmnt->i_mntflag & JFS_DASD_ENABLED))
+		bcopy(&ip->i_DASD, &dp->di_DASD, sizeof(dasd_t));
+#endif				/*  _JFS_FASTDASD */
+
+	/* release the buffer holding the updated on-disk inode. 
+	 * the buffer will be later written by commit processing.
+	 */
+	write_metapage(mp);
+
+	return (rc);
+}
+
+
+/*
+ * NAME:        diFree(ip)
+ *
+ * FUNCTION:    free a specified inode from the inode working map
+ *		for a fileset or aggregate.
+ *
+ *		if the inode to be freed represents the first (only)
+ *		free inode within the iag, the iag will be placed on
+ *		the ag free inode list.
+ *	
+ *		freeing the inode will cause the inode extent to be
+ *		freed if the inode is the only allocated inode within
+ *		the extent.  in this case all the disk resource backing
+ *		up the inode extent will be freed. in addition, the iag
+ *		will be placed on the ag extent free list if the extent
+ *		is the first free extent in the iag.  if freeing the
+ *		extent also means that no free inodes will exist for
+ *		the iag, the iag will also be removed from the ag free
+ *		inode list.
+ *
+ *		the iag describing the inode will be freed if the extent
+ *		is to be freed and it is the only backed extent within
+ *		the iag.  in this case, the iag will be removed from the
+ *		ag free extent list and ag free inode list and placed on
+ *		the inode map's free iag list.
+ *
+ *		a careful update approach is used to provide consistency
+ *		in the face of updates to multiple buffers.  under this
+ *		approach, all required buffers are obtained before making
+ *		any updates and are held until all updates are complete.
+ *
+ * PARAMETERS:
+ *      ip  	- inode to be freed.
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      EIO  	- i/o error.
+ */
+int diFree(struct inode *ip)
+{
+	int rc;
+	ino_t inum = ip->i_ino;
+	iag_t *iagp, *aiagp, *biagp, *ciagp, *diagp;
+	metapage_t *mp, *amp, *bmp, *cmp, *dmp;
+	int iagno, ino, extno, bitno, sword, agno;
+	int back, fwd;
+	u32 bitmap, mask;
+	struct inode *ipimap = JFS_SBI(ip->i_sb)->ipimap;
+	imap_t *imap = JFS_IP(ipimap)->i_imap;
+	s64 xaddr;
+	s64 xlen;
+	pxd_t freepxd;
+	tid_t tid;
+	struct inode *iplist[3];
+	tlock_t *tlck;
+	pxdlock_t *pxdlock;
+
+	/*
+	 * This is just to suppress compiler warnings.  The same logic that
+	 * references these variables is used to initialize them.
+	 */
+	aiagp = biagp = ciagp = diagp = NULL;
+
+	/* get the iag number containing the inode.
+	 */
+	iagno = INOTOIAG(inum);
+
+	/* make sure that the iag is contained within 
+	 * the map.
+	 */
+	//assert(iagno < imap->im_nextiag);
+	if (iagno >= imap->im_nextiag) {
+		jERROR(1, ("diFree: inum = %d, iagno = %d, nextiag = %d\n",
+			   (uint) inum, iagno, imap->im_nextiag));
+		dump_mem("imap", imap, 32);
+		updateSuper(ip->i_sb, FM_DIRTY);
+		return EIO;
+	}
+
+	/* get the allocation group for this ino.
+	 */
+	agno = JFS_IP(ip)->agno;
+
+	/* Lock the AG specific inode map information
+	 */
+	AG_LOCK(imap, agno);
+
+	/* Obtain read lock in imap inode.  Don't release it until we have
+	 * read all of the IAG's that we are going to.
+	 */
+	IREAD_LOCK(ipimap);
+
+	/* read the iag.
+	 */
+	if ((rc = diIAGRead(imap, iagno, &mp))) {
+		IREAD_UNLOCK(ipimap);
+		AG_UNLOCK(imap, agno);
+		return (rc);
+	}
+	iagp = (iag_t *) mp->data;
+
+	/* get the inode number and extent number of the inode within
+	 * the iag and the inode number within the extent.
+	 */
+	ino = inum & (INOSPERIAG - 1);
+	extno = ino >> L2INOSPEREXT;
+	bitno = ino & (INOSPEREXT - 1);
+	mask = HIGHORDER >> bitno;
+
+	assert(le32_to_cpu(iagp->wmap[extno]) & mask);
+#ifdef _STILL_TO_PORT
+	assert((le32_to_cpu(iagp->pmap[extno]) & mask) == 0);
+#endif				/*  _STILL_TO_PORT */
+	assert(addressPXD(&iagp->inoext[extno]));
+
+	/* compute the bitmap for the extent reflecting the freed inode.
+	 */
+	bitmap = le32_to_cpu(iagp->wmap[extno]) & ~mask;
+
+	if (imap->im_agctl[agno].numfree > imap->im_agctl[agno].numinos) {
+		jERROR(1,("diFree: numfree > numinos\n"));
+		release_metapage(mp);
+		IREAD_UNLOCK(ipimap);
+		AG_UNLOCK(imap, agno);
+		updateSuper(ip->i_sb, FM_DIRTY);
+		return EIO;
+	}
+	/*
+	 *      inode extent still has some inodes or below low water mark:
+	 *      keep the inode extent;
+	 */
+	if (bitmap ||
+	    imap->im_agctl[agno].numfree < 96 ||
+	    (imap->im_agctl[agno].numfree < 288 &&
+	     (((imap->im_agctl[agno].numfree * 100) /
+	       imap->im_agctl[agno].numinos) <= 25))) {
+		/* if the iag currently has no free inodes (i.e.,
+		 * the inode being freed is the first free inode of iag),
+		 * insert the iag at head of the inode free list for the ag.
+		 */
+		if (iagp->nfreeinos == 0) {
+			/* check if there are any iags on the ag inode
+			 * free list.  if so, read the first one so that
+			 * we can link the current iag onto the list at
+			 * the head.
+			 */
+			if ((fwd = imap->im_agctl[agno].inofree) >= 0) {
+				/* read the iag that currently is the head
+				 * of the list.
+				 */
+				if ((rc = diIAGRead(imap, fwd, &amp))) {
+					IREAD_UNLOCK(ipimap);
+					AG_UNLOCK(imap, agno);
+					release_metapage(mp);
+					return (rc);
+				}
+				aiagp = (iag_t *) amp->data;
+
+				/* make current head point back to the iag.
+				 */
+				aiagp->inofreeback = cpu_to_le32(iagno);
+
+				write_metapage(amp);
+			}
+
+			/* iag points forward to current head and iag
+			 * becomes the new head of the list.
+			 */
+			iagp->inofreefwd =
+			    cpu_to_le32(imap->im_agctl[agno].inofree);
+			iagp->inofreeback = -1;
+			imap->im_agctl[agno].inofree = iagno;
+		}
+		IREAD_UNLOCK(ipimap);
+
+		/* update the free inode summary map for the extent if
+		 * freeing the inode means the extent will now have free
+		 * inodes (i.e., the inode being freed is the first free 
+		 * inode of extent),
+		 */
+		if (iagp->wmap[extno] == ONES) {
+			sword = extno >> L2EXTSPERSUM;
+			bitno = extno & (EXTSPERSUM - 1);
+			iagp->inosmap[sword] &=
+			    cpu_to_le32(~(HIGHORDER >> bitno));
+		}
+
+		/* update the bitmap.
+		 */
+		iagp->wmap[extno] = cpu_to_le32(bitmap);
+		DBG_DIFREE(imap, inum);
+
+		/* update the free inode counts at the iag, ag and
+		 * map level.
+		 */
+		iagp->nfreeinos =
+		    cpu_to_le32(le32_to_cpu(iagp->nfreeinos) + 1);
+		imap->im_agctl[agno].numfree += 1;
+		atomic_inc(&imap->im_numfree);
+
+		/* release the AG inode map lock
+		 */
+		AG_UNLOCK(imap, agno);
+
+		/* write the iag */
+		write_metapage(mp);
+
+		return (0);
+	}
+
+
+	/*
+	 *      inode extent has become free and above low water mark:
+	 *      free the inode extent;
+	 */
+
+	/*
+	 *      prepare to update iag list(s) (careful update step 1)
+	 */
+	amp = bmp = cmp = dmp = NULL;
+	fwd = back = -1;
+
+	/* check if the iag currently has no free extents.  if so,
+	 * it will be placed on the head of the ag extent free list.
+	 */
+	if (iagp->nfreeexts == 0) {
+		/* check if the ag extent free list has any iags.
+		 * if so, read the iag at the head of the list now.
+		 * this (head) iag will be updated later to reflect
+		 * the addition of the current iag at the head of
+		 * the list.
+		 */
+		if ((fwd = imap->im_agctl[agno].extfree) >= 0) {
+			if ((rc = diIAGRead(imap, fwd, &amp)))
+				goto error_out;
+			aiagp = (iag_t *) amp->data;
+		}
+	} else {
+		/* iag has free extents. check if the addition of a free
+		 * extent will cause all extents to be free within this
+		 * iag.  if so, the iag will be removed from the ag extent
+		 * free list and placed on the inode map's free iag list.
+		 */
+		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG - 1)) {
+			/* in preparation for removing the iag from the
+			 * ag extent free list, read the iags preceeding
+			 * and following the iag on the ag extent free
+			 * list.
+			 */
+			if ((fwd = le32_to_cpu(iagp->extfreefwd)) >= 0) {
+				if ((rc = diIAGRead(imap, fwd, &amp)))
+					goto error_out;
+				aiagp = (iag_t *) amp->data;
+			}
+
+			if ((back = le32_to_cpu(iagp->extfreeback)) >= 0) {
+				if ((rc = diIAGRead(imap, back, &bmp)))
+					goto error_out;
+				biagp = (iag_t *) bmp->data;
+			}
+		}
+	}
+
+	/* remove the iag from the ag inode free list if freeing
+	 * this extent cause the iag to have no free inodes.
+	 */
+	if (iagp->nfreeinos == cpu_to_le32(INOSPEREXT - 1)) {
+		int inofreeback = le32_to_cpu(iagp->inofreeback);
+		int inofreefwd = le32_to_cpu(iagp->inofreefwd);
+
+		/* in preparation for removing the iag from the
+		 * ag inode free list, read the iags preceeding
+		 * and following the iag on the ag inode free
+		 * list.  before reading these iags, we must make
+		 * sure that we already don't have them in hand
+		 * from up above, since re-reading an iag (buffer)
+		 * we are currently holding would cause a deadlock.
+		 */
+		if (inofreefwd >= 0) {
+
+			if (inofreefwd == fwd)
+				ciagp = (iag_t *) amp->data;
+			else if (inofreefwd == back)
+				ciagp = (iag_t *) bmp->data;
+			else {
+				if ((rc =
+				     diIAGRead(imap, inofreefwd, &cmp)))
+					goto error_out;
+				assert(cmp != NULL);
+				ciagp = (iag_t *) cmp->data;
+			}
+			assert(ciagp != NULL);
+		}
+
+		if (inofreeback >= 0) {
+			if (inofreeback == fwd)
+				diagp = (iag_t *) amp->data;
+			else if (inofreeback == back)
+				diagp = (iag_t *) bmp->data;
+			else {
+				if ((rc =
+				     diIAGRead(imap, inofreeback, &dmp)))
+					goto error_out;
+				assert(dmp != NULL);
+				diagp = (iag_t *) dmp->data;
+			}
+			assert(diagp != NULL);
+		}
+	}
+
+	IREAD_UNLOCK(ipimap);
+
+	/*
+	 * invalidate any page of the inode extent freed from buffer cache;
+	 */
+	freepxd = iagp->inoext[extno];
+	xaddr = addressPXD(&iagp->inoext[extno]);
+	xlen = lengthPXD(&iagp->inoext[extno]);
+	invalidate_metapages(JFS_SBI(ip->i_sb)->direct_inode, xaddr, xlen);
+
+	/*
+	 *      update iag list(s) (careful update step 2)
+	 */
+	/* add the iag to the ag extent free list if this is the
+	 * first free extent for the iag.
+	 */
+	if (iagp->nfreeexts == 0) {
+		if (fwd >= 0)
+			aiagp->extfreeback = cpu_to_le32(iagno);
+
+		iagp->extfreefwd =
+		    cpu_to_le32(imap->im_agctl[agno].extfree);
+		iagp->extfreeback = -1;
+		imap->im_agctl[agno].extfree = iagno;
+	} else {
+		/* remove the iag from the ag extent list if all extents
+		 * are now free and place it on the inode map iag free list.
+		 */
+		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG - 1)) {
+			if (fwd >= 0)
+				aiagp->extfreeback = iagp->extfreeback;
+
+			if (back >= 0)
+				biagp->extfreefwd = iagp->extfreefwd;
+			else
+				imap->im_agctl[agno].extfree =
+				    le32_to_cpu(iagp->extfreefwd);
+
+			iagp->extfreefwd = iagp->extfreeback = -1;
+
+			IAGFREE_LOCK(imap);
+			iagp->iagfree = cpu_to_le32(imap->im_freeiag);
+			imap->im_freeiag = iagno;
+			IAGFREE_UNLOCK(imap);
+		}
+	}
+
+	/* remove the iag from the ag inode free list if freeing
+	 * this extent causes the iag to have no free inodes.
+	 */
+	if (iagp->nfreeinos == cpu_to_le32(INOSPEREXT - 1)) {
+		if ((int) le32_to_cpu(iagp->inofreefwd) >= 0)
+			ciagp->inofreeback = iagp->inofreeback;
+
+		if ((int) le32_to_cpu(iagp->inofreeback) >= 0)
+			diagp->inofreefwd = iagp->inofreefwd;
+		else
+			imap->im_agctl[agno].inofree =
+			    le32_to_cpu(iagp->inofreefwd);
+
+		iagp->inofreefwd = iagp->inofreeback = -1;
+	}
+
+	/* update the inode extent address and working map 
+	 * to reflect the free extent.
+	 * the permanent map should have been updated already 
+	 * for the inode being freed.
+	 */
+	assert(iagp->pmap[extno] == 0);
+	iagp->wmap[extno] = 0;
+	DBG_DIFREE(imap, inum);
+	PXDlength(&iagp->inoext[extno], 0);
+	PXDaddress(&iagp->inoext[extno], 0);
+
+	/* update the free extent and free inode summary maps
+	 * to reflect the freed extent.
+	 * the inode summary map is marked to indicate no inodes 
+	 * available for the freed extent.
+	 */
+	sword = extno >> L2EXTSPERSUM;
+	bitno = extno & (EXTSPERSUM - 1);
+	mask = HIGHORDER >> bitno;
+	iagp->inosmap[sword] |= cpu_to_le32(mask);
+	iagp->extsmap[sword] &= cpu_to_le32(~mask);
+
+	/* update the number of free inodes and number of free extents
+	 * for the iag.
+	 */
+	iagp->nfreeinos = cpu_to_le32(le32_to_cpu(iagp->nfreeinos) -
+				      (INOSPEREXT - 1));
+	iagp->nfreeexts = cpu_to_le32(le32_to_cpu(iagp->nfreeexts) + 1);
+
+	/* update the number of free inodes and backed inodes
+	 * at the ag and inode map level.
+	 */
+	imap->im_agctl[agno].numfree -= (INOSPEREXT - 1);
+	imap->im_agctl[agno].numinos -= INOSPEREXT;
+	atomic_sub(INOSPEREXT - 1, &imap->im_numfree);
+	atomic_sub(INOSPEREXT, &imap->im_numinos);
+
+	if (amp)
+		write_metapage(amp);
+	if (bmp)
+		write_metapage(bmp);
+	if (cmp)
+		write_metapage(cmp);
+	if (dmp)
+		write_metapage(dmp);
+
+	/*
+	 * start transaction to update block allocation map
+	 * for the inode extent freed;
+	 *
+	 * N.B. AG_LOCK is released and iag will be released below, and 
+	 * other thread may allocate inode from/reusing the ixad freed
+	 * BUT with new/different backing inode extent from the extent 
+	 * to be freed by the transaction;  
+	 */
+	tid = txBegin(ipimap->i_sb, COMMIT_FORCE);
+
+	/* acquire tlock of the iag page of the freed ixad 
+	 * to force the page NOHOMEOK (even though no data is
+	 * logged from the iag page) until NOREDOPAGE|FREEXTENT log 
+	 * for the free of the extent is committed;
+	 * write FREEXTENT|NOREDOPAGE log record
+	 * N.B. linelock is overlaid as freed extent descriptor;
+	 */
+	tlck = txLock(tid, ipimap, mp, tlckINODE | tlckFREE);
+	pxdlock = (pxdlock_t *) & tlck->lock;
+	pxdlock->flag = mlckFREEPXD;
+	pxdlock->pxd = freepxd;
+	pxdlock->index = 1;
+
+	write_metapage(mp);
+
+	iplist[0] = ipimap;
+
+	/*
+	 * logredo needs the IAG number and IAG extent index in order
+	 * to ensure that the IMap is consistent.  The least disruptive
+	 * way to pass these values through  to the transaction manager
+	 * is in the iplist array.  
+	 * 
+	 * It's not pretty, but it works.
+	 */
+	iplist[1] = (struct inode *) (size_t)iagno;
+	iplist[2] = (struct inode *) (size_t)extno;
+
+	rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);	// D233382
+
+	txEnd(tid);
+
+	/* unlock the AG inode map information */
+	AG_UNLOCK(imap, agno);
+
+	return (0);
+
+      error_out:
+	IREAD_UNLOCK(ipimap);
+
+	if (amp)
+		release_metapage(amp);
+	if (bmp)
+		release_metapage(bmp);
+	if (cmp)
+		release_metapage(cmp);
+	if (dmp)
+		release_metapage(dmp);
+
+	AG_UNLOCK(imap, agno);
+
+	release_metapage(mp);
+
+	return (rc);
+}
+
+/*
+ * There are several places in the diAlloc* routines where we initialize
+ * the inode.
+ */
+static inline void
+diInitInode(struct inode *ip, int iagno, int ino, int extno, iag_t * iagp)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+
+	ip->i_ino = (iagno << L2INOSPERIAG) + ino;
+	DBG_DIALLOC(JFS_IP(ipimap)->i_imap, ip->i_ino);
+	jfs_ip->ixpxd = iagp->inoext[extno];
+	jfs_ip->agno = BLKTOAG(le64_to_cpu(iagp->agstart), sbi);
+}
+
+
+/*
+ * NAME:        diAlloc(pip,dir,ip)
+ *
+ * FUNCTION:    allocate a disk inode from the inode working map 
+ *		for a fileset or aggregate.
+ *
+ * PARAMETERS:
+ *      pip  	- pointer to incore inode for the parent inode.
+ *      dir  	- TRUE if the new disk inode is for a directory.
+ *      ip  	- pointer to a new inode
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ */
+int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip)
+{
+	int rc, ino, iagno, addext, extno, bitno, sword;
+	int nwords, rem, i, agno;
+	u32 mask, inosmap, extsmap;
+	struct inode *ipimap;
+	metapage_t *mp;
+	ino_t inum;
+	iag_t *iagp;
+	imap_t *imap;
+
+	/* get the pointers to the inode map inode and the
+	 * corresponding imap control structure.
+	 */
+	ipimap = JFS_SBI(pip->i_sb)->ipimap;
+	imap = JFS_IP(ipimap)->i_imap;
+	JFS_IP(ip)->ipimap = ipimap;
+	JFS_IP(ip)->fileset = FILESYSTEM_I;
+
+	/* for a directory, the allocation policy is to start 
+	 * at the ag level using the preferred ag.
+	 */
+	if (dir == TRUE) {
+		agno = dbNextAG(JFS_SBI(pip->i_sb)->ipbmap);
+		AG_LOCK(imap, agno);
+		goto tryag;
+	}
+
+	/* for files, the policy starts off by trying to allocate from
+	 * the same iag containing the parent disk inode:
+	 * try to allocate the new disk inode close to the parent disk
+	 * inode, using parent disk inode number + 1 as the allocation
+	 * hint.  (we use a left-to-right policy to attempt to avoid
+	 * moving backward on the disk.)  compute the hint within the
+	 * file system and the iag.
+	 */
+	inum = pip->i_ino + 1;
+	ino = inum & (INOSPERIAG - 1);
+
+	/* back off the the hint if it is outside of the iag */
+	if (ino == 0)
+		inum = pip->i_ino;
+
+	/* get the ag number of this iag */
+	agno = JFS_IP(pip)->agno;
+
+	/* lock the AG inode map information */
+	AG_LOCK(imap, agno);
+
+	/* Get read lock on imap inode */
+	IREAD_LOCK(ipimap);
+
+	/* get the iag number and read the iag */
+	iagno = INOTOIAG(inum);
+	if ((rc = diIAGRead(imap, iagno, &mp))) {
+		IREAD_UNLOCK(ipimap);
+		return (rc);
+	}
+	iagp = (iag_t *) mp->data;
+
+	/* determine if new inode extent is allowed to be added to the iag.
+	 * new inode extent can be added to the iag if the ag
+	 * has less than 32 free disk inodes and the iag has free extents.
+	 */
+	addext = (imap->im_agctl[agno].numfree < 32 && iagp->nfreeexts);
+
+	/*
+	 *      try to allocate from the IAG
+	 */
+	/* check if the inode may be allocated from the iag 
+	 * (i.e. the inode has free inodes or new extent can be added).
+	 */
+	if (iagp->nfreeinos || addext) {
+		/* determine the extent number of the hint.
+		 */
+		extno = ino >> L2INOSPEREXT;
+
+		/* check if the extent containing the hint has backed
+		 * inodes.  if so, try to allocate within this extent.
+		 */
+		if (addressPXD(&iagp->inoext[extno])) {
+			bitno = ino & (INOSPEREXT - 1);
+			if ((bitno =
+			     diFindFree(le32_to_cpu(iagp->wmap[extno]),
+					bitno))
+			    < INOSPEREXT) {
+				ino = (extno << L2INOSPEREXT) + bitno;
+
+				/* a free inode (bit) was found within this
+				 * extent, so allocate it.
+				 */
+				rc = diAllocBit(imap, iagp, ino);
+				IREAD_UNLOCK(ipimap);
+				if (rc) {
+					assert(rc == EIO);
+				} else {
+					/* set the results of the allocation
+					 * and write the iag.
+					 */
+					diInitInode(ip, iagno, ino, extno,
+						    iagp);
+					mark_metapage_dirty(mp);
+				}
+				release_metapage(mp);
+
+				/* free the AG lock and return.
+				 */
+				AG_UNLOCK(imap, agno);
+				return (rc);
+			}
+
+			if (!addext)
+				extno =
+				    (extno ==
+				     EXTSPERIAG - 1) ? 0 : extno + 1;
+		}
+
+		/*
+		 * no free inodes within the extent containing the hint.
+		 *
+		 * try to allocate from the backed extents following
+		 * hint or, if appropriate (i.e. addext is true), allocate
+		 * an extent of free inodes at or following the extent
+		 * containing the hint.
+		 * 
+		 * the free inode and free extent summary maps are used
+		 * here, so determine the starting summary map position
+		 * and the number of words we'll have to examine.  again,
+		 * the approach is to allocate following the hint, so we
+		 * might have to initially ignore prior bits of the summary
+		 * map that represent extents prior to the extent containing
+		 * the hint and later revisit these bits.
+		 */
+		bitno = extno & (EXTSPERSUM - 1);
+		nwords = (bitno == 0) ? SMAPSZ : SMAPSZ + 1;
+		sword = extno >> L2EXTSPERSUM;
+
+		/* mask any prior bits for the starting words of the
+		 * summary map.
+		 */
+		mask = ONES << (EXTSPERSUM - bitno);
+		inosmap = le32_to_cpu(iagp->inosmap[sword]) | mask;
+		extsmap = le32_to_cpu(iagp->extsmap[sword]) | mask;
+
+		/* scan the free inode and free extent summary maps for
+		 * free resources.
+		 */
+		for (i = 0; i < nwords; i++) {
+			/* check if this word of the free inode summary
+			 * map describes an extent with free inodes.
+			 */
+			if (~inosmap) {
+				/* an extent with free inodes has been
+				 * found. determine the extent number
+				 * and the inode number within the extent.
+				 */
+				rem = diFindFree(inosmap, 0);
+				extno = (sword << L2EXTSPERSUM) + rem;
+				rem =
+				    diFindFree(le32_to_cpu
+					       (iagp->wmap[extno]), 0);
+				assert(rem < INOSPEREXT);
+
+				/* determine the inode number within the
+				 * iag and allocate the inode from the
+				 * map.
+				 */
+				ino = (extno << L2INOSPEREXT) + rem;
+				rc = diAllocBit(imap, iagp, ino);
+				IREAD_UNLOCK(ipimap);
+				if (rc) {
+					assert(rc == EIO);
+				} else {
+					/* set the results of the allocation
+					 * and write the iag.
+					 */
+					diInitInode(ip, iagno, ino, extno,
+						    iagp);
+					mark_metapage_dirty(mp);
+				}
+				release_metapage(mp);
+
+				/* free the AG lock and return.
+				 */
+				AG_UNLOCK(imap, agno);
+				return (rc);
+
+			}
+
+			/* check if we may allocate an extent of free
+			 * inodes and whether this word of the free
+			 * extents summary map describes a free extent.
+			 */
+			if (addext && ~extsmap) {
+				/* a free extent has been found.  determine
+				 * the extent number.
+				 */
+				rem = diFindFree(extsmap, 0);
+				extno = (sword << L2EXTSPERSUM) + rem;
+
+				/* allocate an extent of free inodes.
+				 */
+				if ((rc = diNewExt(imap, iagp, extno))) {
+					/* if there is no disk space for a
+					 * new extent, try to allocate the
+					 * disk inode from somewhere else.
+					 */
+					if (rc == ENOSPC)
+						break;
+
+					assert(rc == EIO);
+				} else {
+					/* set the results of the allocation
+					 * and write the iag.
+					 */
+					diInitInode(ip, iagno,
+						    extno << L2INOSPEREXT,
+						    extno, iagp);
+					mark_metapage_dirty(mp);
+				}
+				release_metapage(mp);
+				/* free the imap inode & the AG lock & return.
+				 */
+				IREAD_UNLOCK(ipimap);
+				AG_UNLOCK(imap, agno);
+				return (rc);
+			}
+
+			/* move on to the next set of summary map words.
+			 */
+			sword = (sword == SMAPSZ - 1) ? 0 : sword + 1;
+			inosmap = le32_to_cpu(iagp->inosmap[sword]);
+			extsmap = le32_to_cpu(iagp->extsmap[sword]);
+		}
+	}
+	/* unlock imap inode */
+	IREAD_UNLOCK(ipimap);
+
+	/* nothing doing in this iag, so release it. */
+	release_metapage(mp);
+
+      tryag:
+	/*
+	 * try to allocate anywhere within the same AG as the parent inode.
+	 */
+	rc = diAllocAG(imap, agno, dir, ip);
+
+	AG_UNLOCK(imap, agno);
+
+	if (rc != ENOSPC)
+		return (rc);
+
+	/*
+	 * try to allocate in any AG.
+	 */
+	return (diAllocAny(imap, agno, dir, ip));
+}
+
+
+/*
+ * NAME:        diAllocAG(imap,agno,dir,ip)
+ *
+ * FUNCTION:    allocate a disk inode from the allocation group.
+ *
+ *		this routine first determines if a new extent of free
+ *		inodes should be added for the allocation group, with
+ *		the current request satisfied from this extent. if this
+ *		is the case, an attempt will be made to do just that.  if
+ *		this attempt fails or it has been determined that a new 
+ *		extent should not be added, an attempt is made to satisfy
+ *		the request by allocating an existing (backed) free inode
+ *		from the allocation group.
+ *
+ * PRE CONDITION: Already have the AG lock for this AG.
+ *
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      agno  	- allocation group to allocate from.
+ *      dir  	- TRUE if the new disk inode is for a directory.
+ *      ip  	- pointer to the new inode to be filled in on successful return
+ *		  with the disk inode number allocated, its extent address
+ *		  and the start of the ag.
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ */
+static int
+diAllocAG(imap_t * imap, int agno, boolean_t dir, struct inode *ip)
+{
+	int rc, addext, numfree, numinos;
+
+	/* get the number of free and the number of backed disk 
+	 * inodes currently within the ag.
+	 */
+	numfree = imap->im_agctl[agno].numfree;
+	numinos = imap->im_agctl[agno].numinos;
+
+	if (numfree > numinos) {
+		jERROR(1,("diAllocAG: numfree > numinos\n"));
+		updateSuper(ip->i_sb, FM_DIRTY);
+		return EIO;
+	}
+
+	/* determine if we should allocate a new extent of free inodes
+	 * within the ag: for directory inodes, add a new extent
+	 * if there are a small number of free inodes or number of free
+	 * inodes is a small percentage of the number of backed inodes.
+	 */
+	if (dir == TRUE)
+		addext = (numfree < 64 ||
+			  (numfree < 256
+			   && ((numfree * 100) / numinos) <= 20));
+	else
+		addext = (numfree == 0);
+
+	/*
+	 * try to allocate a new extent of free inodes.
+	 */
+	if (addext) {
+		/* if free space is not avaliable for this new extent, try
+		 * below to allocate a free and existing (already backed)
+		 * inode from the ag.
+		 */
+		if ((rc = diAllocExt(imap, agno, ip)) != ENOSPC)
+			return (rc);
+	}
+
+	/*
+	 * try to allocate an existing free inode from the ag.
+	 */
+	return (diAllocIno(imap, agno, ip));
+}
+
+
+/*
+ * NAME:        diAllocAny(imap,agno,dir,iap)
+ *
+ * FUNCTION:    allocate a disk inode from any other allocation group.
+ *
+ *		this routine is called when an allocation attempt within
+ *		the primary allocation group has failed. if attempts to
+ *		allocate an inode from any allocation group other than the
+ *		specified primary group.
+ *
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      agno  	- primary allocation group (to avoid).
+ *      dir  	- TRUE if the new disk inode is for a directory.
+ *      ip  	- pointer to a new inode to be filled in on successful return
+ *		  with the disk inode number allocated, its extent address
+ *		  and the start of the ag.
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ */
+static int
+diAllocAny(imap_t * imap, int agno, boolean_t dir, struct inode *ip)
+{
+	int ag, rc;
+	int maxag = JFS_SBI(imap->im_ipimap->i_sb)->bmap->db_maxag;
+
+
+	/* try to allocate from the ags following agno up to 
+	 * the maximum ag number.
+	 */
+	for (ag = agno + 1; ag <= maxag; ag++) {
+		AG_LOCK(imap, ag);
+
+		rc = diAllocAG(imap, ag, dir, ip);
+
+		AG_UNLOCK(imap, ag);
+
+		if (rc != ENOSPC)
+			return (rc);
+	}
+
+	/* try to allocate from the ags in front of agno.
+	 */
+	for (ag = 0; ag < agno; ag++) {
+		AG_LOCK(imap, ag);
+
+		rc = diAllocAG(imap, ag, dir, ip);
+
+		AG_UNLOCK(imap, ag);
+
+		if (rc != ENOSPC)
+			return (rc);
+	}
+
+	/* no free disk inodes.
+	 */
+	return (ENOSPC);
+}
+
+
+/*
+ * NAME:        diAllocIno(imap,agno,ip)
+ *
+ * FUNCTION:    allocate a disk inode from the allocation group's free
+ *		inode list, returning an error if this free list is
+ *		empty (i.e. no iags on the list).
+ *
+ *		allocation occurs from the first iag on the list using
+ *		the iag's free inode summary map to find the leftmost
+ *		free inode in the iag. 
+ *		
+ * PRE CONDITION: Already have AG lock for this AG.
+ *		
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      agno  	- allocation group.
+ *      ip  	- pointer to new inode to be filled in on successful return
+ *		  with the disk inode number allocated, its extent address
+ *		  and the start of the ag.
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ */
+static int diAllocIno(imap_t * imap, int agno, struct inode *ip)
+{
+	int iagno, ino, rc, rem, extno, sword;
+	metapage_t *mp;
+	iag_t *iagp;
+
+	/* check if there are iags on the ag's free inode list.
+	 */
+	if ((iagno = imap->im_agctl[agno].inofree) < 0)
+		return (ENOSPC);
+
+	/* obtain read lock on imap inode */
+	IREAD_LOCK(imap->im_ipimap);
+
+	/* read the iag at the head of the list.
+	 */
+	if ((rc = diIAGRead(imap, iagno, &mp))) {
+		IREAD_UNLOCK(imap->im_ipimap);
+		return (rc);
+	}
+	iagp = (iag_t *) mp->data;
+
+	/* better be free inodes in this iag if it is on the
+	 * list.
+	 */
+	//assert(iagp->nfreeinos);
+	if (!iagp->nfreeinos) {
+		jERROR(1,
+		       ("diAllocIno: nfreeinos = 0, but iag on freelist\n"));
+		jERROR(1, ("  agno = %d, iagno = %d\n", agno, iagno));
+		dump_mem("iag", iagp, 64);
+		updateSuper(ip->i_sb, FM_DIRTY);
+		return EIO;
+	}
+
+	/* scan the free inode summary map to find an extent
+	 * with free inodes.
+	 */
+	for (sword = 0;; sword++) {
+		assert(sword < SMAPSZ);
+
+		if (~iagp->inosmap[sword])
+			break;
+	}
+
+	/* found a extent with free inodes. determine
+	 * the extent number.
+	 */
+	rem = diFindFree(le32_to_cpu(iagp->inosmap[sword]), 0);
+	assert(rem < EXTSPERSUM);
+	extno = (sword << L2EXTSPERSUM) + rem;
+
+	/* find the first free inode in the extent.
+	 */
+	rem = diFindFree(le32_to_cpu(iagp->wmap[extno]), 0);
+	assert(rem < INOSPEREXT);
+
+	/* compute the inode number within the iag. 
+	 */
+	ino = (extno << L2INOSPEREXT) + rem;
+
+	/* allocate the inode.
+	 */
+	rc = diAllocBit(imap, iagp, ino);
+	IREAD_UNLOCK(imap->im_ipimap);
+	if (rc) {
+		release_metapage(mp);
+		return (rc);
+	}
+
+	/* set the results of the allocation and write the iag.
+	 */
+	diInitInode(ip, iagno, ino, extno, iagp);
+	write_metapage(mp);
+
+	return (0);
+}
+
+
+/*
+ * NAME:        diAllocExt(imap,agno,ip)
+ *
+ * FUNCTION:   	add a new extent of free inodes to an iag, allocating
+ *	       	an inode from this extent to satisfy the current allocation
+ *	       	request.
+ *		
+ *		this routine first tries to find an existing iag with free
+ *		extents through the ag free extent list.  if list is not
+ *		empty, the head of the list will be selected as the home
+ *		of the new extent of free inodes.  otherwise (the list is
+ *		empty), a new iag will be allocated for the ag to contain
+ *		the extent.
+ *		
+ *		once an iag has been selected, the free extent summary map
+ *		is used to locate a free extent within the iag and diNewExt()
+ *		is called to initialize the extent, with initialization
+ *		including the allocation of the first inode of the extent
+ *		for the purpose of satisfying this request.
+ *
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      agno  	- allocation group number.
+ *      ip  	- pointer to new inode to be filled in on successful return
+ *		  with the disk inode number allocated, its extent address
+ *		  and the start of the ag.
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ */
+static int diAllocExt(imap_t * imap, int agno, struct inode *ip)
+{
+	int rem, iagno, sword, extno, rc;
+	metapage_t *mp;
+	iag_t *iagp;
+
+	/* check if the ag has any iags with free extents.  if not,
+	 * allocate a new iag for the ag.
+	 */
+	if ((iagno = imap->im_agctl[agno].extfree) < 0) {
+		/* If successful, diNewIAG will obtain the read lock on the
+		 * imap inode.
+		 */
+		if ((rc = diNewIAG(imap, &iagno, agno, &mp))) {
+			return (rc);
+		}
+		iagp = (iag_t *) mp->data;
+
+		/* set the ag number if this a brand new iag
+		 */
+		iagp->agstart =
+		    cpu_to_le64(AGTOBLK(agno, imap->im_ipimap));
+	} else {
+		/* read the iag.
+		 */
+		IREAD_LOCK(imap->im_ipimap);
+		if ((rc = diIAGRead(imap, iagno, &mp))) {
+			assert(0);
+		}
+		iagp = (iag_t *) mp->data;
+	}
+
+	/* using the free extent summary map, find a free extent.
+	 */
+	for (sword = 0;; sword++) {
+		assert(sword < SMAPSZ);
+		if (~iagp->extsmap[sword])
+			break;
+	}
+
+	/* determine the extent number of the free extent.
+	 */
+	rem = diFindFree(le32_to_cpu(iagp->extsmap[sword]), 0);
+	assert(rem < EXTSPERSUM);
+	extno = (sword << L2EXTSPERSUM) + rem;
+
+	/* initialize the new extent.
+	 */
+	rc = diNewExt(imap, iagp, extno);
+	IREAD_UNLOCK(imap->im_ipimap);
+	if (rc) {
+		/* something bad happened.  if a new iag was allocated,
+		 * place it back on the inode map's iag free list, and
+		 * clear the ag number information.
+		 */
+		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
+			IAGFREE_LOCK(imap);
+			iagp->iagfree = cpu_to_le32(imap->im_freeiag);
+			imap->im_freeiag = iagno;
+			IAGFREE_UNLOCK(imap);
+		}
+		write_metapage(mp);
+		return (rc);
+	}
+
+	/* set the results of the allocation and write the iag.
+	 */
+	diInitInode(ip, iagno, extno << L2INOSPEREXT, extno, iagp);
+
+	write_metapage(mp);
+
+	return (0);
+}
+
+
+/*
+ * NAME:        diAllocBit(imap,iagp,ino)
+ *
+ * FUNCTION:   	allocate a backed inode from an iag.
+ *
+ *		this routine performs the mechanics of allocating a
+ *		specified inode from a backed extent.
+ *
+ *		if the inode to be allocated represents the last free
+ *		inode within the iag, the iag will be removed from the
+ *		ag free inode list.
+ *
+ *		a careful update approach is used to provide consistency
+ *		in the face of updates to multiple buffers.  under this
+ *		approach, all required buffers are obtained before making
+ *		any updates and are held all are updates are complete.
+ *		
+ * PRE CONDITION: Already have buffer lock on iagp.  Already have AG lock on
+ *	this AG.  Must have read lock on imap inode.
+ *
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      iagp  	- pointer to iag. 
+ *      ino   	- inode number to be allocated within the iag.
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ */
+static int diAllocBit(imap_t * imap, iag_t * iagp, int ino)
+{
+	int extno, bitno, agno, sword, rc;
+	metapage_t *amp, *bmp;
+	iag_t *aiagp = 0, *biagp = 0;
+	u32 mask;
+
+	/* check if this is the last free inode within the iag.
+	 * if so, it will have to be removed from the ag free
+	 * inode list, so get the iags preceeding and following
+	 * it on the list.
+	 */
+	if (iagp->nfreeinos == cpu_to_le32(1)) {
+		amp = bmp = NULL;
+
+		if ((int) le32_to_cpu(iagp->inofreefwd) >= 0) {
+			if ((rc =
+			     diIAGRead(imap, le32_to_cpu(iagp->inofreefwd),
+				       &amp)))
+				return (rc);
+			aiagp = (iag_t *) amp->data;
+		}
+
+		if ((int) le32_to_cpu(iagp->inofreeback) >= 0) {
+			if ((rc =
+			     diIAGRead(imap,
+				       le32_to_cpu(iagp->inofreeback),
+				       &bmp))) {
+				if (amp)
+					release_metapage(amp);
+				return (rc);
+			}
+			biagp = (iag_t *) bmp->data;
+		}
+	}
+
+	/* get the ag number, extent number, inode number within
+	 * the extent.
+	 */
+	agno = BLKTOAG(le64_to_cpu(iagp->agstart), JFS_SBI(imap->im_ipimap->i_sb));
+	extno = ino >> L2INOSPEREXT;
+	bitno = ino & (INOSPEREXT - 1);
+
+	/* compute the mask for setting the map.
+	 */
+	mask = HIGHORDER >> bitno;
+
+	/* the inode should be free and backed.
+	 */
+	assert((le32_to_cpu(iagp->pmap[extno]) & mask) == 0);
+	assert((le32_to_cpu(iagp->wmap[extno]) & mask) == 0);
+	assert(addressPXD(&iagp->inoext[extno]) != 0);
+
+	/* mark the inode as allocated in the working map.
+	 */
+	iagp->wmap[extno] |= cpu_to_le32(mask);
+
+	/* check if all inodes within the extent are now
+	 * allocated.  if so, update the free inode summary
+	 * map to reflect this.
+	 */
+	if (iagp->wmap[extno] == ONES) {
+		sword = extno >> L2EXTSPERSUM;
+		bitno = extno & (EXTSPERSUM - 1);
+		iagp->inosmap[sword] |= cpu_to_le32(HIGHORDER >> bitno);
+	}
+
+	/* if this was the last free inode in the iag, remove the
+	 * iag from the ag free inode list.
+	 */
+	if (iagp->nfreeinos == cpu_to_le32(1)) {
+		if (amp) {
+			aiagp->inofreeback = iagp->inofreeback;
+			write_metapage(amp);
+		}
+
+		if (bmp) {
+			biagp->inofreefwd = iagp->inofreefwd;
+			write_metapage(bmp);
+		} else {
+			imap->im_agctl[agno].inofree =
+			    le32_to_cpu(iagp->inofreefwd);
+		}
+		iagp->inofreefwd = iagp->inofreeback = -1;
+	}
+
+	/* update the free inode count at the iag, ag, inode
+	 * map levels.
+	 */
+	iagp->nfreeinos = cpu_to_le32(le32_to_cpu(iagp->nfreeinos) - 1);
+	imap->im_agctl[agno].numfree -= 1;
+	atomic_dec(&imap->im_numfree);
+
+	return (0);
+}
+
+
+/*
+ * NAME:        diNewExt(imap,iagp,extno)
+ *
+ * FUNCTION:    initialize a new extent of inodes for an iag, allocating
+ *	        the first inode of the extent for use for the current
+ *	        allocation request.
+ *
+ *		disk resources are allocated for the new extent of inodes
+ *		and the inodes themselves are initialized to reflect their
+ *		existence within the extent (i.e. their inode numbers and
+ *		inode extent addresses are set) and their initial state
+ *		(mode and link count are set to zero).
+ *
+ *		if the iag is new, it is not yet on an ag extent free list
+ *		but will now be placed on this list.
+ *
+ *		if the allocation of the new extent causes the iag to
+ *		have no free extent, the iag will be removed from the
+ *		ag extent free list.
+ *
+ *		if the iag has no free backed inodes, it will be placed
+ *		on the ag free inode list, since the addition of the new
+ *		extent will now cause it to have free inodes.
+ *
+ *		a careful update approach is used to provide consistency
+ *		(i.e. list consistency) in the face of updates to multiple
+ *		buffers.  under this approach, all required buffers are
+ *		obtained before making any updates and are held until all
+ *		updates are complete.
+ *		
+ * PRE CONDITION: Already have buffer lock on iagp.  Already have AG lock on
+ *	this AG.  Must have read lock on imap inode.
+ *
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      iagp  	- pointer to iag. 
+ *      extno  	- extent number.
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ */
+static int diNewExt(imap_t * imap, iag_t * iagp, int extno)
+{
+	int agno, iagno, fwd, back, freei = 0, sword, rc;
+	iag_t *aiagp = 0, *biagp = 0, *ciagp = 0;
+	metapage_t *amp, *bmp, *cmp, *dmp;
+	struct inode *ipimap;
+	s64 blkno, hint;
+	int i, j;
+	u32 mask;
+	ino_t ino;
+	dinode_t *dp;
+	struct jfs_sb_info *sbi;
+
+	/* better have free extents.
+	 */
+	assert(iagp->nfreeexts);
+
+	/* get the inode map inode.
+	 */
+	ipimap = imap->im_ipimap;
+	sbi = JFS_SBI(ipimap->i_sb);
+
+	amp = bmp = cmp = NULL;
+
+	/* get the ag and iag numbers for this iag.
+	 */
+	agno = BLKTOAG(le64_to_cpu(iagp->agstart), sbi);
+	iagno = le32_to_cpu(iagp->iagnum);
+
+	/* check if this is the last free extent within the
+	 * iag.  if so, the iag must be removed from the ag
+	 * free extent list, so get the iags preceeding and
+	 * following the iag on this list.
+	 */
+	if (iagp->nfreeexts == cpu_to_le32(1)) {
+		if ((fwd = le32_to_cpu(iagp->extfreefwd)) >= 0) {
+			if ((rc = diIAGRead(imap, fwd, &amp)))
+				return (rc);
+			aiagp = (iag_t *) amp->data;
+		}
+
+		if ((back = le32_to_cpu(iagp->extfreeback)) >= 0) {
+			if ((rc = diIAGRead(imap, back, &bmp)))
+				goto error_out;
+			biagp = (iag_t *) bmp->data;
+		}
+	} else {
+		/* the iag has free extents.  if all extents are free
+		 * (as is the case for a newly allocated iag), the iag
+		 * must be added to the ag free extent list, so get
+		 * the iag at the head of the list in preparation for
+		 * adding this iag to this list.
+		 */
+		fwd = back = -1;
+		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
+			if ((fwd = imap->im_agctl[agno].extfree) >= 0) {
+				if ((rc = diIAGRead(imap, fwd, &amp)))
+					goto error_out;
+				aiagp = (iag_t *) amp->data;
+			}
+		}
+	}
+
+	/* check if the iag has no free inodes.  if so, the iag
+	 * will have to be added to the ag free inode list, so get
+	 * the iag at the head of the list in preparation for
+	 * adding this iag to this list.  in doing this, we must
+	 * check if we already have the iag at the head of
+	 * the list in hand.
+	 */
+	if (iagp->nfreeinos == 0) {
+		freei = imap->im_agctl[agno].inofree;
+
+		if (freei >= 0) {
+			if (freei == fwd) {
+				ciagp = aiagp;
+			} else if (freei == back) {
+				ciagp = biagp;
+			} else {
+				if ((rc = diIAGRead(imap, freei, &cmp)))
+					goto error_out;
+				ciagp = (iag_t *) cmp->data;
+			}
+			assert(ciagp != NULL);
+		}
+	}
+
+	/* allocate disk space for the inode extent.
+	 */
+	if ((extno == 0) || (addressPXD(&iagp->inoext[extno - 1]) == 0))
+		hint = ((s64) agno << sbi->bmap->db_agl2size) - 1;
+	else
+		hint = addressPXD(&iagp->inoext[extno - 1]) +
+		    lengthPXD(&iagp->inoext[extno - 1]) - 1;
+
+	if ((rc = dbAlloc(ipimap, hint, (s64) imap->im_nbperiext, &blkno)))
+		goto error_out;
+
+	/* compute the inode number of the first inode within the
+	 * extent.
+	 */
+	ino = (iagno << L2INOSPERIAG) + (extno << L2INOSPEREXT);
+
+	/* initialize the inodes within the newly allocated extent a
+	 * page at a time.
+	 */
+	for (i = 0; i < imap->im_nbperiext; i += sbi->nbperpage) {
+		/* get a buffer for this page of disk inodes.
+		 */
+		dmp = get_metapage(ipimap, blkno + i, PSIZE, 1);
+		if (dmp == NULL) {
+			rc = EIO;
+			goto error_out;
+		}
+		dp = (dinode_t *) dmp->data;
+
+		/* initialize the inode number, mode, link count and
+		 * inode extent address.
+		 */
+		for (j = 0; j < INOSPERPAGE; j++, dp++, ino++) {
+			dp->di_inostamp = cpu_to_le32(sbi->inostamp);
+			dp->di_number = cpu_to_le32(ino);
+			dp->di_fileset = cpu_to_le32(FILESYSTEM_I);
+			dp->di_mode = 0;
+			dp->di_nlink = 0;
+			PXDaddress(&(dp->di_ixpxd), blkno);
+			PXDlength(&(dp->di_ixpxd), imap->im_nbperiext);
+		}
+		write_metapage(dmp);
+	}
+
+	/* if this is the last free extent within the iag, remove the
+	 * iag from the ag free extent list.
+	 */
+	if (iagp->nfreeexts == cpu_to_le32(1)) {
+		if (fwd >= 0)
+			aiagp->extfreeback = iagp->extfreeback;
+
+		if (back >= 0)
+			biagp->extfreefwd = iagp->extfreefwd;
+		else
+			imap->im_agctl[agno].extfree =
+			    le32_to_cpu(iagp->extfreefwd);
+
+		iagp->extfreefwd = iagp->extfreeback = -1;
+	} else {
+		/* if the iag has all free extents (newly allocated iag),
+		 * add the iag to the ag free extent list.
+		 */
+		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
+			if (fwd >= 0)
+				aiagp->extfreeback = cpu_to_le32(iagno);
+
+			iagp->extfreefwd = cpu_to_le32(fwd);
+			iagp->extfreeback = -1;
+			imap->im_agctl[agno].extfree = iagno;
+		}
+	}
+
+	/* if the iag has no free inodes, add the iag to the
+	 * ag free inode list.
+	 */
+	if (iagp->nfreeinos == 0) {
+		if (freei >= 0)
+			ciagp->inofreeback = cpu_to_le32(iagno);
+
+		iagp->inofreefwd =
+		    cpu_to_le32(imap->im_agctl[agno].inofree);
+		iagp->inofreeback = -1;
+		imap->im_agctl[agno].inofree = iagno;
+	}
+
+	/* initialize the extent descriptor of the extent. */
+	PXDlength(&iagp->inoext[extno], imap->im_nbperiext);
+	PXDaddress(&iagp->inoext[extno], blkno);
+
+	/* initialize the working and persistent map of the extent.
+	 * the working map will be initialized such that
+	 * it indicates the first inode of the extent is allocated.
+	 */
+	iagp->wmap[extno] = cpu_to_le32(HIGHORDER);
+	iagp->pmap[extno] = 0;
+
+	/* update the free inode and free extent summary maps
+	 * for the extent to indicate the extent has free inodes
+	 * and no longer represents a free extent.
+	 */
+	sword = extno >> L2EXTSPERSUM;
+	mask = HIGHORDER >> (extno & (EXTSPERSUM - 1));
+	iagp->extsmap[sword] |= cpu_to_le32(mask);
+	iagp->inosmap[sword] &= cpu_to_le32(~mask);
+
+	/* update the free inode and free extent counts for the
+	 * iag.
+	 */
+	iagp->nfreeinos = cpu_to_le32(le32_to_cpu(iagp->nfreeinos) +
+				      (INOSPEREXT - 1));
+	iagp->nfreeexts = cpu_to_le32(le32_to_cpu(iagp->nfreeexts) - 1);
+
+	/* update the free and backed inode counts for the ag.
+	 */
+	imap->im_agctl[agno].numfree += (INOSPEREXT - 1);
+	imap->im_agctl[agno].numinos += INOSPEREXT;
+
+	/* update the free and backed inode counts for the inode map.
+	 */
+	atomic_add(INOSPEREXT - 1, &imap->im_numfree);
+	atomic_add(INOSPEREXT, &imap->im_numinos);
+
+	/* write the iags.
+	 */
+	if (amp)
+		write_metapage(amp);
+	if (bmp)
+		write_metapage(bmp);
+	if (cmp)
+		write_metapage(cmp);
+
+	return (0);
+
+      error_out:
+
+	/* release the iags.
+	 */
+	if (amp)
+		release_metapage(amp);
+	if (bmp)
+		release_metapage(bmp);
+	if (cmp)
+		release_metapage(cmp);
+
+	return (rc);
+}
+
+
+/*
+ * NAME:        diNewIAG(imap,iagnop,agno)
+ *
+ * FUNCTION:   	allocate a new iag for an allocation group.
+ *		
+ *		first tries to allocate the iag from the inode map 
+ *		iagfree list:  
+ *		if the list has free iags, the head of the list is removed 
+ *		and returned to satisfy the request.
+ *		if the inode map's iag free list is empty, the inode map
+ *		is extended to hold a new iag. this new iag is initialized
+ *		and returned to satisfy the request.
+ *
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      iagnop 	- pointer to an iag number set with the number of the
+ *		  newly allocated iag upon successful return.
+ *      agno  	- allocation group number.
+ *	bpp	- Buffer pointer to be filled in with new IAG's buffer
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      ENOSPC 	- insufficient disk resources.
+ *      EIO  	- i/o error.
+ *
+ * serialization: 
+ *	AG lock held on entry/exit;
+ *	write lock on the map is held inside;
+ *	read lock on the map is held on successful completion;
+ *
+ * note: new iag transaction: 
+ * . synchronously write iag;
+ * . write log of xtree and inode  of imap;
+ * . commit;
+ * . synchronous write of xtree (right to left, bottom to top);
+ * . at start of logredo(): init in-memory imap with one additional iag page;
+ * . at end of logredo(): re-read imap inode to determine
+ *   new imap size;
+ */
+static int
+diNewIAG(imap_t * imap, int *iagnop, int agno, metapage_t ** mpp)
+{
+	int rc;
+	int iagno, i, xlen;
+	struct inode *ipimap;
+	struct super_block *sb;
+	struct jfs_sb_info *sbi;
+	metapage_t *mp;
+	iag_t *iagp;
+	s64 xaddr = 0;
+	s64 blkno;
+	tid_t tid;
+#ifdef _STILL_TO_PORT
+	xad_t xad;
+#endif				/*  _STILL_TO_PORT */
+	struct inode *iplist[1];
+
+	/* pick up pointers to the inode map and mount inodes */
+	ipimap = imap->im_ipimap;
+	sb = ipimap->i_sb;
+	sbi = JFS_SBI(sb);
+
+	/* acquire the free iag lock */
+	IAGFREE_LOCK(imap);
+
+	/* if there are any iags on the inode map free iag list, 
+	 * allocate the iag from the head of the list.
+	 */
+	if (imap->im_freeiag >= 0) {
+		/* pick up the iag number at the head of the list */
+		iagno = imap->im_freeiag;
+
+		/* determine the logical block number of the iag */
+		blkno = IAGTOLBLK(iagno, sbi->l2nbperpage);
+	} else {
+		/* no free iags. the inode map will have to be extented
+		 * to include a new iag.
+		 */
+
+		/* acquire inode map lock */
+		IWRITE_LOCK(ipimap);
+
+		assert(ipimap->i_size >> L2PSIZE == imap->im_nextiag + 1);
+
+		/* get the next avaliable iag number */
+		iagno = imap->im_nextiag;
+
+		/* make sure that we have not exceeded the maximum inode
+		 * number limit.
+		 */
+		if (iagno > (MAXIAGS - 1)) {
+			/* release the inode map lock */
+			IWRITE_UNLOCK(ipimap);
+
+			rc = ENOSPC;
+			goto out;
+		}
+
+		/*
+		 * synchronously append new iag page.
+		 */
+		/* determine the logical address of iag page to append */
+		blkno = IAGTOLBLK(iagno, sbi->l2nbperpage);
+
+		/* Allocate extent for new iag page */
+		xlen = sbi->nbperpage;
+		if ((rc = dbAlloc(ipimap, 0, (s64) xlen, &xaddr))) {
+			/* release the inode map lock */
+			IWRITE_UNLOCK(ipimap);
+
+			goto out;
+		}
+
+		/* assign a buffer for the page */
+		mp = get_metapage(ipimap, xaddr, PSIZE, 1);
+		//bp = bmAssign(ipimap, blkno, xaddr, PSIZE, bmREAD_PAGE);
+		if (!mp) {
+			/* Free the blocks allocated for the iag since it was
+			 * not successfully added to the inode map
+			 */
+			dbFree(ipimap, xaddr, (s64) xlen);
+
+			/* release the inode map lock */
+			IWRITE_UNLOCK(ipimap);
+
+			rc = EIO;
+			goto out;
+		}
+		iagp = (iag_t *) mp->data;
+
+		/* init the iag */
+		memset(iagp, 0, sizeof(iag_t));
+		iagp->iagnum = cpu_to_le32(iagno);
+		iagp->inofreefwd = iagp->inofreeback = -1;
+		iagp->extfreefwd = iagp->extfreeback = -1;
+		iagp->iagfree = -1;
+		iagp->nfreeinos = 0;
+		iagp->nfreeexts = cpu_to_le32(EXTSPERIAG);
+
+		/* initialize the free inode summary map (free extent
+		 * summary map initialization handled by bzero).
+		 */
+		for (i = 0; i < SMAPSZ; i++)
+			iagp->inosmap[i] = ONES;
+
+		flush_metapage(mp);
+#ifdef _STILL_TO_PORT
+		/* synchronously write the iag page */
+		if (bmWrite(bp)) {
+			/* Free the blocks allocated for the iag since it was
+			 * not successfully added to the inode map
+			 */
+			dbFree(ipimap, xaddr, (s64) xlen);
+
+			/* release the inode map lock */
+			IWRITE_UNLOCK(ipimap);
+
+			rc = EIO;
+			goto out;
+		}
+
+		/* Now the iag is on disk */
+
+		/*
+		 * start tyransaction of update of the inode map
+		 * addressing structure pointing to the new iag page;
+		 */
+#endif				/*  _STILL_TO_PORT */
+		tid = txBegin(sb, COMMIT_FORCE);
+
+		/* update the inode map addressing structure to point to it */
+		if ((rc =
+		     xtInsert(tid, ipimap, 0, blkno, xlen, &xaddr, 0))) {
+			/* Free the blocks allocated for the iag since it was
+			 * not successfully added to the inode map
+			 */
+			dbFree(ipimap, xaddr, (s64) xlen);
+
+			/* release the inode map lock */
+			IWRITE_UNLOCK(ipimap);
+
+			goto out;
+		}
+
+		/* update the inode map's inode to reflect the extension */
+		ipimap->i_size += PSIZE;
+		ipimap->i_blocks += LBLK2PBLK(sb, xlen);
+
+		/*
+		 * txCommit(COMMIT_FORCE) will synchronously write address 
+		 * index pages and inode after commit in careful update order 
+		 * of address index pages (right to left, bottom up);
+		 */
+		iplist[0] = ipimap;
+		rc = txCommit(tid, 1, &iplist[0], COMMIT_FORCE);
+
+		txEnd(tid);
+
+		duplicateIXtree(sb, blkno, xlen, &xaddr);
+
+		/* update the next avaliable iag number */
+		imap->im_nextiag += 1;
+
+		/* Add the iag to the iag free list so we don't lose the iag
+		 * if a failure happens now.
+		 */
+		imap->im_freeiag = iagno;
+
+		/* Until we have logredo working, we want the imap inode &
+		 * control page to be up to date.
+		 */
+		diSync(ipimap);
+
+		/* release the inode map lock */
+		IWRITE_UNLOCK(ipimap);
+	}
+
+	/* obtain read lock on map */
+	IREAD_LOCK(ipimap);
+
+	/* read the iag */
+	if ((rc = diIAGRead(imap, iagno, &mp))) {
+		IREAD_UNLOCK(ipimap);
+		rc = EIO;
+		goto out;
+	}
+	iagp = (iag_t *) mp->data;
+
+	/* remove the iag from the iag free list */
+	imap->im_freeiag = le32_to_cpu(iagp->iagfree);
+	iagp->iagfree = -1;
+
+	/* set the return iag number and buffer pointer */
+	*iagnop = iagno;
+	*mpp = mp;
+
+      out:
+	/* release the iag free lock */
+	IAGFREE_UNLOCK(imap);
+
+	return (rc);
+}
+
+/*
+ * NAME:        diIAGRead()
+ *
+ * FUNCTION:    get the buffer for the specified iag within a fileset
+ *		or aggregate inode map.
+ *		
+ * PARAMETERS:
+ *      imap  	- pointer to inode map control structure.
+ *      iagno  	- iag number.
+ *      bpp  	- point to buffer pointer to be filled in on successful
+ *		  exit.
+ *
+ * SERIALIZATION:
+ *	must have read lock on imap inode
+ *	(When called by diExtendFS, the filesystem is quiesced, therefore
+ *	 the read lock is unnecessary.)
+ *
+ * RETURN VALUES:
+ *      0       - success.
+ *      EIO  	- i/o error.
+ */
+static int diIAGRead(imap_t * imap, int iagno, metapage_t ** mpp)
+{
+	struct inode *ipimap = imap->im_ipimap;
+	s64 blkno;
+
+	/* compute the logical block number of the iag. */
+	blkno = IAGTOLBLK(iagno, JFS_SBI(ipimap->i_sb)->l2nbperpage);
+
+	/* read the iag. */
+	*mpp = read_metapage(ipimap, blkno, PSIZE, 0);
+	if (*mpp == NULL) {
+		return (EIO);
+	}
+
+	return (0);
+}
+
+/*
+ * NAME:        diFindFree()
+ *
+ * FUNCTION:    find the first free bit in a word starting at
+ *		the specified bit position.
+ *
+ * PARAMETERS:
+ *      word  	- word to be examined.
+ *      start  	- starting bit position.
+ *
+ * RETURN VALUES:
+ *      bit position of first free bit in the word or 32 if
+ *	no free bits were found.
+ */
+static int diFindFree(u32 word, int start)
+{
+	int bitno;
+	assert(start < 32);
+	/* scan the word for the first free bit. */
+	for (word <<= start, bitno = start; bitno < 32;
+	     bitno++, word <<= 1) {
+		if ((word & HIGHORDER) == 0)
+			break;
+	}
+	return (bitno);
+}
+
+/*
+ * NAME:	diUpdatePMap()
+ *                                                                    
+ * FUNCTION: Update the persistent map in an IAG for the allocation or 
+ *	freeing of the specified inode.
+ *                                                                    
+ * PRE CONDITIONS: Working map has already been updated for allocate.
+ *
+ * PARAMETERS:
+ *	ipimap	- Incore inode map inode
+ *	inum	- Number of inode to mark in permanent map
+ *	is_free	- If TRUE indicates inode should be marked freed, otherwise
+ *		  indicates inode should be marked allocated.
+ *
+ * RETURNS: 0 for success
+ */
+int
+diUpdatePMap(struct inode *ipimap,
+	     unsigned long inum, boolean_t is_free, tblock_t * tblk)
+{
+	int rc;
+	iag_t *iagp;
+	metapage_t *mp;
+	int iagno, ino, extno, bitno;
+	imap_t *imap;
+	u32 mask;
+	log_t *log;
+	int lsn, difft, diffp;
+
+	imap = JFS_IP(ipimap)->i_imap;
+	/* get the iag number containing the inode */
+	iagno = INOTOIAG(inum);
+	/* make sure that the iag is contained within the map */
+	assert(iagno < imap->im_nextiag);
+	/* read the iag */
+	IREAD_LOCK(ipimap);
+	rc = diIAGRead(imap, iagno, &mp);
+	IREAD_UNLOCK(ipimap);
+	if (rc)
+		return (rc);
+	iagp = (iag_t *) mp->data;
+	/* get the inode number and extent number of the inode within
+	 * the iag and the inode number within the extent.
+	 */
+	ino = inum & (INOSPERIAG - 1);
+	extno = ino >> L2INOSPEREXT;
+	bitno = ino & (INOSPEREXT - 1);
+	mask = HIGHORDER >> bitno;
+	/* 
+	 * mark the inode free in persistent map:
+	 */
+	if (is_free == TRUE) {
+		/* The inode should have been allocated both in working
+		 * map and in persistent map;
+		 * the inode will be freed from working map at the release
+		 * of last reference release;
+		 */
+//              assert(le32_to_cpu(iagp->wmap[extno]) & mask);
+		if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
+			jERROR(1,
+			       ("diUpdatePMap: inode %ld not marked as allocated in wmap!\n",
+				inum));
+			updateSuper(ipimap->i_sb, FM_DIRTY);
+		}
+//              assert(le32_to_cpu(iagp->pmap[extno]) & mask);
+		if (!(le32_to_cpu(iagp->pmap[extno]) & mask)) {
+			jERROR(1,
+			       ("diUpdatePMap: inode %ld not marked as allocated in pmap!\n",
+				inum));
+			updateSuper(ipimap->i_sb, FM_DIRTY);
+		}
+		/* update the bitmap for the extent of the freed inode */
+		iagp->pmap[extno] &= cpu_to_le32(~mask);
+	}
+	/*
+	 * mark the inode allocated in persistent map:
+	 */
+	else {
+		/* The inode should be already allocated in the working map
+		 * and should be free in persistent map;
+		 */
+		assert(le32_to_cpu(iagp->wmap[extno]) & mask);
+		assert((le32_to_cpu(iagp->pmap[extno]) & mask) == 0);
+		/* update the bitmap for the extent of the allocated inode */
+		iagp->pmap[extno] |= cpu_to_le32(mask);
+	}
+	/*
+	 * update iag lsn
+	 */
+	lsn = tblk->lsn;
+	log = JFS_SBI(tblk->sb)->log;
+	if (mp->lsn != 0) {
+		/* inherit older/smaller lsn */
+		logdiff(difft, lsn, log);
+		logdiff(diffp, mp->lsn, log);
+		if (difft < diffp) {
+			mp->lsn = lsn;
+			/* move mp after tblock in logsync list */
+			LOGSYNC_LOCK(log);
+			list_del(&mp->synclist);
+			list_add(&mp->synclist, &tblk->synclist);
+			LOGSYNC_UNLOCK(log);
+		}
+		/* inherit younger/larger clsn */
+		LOGSYNC_LOCK(log);
+		assert(mp->clsn);
+		logdiff(difft, tblk->clsn, log);
+		logdiff(diffp, mp->clsn, log);
+		if (difft > diffp)
+			mp->clsn = tblk->clsn;
+		LOGSYNC_UNLOCK(log);
+	} else {
+		mp->log = log;
+		mp->lsn = lsn;
+		/* insert mp after tblock in logsync list */
+		LOGSYNC_LOCK(log);
+		log->count++;
+		list_add(&mp->synclist, &tblk->synclist);
+		mp->clsn = tblk->clsn;
+		LOGSYNC_UNLOCK(log);
+	}
+//      bmLazyWrite(mp, log->flag & JFS_COMMIT);
+	write_metapage(mp);
+	return (0);
+}
+
+/*
+ *	diExtendFS()
+ *
+ * function: update imap for extendfs();
+ * 
+ * note: AG size has been increased s.t. each k old contiguous AGs are 
+ * coalesced into a new AG;
+ */
+int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
+{
+	int rc, rcx = 0;
+	imap_t *imap = JFS_IP(ipimap)->i_imap;
+	iag_t *iagp = 0, *hiagp = 0;
+	bmap_t *mp = JFS_SBI(ipbmap->i_sb)->bmap;
+	metapage_t *bp, *hbp;
+	int i, n, head;
+	int numinos, xnuminos = 0, xnumfree = 0;
+	s64 agstart;
+
+	jEVENT(0, ("diExtendFS: nextiag:%d numinos:%d numfree:%d\n",
+		   imap->im_nextiag, atomic_read(&imap->im_numinos),
+		   atomic_read(&imap->im_numfree)));
+
+	/*
+	 *      reconstruct imap 
+	 *
+	 * coalesce contiguous k (newAGSize/oldAGSize) AGs;
+	 * i.e., (AGi, ..., AGj) where i = k*n and j = k*(n+1) - 1 to AGn;
+	 * note: new AG size = old AG size * (2**x).
+	 */
+
+	/* init per AG control information im_agctl[] */
+	for (i = 0; i < MAXAG; i++) {
+		imap->im_agctl[i].inofree = -1;	/* free inode list */
+		imap->im_agctl[i].extfree = -1;	/* free extent list */
+		imap->im_agctl[i].numinos = 0;	/* number of backed inodes */
+		imap->im_agctl[i].numfree = 0;	/* number of free backed inodes */
+	}
+
+	/*
+	 *      process each iag_t page of the map.
+	 *
+	 * rebuild AG Free Inode List, AG Free Inode Extent List;
+	 */
+	for (i = 0; i < imap->im_nextiag; i++) {
+		if ((rc = diIAGRead(imap, i, &bp))) {
+			rcx = rc;
+			continue;
+		}
+		iagp = (iag_t *) bp->data;
+		assert(le32_to_cpu(iagp->iagnum) == i);
+
+		/* leave free iag in the free iag list */
+		if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {  
+		        release_metapage(bp);
+			continue;
+		}
+
+		/* agstart that computes to the same ag is treated as same; */
+		agstart = le64_to_cpu(iagp->agstart);
+		/* iagp->agstart = agstart & ~(mp->db_agsize - 1); */
+		n = agstart >> mp->db_agl2size;
+/*
+printf("diExtendFS: iag:%d agstart:%Ld agno:%d\n", i, agstart, n);
+*/
+
+		/* compute backed inodes */
+		numinos = (EXTSPERIAG - le32_to_cpu(iagp->nfreeexts))
+		    << L2INOSPEREXT;
+		if (numinos > 0) {
+			/* merge AG backed inodes */
+			imap->im_agctl[n].numinos += numinos;
+			xnuminos += numinos;
+		}
+
+		/* if any backed free inodes, insert at AG free inode list */
+		if ((int) le32_to_cpu(iagp->nfreeinos) > 0) {
+			if ((head = imap->im_agctl[n].inofree) == -1)
+				iagp->inofreefwd = iagp->inofreeback = -1;
+			else {
+				if ((rc = diIAGRead(imap, head, &hbp))) {
+					rcx = rc;
+					goto nextiag;
+				}
+				hiagp = (iag_t *) hbp->data;
+				hiagp->inofreeback =
+				    le32_to_cpu(iagp->iagnum);
+				iagp->inofreefwd = cpu_to_le32(head);
+				iagp->inofreeback = -1;
+				write_metapage(hbp);
+			}
+
+			imap->im_agctl[n].inofree =
+			    le32_to_cpu(iagp->iagnum);
+
+			/* merge AG backed free inodes */
+			imap->im_agctl[n].numfree +=
+			    le32_to_cpu(iagp->nfreeinos);
+			xnumfree += le32_to_cpu(iagp->nfreeinos);
+		}
+
+		/* if any free extents, insert at AG free extent list */
+		if (le32_to_cpu(iagp->nfreeexts) > 0) {
+			if ((head = imap->im_agctl[n].extfree) == -1)
+				iagp->extfreefwd = iagp->extfreeback = -1;
+			else {
+				if ((rc = diIAGRead(imap, head, &hbp))) {
+					rcx = rc;
+					goto nextiag;
+				}
+				hiagp = (iag_t *) hbp->data;
+				hiagp->extfreeback = iagp->iagnum;
+				iagp->extfreefwd = cpu_to_le32(head);
+				iagp->extfreeback = -1;
+				write_metapage(hbp);
+			}
+
+			imap->im_agctl[n].extfree =
+			    le32_to_cpu(iagp->iagnum);
+		}
+
+	      nextiag:
+		write_metapage(bp);
+	}
+
+	ASSERT(xnuminos == atomic_read(&imap->im_numinos) &&
+	       xnumfree == atomic_read(&imap->im_numfree));
+
+	return rcx;
+}
+
+
+/*
+ *	duplicateIXtree()
+ *
+ * serialization: IWRITE_LOCK held on entry/exit
+ *
+ * note: shadow page with regular inode (rel.2);
+ */
+static void
+duplicateIXtree(struct super_block *sb, s64 blkno, int xlen, s64 * xaddr)
+{
+	int rc;
+	tid_t tid;
+	struct inode *ip;
+	metapage_t *mpsuper;
+	struct jfs_superblock *j_sb;
+
+	/* if AIT2 ipmap2 is bad, do not try to update it */
+	if (JFS_SBI(sb)->mntflag & JFS_BAD_SAIT)	/* s_flag */
+		return;
+	ip = diReadSpecial(sb, FILESYSTEM_I + INOSPEREXT);
+	if (ip == 0) {
+		JFS_SBI(sb)->mntflag |= JFS_BAD_SAIT;
+		if ((rc = readSuper(sb, &mpsuper)))
+			return;
+		j_sb = (struct jfs_superblock *) (mpsuper->data);
+		j_sb->s_flag |= JFS_BAD_SAIT;
+		write_metapage(mpsuper);
+		return;
+	}
+
+	/* start transaction */
+	tid = txBegin(sb, COMMIT_FORCE);
+	/* update the inode map addressing structure to point to it */
+	if ((rc = xtInsert(tid, ip, 0, blkno, xlen, xaddr, 0))) {
+		JFS_SBI(sb)->mntflag |= JFS_BAD_SAIT;
+		txAbort(tid, 1);
+		goto cleanup;
+
+	}
+	/* update the inode map's inode to reflect the extension */
+	ip->i_size += PSIZE;
+	ip->i_blocks += LBLK2PBLK(sb, xlen);
+	rc = txCommit(tid, 1, &ip, COMMIT_FORCE);
+      cleanup:
+	txEnd(tid);
+	diFreeSpecial(ip);
+}
+
+/*
+ * NAME:        copy_from_dinode()
+ *
+ * FUNCTION:    Copies inode info from disk inode to in-memory inode
+ *
+ * RETURN VALUES:
+ *      0       - success
+ *      ENOMEM	- insufficient memory
+ */
+static int copy_from_dinode(dinode_t * dip, struct inode *ip)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+
+	jfs_ip->fileset = le32_to_cpu(dip->di_fileset);
+	jfs_ip->mode2 = le32_to_cpu(dip->di_mode);
+
+	ip->i_mode = le32_to_cpu(dip->di_mode) & 0xffff;
+	ip->i_nlink = le32_to_cpu(dip->di_nlink);
+	ip->i_uid = le32_to_cpu(dip->di_uid);
+	ip->i_gid = le32_to_cpu(dip->di_gid);
+	ip->i_size = le64_to_cpu(dip->di_size);
+	ip->i_atime = le32_to_cpu(dip->di_atime.tv_sec);
+	ip->i_mtime = le32_to_cpu(dip->di_mtime.tv_sec);
+	ip->i_ctime = le32_to_cpu(dip->di_ctime.tv_sec);
+	ip->i_blksize = ip->i_sb->s_blocksize;
+	ip->i_blocks = LBLK2PBLK(ip->i_sb, le64_to_cpu(dip->di_nblocks));
+	ip->i_version = ++event;
+	ip->i_generation = le32_to_cpu(dip->di_gen);
+
+	jfs_ip->ixpxd = dip->di_ixpxd;	/* in-memory pxd's are little-endian */
+	jfs_ip->acl = dip->di_acl;	/* as are dxd's */
+	jfs_ip->ea = dip->di_ea;
+	jfs_ip->next_index = le32_to_cpu(dip->di_next_index);
+	jfs_ip->otime = le32_to_cpu(dip->di_otime.tv_sec);
+	jfs_ip->acltype = le32_to_cpu(dip->di_acltype);
+	/*
+	 * We may only need to do this for "special" inodes (dmap, imap)
+	 */
+	if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode))
+		ip->i_rdev = to_kdev_t(le32_to_cpu(dip->di_rdev));
+	else if (S_ISDIR(ip->i_mode)) {
+		memcpy(&jfs_ip->i_dirtable, &dip->di_dirtable, 384);
+	} else if (!S_ISFIFO(ip->i_mode)) {
+		memcpy(&jfs_ip->i_xtroot, &dip->di_xtroot, 288);
+	}
+	/* Zero the in-memory-only stuff */
+	jfs_ip->cflag = 0;
+	jfs_ip->btindex = 0;
+	jfs_ip->btorder = 0;
+	jfs_ip->bxflag = 0;
+	jfs_ip->blid = 0;
+	jfs_ip->atlhead = 0;
+	jfs_ip->atltail = 0;
+	jfs_ip->xtlid = 0;
+	return (0);
+}
+
+/*
+ * NAME:        copy_to_dinode()
+ *
+ * FUNCTION:    Copies inode info from in-memory inode to disk inode
+ */
+static void copy_to_dinode(dinode_t * dip, struct inode *ip)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+
+	dip->di_fileset = cpu_to_le32(jfs_ip->fileset);
+	dip->di_inostamp = cpu_to_le32(JFS_SBI(ip->i_sb)->inostamp);
+	dip->di_number = cpu_to_le32(ip->i_ino);
+	dip->di_gen = cpu_to_le32(ip->i_generation);
+	dip->di_size = cpu_to_le64(ip->i_size);
+	dip->di_nblocks = cpu_to_le64(PBLK2LBLK(ip->i_sb, ip->i_blocks));
+	dip->di_nlink = cpu_to_le32(ip->i_nlink);
+	dip->di_uid = cpu_to_le32(ip->i_uid);
+	dip->di_gid = cpu_to_le32(ip->i_gid);
+	/*
+	 * mode2 is only needed for storing the higher order bits.
+	 * Trust i_mode for the lower order ones
+	 */
+	dip->di_mode = cpu_to_le32((jfs_ip->mode2 & 0xffff0000) | ip->i_mode);
+	dip->di_atime.tv_sec = cpu_to_le32(ip->i_atime);
+	dip->di_atime.tv_nsec = 0;
+	dip->di_ctime.tv_sec = cpu_to_le32(ip->i_ctime);
+	dip->di_ctime.tv_nsec = 0;
+	dip->di_mtime.tv_sec = cpu_to_le32(ip->i_mtime);
+	dip->di_mtime.tv_nsec = 0;
+	dip->di_ixpxd = jfs_ip->ixpxd;	/* in-memory pxd's are little-endian */
+	dip->di_acl = jfs_ip->acl;	/* as are dxd's */
+	dip->di_ea = jfs_ip->ea;
+	dip->di_next_index = cpu_to_le32(jfs_ip->next_index);
+	dip->di_otime.tv_sec = cpu_to_le32(jfs_ip->otime);
+	dip->di_otime.tv_nsec = 0;
+	dip->di_acltype = cpu_to_le32(jfs_ip->acltype);
+
+	if (S_ISCHR(ip->i_mode) || S_ISBLK(ip->i_mode))
+		dip->di_rdev = cpu_to_le32(kdev_t_to_nr(ip->i_rdev));
+}
+
+#ifdef	_JFS_DEBUG_IMAP
+/*
+ *	DBGdiInit()
+ */
+static void *DBGdiInit(imap_t * imap)
+{
+	u32 *dimap;
+	int size;
+	size = 64 * 1024;
+	if ((dimap = (u32 *) xmalloc(size, L2PSIZE, kernel_heap)) == NULL)
+		assert(0);
+	bzero((void *) dimap, size);
+	imap->im_DBGdimap = dimap;
+}
+
+/*
+ *	DBGdiAlloc()
+ */
+static void DBGdiAlloc(imap_t * imap, ino_t ino)
+{
+	u32 *dimap = imap->im_DBGdimap;
+	int w, b;
+	u32 m;
+	w = ino >> 5;
+	b = ino & 31;
+	m = 0x80000000 >> b;
+	assert(w < 64 * 256);
+	if (dimap[w] & m) {
+		printk("DEBUG diAlloc: duplicate alloc ino:0x%x\n", ino);
+	}
+	dimap[w] |= m;
+}
+
+/*
+ *	DBGdiFree()
+ */
+static void DBGdiFree(imap_t * imap, ino_t ino)
+{
+	u32 *dimap = imap->im_DBGdimap;
+	int w, b;
+	u32 m;
+	w = ino >> 5;
+	b = ino & 31;
+	m = 0x80000000 >> b;
+	assert(w < 64 * 256);
+	if ((dimap[w] & m) == 0) {
+		printk("DEBUG diFree: duplicate free ino:0x%x\n", ino);
+	}
+	dimap[w] &= ~m;
+}
+
+static void dump_cp(imap_t * ipimap, char *function, int line)
+{
+	printk("\n* ********* *\nControl Page %s %d\n", function, line);
+	printk("FreeIAG %d\tNextIAG %d\n", ipimap->im_freeiag,
+	       ipimap->im_nextiag);
+	printk("NumInos %d\tNumFree %d\n",
+	       atomic_read(&ipimap->im_numinos),
+	       atomic_read(&ipimap->im_numfree));
+	printk("AG InoFree %d\tAG ExtFree %d\n",
+	       ipimap->im_agctl[0].inofree, ipimap->im_agctl[0].extfree);
+	printk("AG NumInos %d\tAG NumFree %d\n",
+	       ipimap->im_agctl[0].numinos, ipimap->im_agctl[0].numfree);
+}
+
+static void dump_iag(iag_t * iag, char *function, int line)
+{
+	printk("\n* ********* *\nIAG %s %d\n", function, line);
+	printk("IagNum %d\tIAG Free %d\n", le32_to_cpu(iag->iagnum),
+	       le32_to_cpu(iag->iagfree));
+	printk("InoFreeFwd %d\tInoFreeBack %d\n",
+	       le32_to_cpu(iag->inofreefwd),
+	       le32_to_cpu(iag->inofreeback));
+	printk("ExtFreeFwd %d\tExtFreeBack %d\n",
+	       le32_to_cpu(iag->extfreefwd),
+	       le32_to_cpu(iag->extfreeback));
+	printk("NFreeInos %d\tNFreeExts %d\n", le32_to_cpu(iag->nfreeinos),
+	       le32_to_cpu(iag->nfreeexts));
+}
+#endif				/* _JFS_DEBUG_IMAP */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_imap.h linux-2.5.6-pre2/fs/jfs/jfs_imap.h
--- linux-2.5.6-pre1/fs/jfs/jfs_imap.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_imap.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,161 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef	_H_JFS_IMAP
+#define _H_JFS_IMAP
+
+#include "jfs_txnmgr.h"
+
+/*
+ *	jfs_imap.h: disk inode manager
+ */
+
+#define	EXTSPERIAG	128	/* number of disk inode extent per iag  */
+#define IMAPBLKNO	0	/* lblkno of dinomap within inode map   */
+#define SMAPSZ		4	/* number of words per summary map      */
+#define	EXTSPERSUM	32	/* number of extents per summary map entry */
+#define	L2EXTSPERSUM	5	/* l2 number of extents per summary map */
+#define	PGSPERIEXT	4	/* number of 4K pages per dinode extent */
+#define	MAXIAGS		((1<<20)-1)	/* maximum number of iags       */
+#define	MAXAG		128	/* maximum number of allocation groups  */
+
+#define AMAPSIZE      512	/* bytes in the IAG allocation maps */
+#define SMAPSIZE      16	/* bytes in the IAG summary maps */
+
+/* convert inode number to iag number */
+#define	INOTOIAG(ino)	((ino) >> L2INOSPERIAG)
+
+/* convert iag number to logical block number of the iag page */
+#define IAGTOLBLK(iagno,l2nbperpg)	(((iagno) + 1) << (l2nbperpg))
+
+/* get the starting block number of the 4K page of an inode extent
+ * that contains ino.
+ */
+#define INOPBLK(pxd,ino,l2nbperpg)    	(addressPXD((pxd)) +		\
+	((((ino) & (INOSPEREXT-1)) >> L2INOSPERPAGE) << (l2nbperpg)))
+
+/*
+ *	inode allocation map:
+ * 
+ * inode allocation map consists of 
+ * . the inode map control page and
+ * . inode allocation group pages (per 4096 inodes)
+ * which are addressed by standard JFS xtree.
+ */
+/*
+ *	inode allocation group page (per 4096 inodes of an AG)
+ */
+typedef struct {
+	s64 agstart;		/* 8: starting block of ag              */
+	s32 iagnum;		/* 4: inode allocation group number     */
+	s32 inofreefwd;		/* 4: ag inode free list forward        */
+	s32 inofreeback;	/* 4: ag inode free list back           */
+	s32 extfreefwd;		/* 4: ag inode extent free list forward */
+	s32 extfreeback;	/* 4: ag inode extent free list back    */
+	s32 iagfree;		/* 4: iag free list                     */
+
+	/* summary map: 1 bit per inode extent */
+	s32 inosmap[SMAPSZ];	/* 16: sum map of mapwords w/ free inodes;
+				 *      note: this indicates free and backed
+				 *      inodes, if the extent is not backed the
+				 *      value will be 1.  if the extent is
+				 *      backed but all inodes are being used the
+				 *      value will be 1.  if the extent is
+				 *      backed but at least one of the inodes is
+				 *      free the value will be 0.
+				 */
+	s32 extsmap[SMAPSZ];	/* 16: sum map of mapwords w/ free extents */
+	s32 nfreeinos;		/* 4: number of free inodes             */
+	s32 nfreeexts;		/* 4: number of free extents            */
+	/* (72) */
+	u8 pad[1976];		/* 1976: pad to 2048 bytes */
+	/* allocation bit map: 1 bit per inode (0 - free, 1 - allocated) */
+	u32 wmap[EXTSPERIAG];	/* 512: working allocation map  */
+	u32 pmap[EXTSPERIAG];	/* 512: persistent allocation map */
+	pxd_t inoext[EXTSPERIAG];	/* 1024: inode extent addresses */
+} iag_t;			/* (4096) */
+
+/*
+ *	per AG control information (in inode map control page)
+ */
+typedef struct {
+	s32 inofree;		/* 4: free inode list anchor            */
+	s32 extfree;		/* 4: free extent list anchor           */
+	s32 numinos;		/* 4: number of backed inodes           */
+	s32 numfree;		/* 4: number of free inodes             */
+} iagctl_t;			/* (16) */
+
+/*
+ *	per fileset/aggregate inode map control page
+ */
+typedef struct {
+	s32 in_freeiag;		/* 4: free iag list anchor     */
+	s32 in_nextiag;		/* 4: next free iag number     */
+	s32 in_numinos;		/* 4: num of backed inodes */
+	s32 in_numfree;		/* 4: num of free backed inodes */
+	s32 in_nbperiext;	/* 4: num of blocks per inode extent */
+	s32 in_l2nbperiext;	/* 4: l2 of in_nbperiext */
+	s32 in_diskblock;	/* 4: for standalone test driver  */
+	s32 in_maxag;		/* 4: for standalone test driver  */
+	u8 pad[2016];		/* 2016: pad to 2048 */
+	iagctl_t in_agctl[MAXAG];	/* 2048: AG control information */
+} dinomap_t;			/* (4096) */
+
+
+/*
+ *	In-core inode map control page
+ */
+typedef struct inomap {
+	dinomap_t im_imap;	/* 4096: inode allocation control */
+	struct inode *im_ipimap;	/* 4: ptr to inode for imap   */
+	struct semaphore im_freelock;	/* 4: iag free list lock      */
+	struct semaphore im_aglock[MAXAG];	/* 512: per AG locks          */
+	u32 *im_DBGdimap;
+	atomic_t im_numinos;	/* num of backed inodes */
+	atomic_t im_numfree;	/* num of free backed inodes */
+} imap_t;
+
+#define	im_freeiag	im_imap.in_freeiag
+#define	im_nextiag	im_imap.in_nextiag
+#define	im_agctl	im_imap.in_agctl
+#define	im_nbperiext	im_imap.in_nbperiext
+#define	im_l2nbperiext	im_imap.in_l2nbperiext
+
+/* for standalone testdriver
+ */
+#define	im_diskblock	im_imap.in_diskblock
+#define	im_maxag	im_imap.in_maxag
+
+extern int diFree(struct inode *);
+extern int diAlloc(struct inode *, boolean_t, struct inode *);
+extern int diSync(struct inode *);
+/* external references */
+extern int diUpdatePMap(struct inode *ipimap, unsigned long inum,
+			boolean_t is_free, tblock_t * tblk);
+#ifdef _STILL_TO_PORT
+extern int diExtendFS(inode_t * ipimap, inode_t * ipbmap);
+#endif				/* _STILL_TO_PORT */
+
+extern int diMount(struct inode *);
+extern int diUnmount(struct inode *, int);
+extern int diRead(struct inode *);
+extern void diClearExtension(struct inode *);
+extern struct inode *diReadSpecial(struct super_block *, ino_t);
+extern void diWriteSpecial(struct inode *);
+extern void diFreeSpecial(struct inode *);
+extern int diWrite(tid_t tid, struct inode *);
+#endif				/* _H_JFS_IMAP */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_incore.h linux-2.5.6-pre2/fs/jfs/jfs_incore.h
--- linux-2.5.6-pre1/fs/jfs/jfs_incore.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_incore.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,149 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/ 
+#ifndef _H_JFS_INCORE
+#define _H_JFS_INCORE
+
+#include <linux/slab.h>
+#include <asm/bitops.h>
+#include "jfs_types.h"
+#include "jfs_xtree.h"
+#include "jfs_dtree.h"
+
+/*
+ * JFS magic number
+ */
+#define JFS_SUPER_MAGIC 0x3153464a /* "JFS1" */
+
+/*
+ * Due to header ordering problems this can't be in jfs_lock.h
+ */
+typedef struct	jfs_rwlock {
+	struct rw_semaphore rw_sem;
+	atomic_t in_use;	/* for hacked implementation of trylock */
+} jfs_rwlock_t;
+
+/*
+ * JFS-private inode information
+ */
+struct jfs_inode_info {
+	int	fileset;	/* fileset number (always 16)*/
+	uint	mode2;		/* jfs-specific mode		*/
+	pxd_t   ixpxd;		/* inode extent descriptor	*/
+	dxd_t	acl;		/* dxd describing acl	*/
+	dxd_t	ea;		/* dxd describing ea	*/
+	time_t	otime;		/* time created	*/
+	uint	next_index;	/* next available directory entry index */
+	int	acltype;	/* Type of ACL	*/
+	short	btorder;	/* access order	*/
+	short	btindex;	/* btpage entry index*/
+	struct inode *ipimap;	/* inode map			*/
+	long	cflag;		/* commit flags		*/
+	u16	bxflag;		/* xflag of pseudo buffer?	*/
+	unchar	agno;		/* ag number			*/
+	unchar	pad;		/* pad			*/
+	lid_t	blid;		/* lid of pseudo buffer?	*/
+	lid_t	atlhead;	/* anonymous tlock list head	*/
+	lid_t	atltail;	/* anonymous tlock list tail	*/
+	struct list_head anon_inode_list; /* inodes having anonymous txns */
+	struct list_head mp_list; /* metapages in inode's address space */
+	jfs_rwlock_t rdwrlock;	/* read/write lock	*/
+	lid_t	xtlid;		/* lid of xtree lock on directory */
+	union {
+		struct {
+			xtpage_t _xtroot;	/* 288: xtree root */
+			struct inomap *_imap;	/* 4: inode map header	*/
+		} file;
+		struct {
+			dir_table_slot_t _table[12]; /* 96: directory index */
+			dtroot_t _dtroot;	/* 288: dtree root */
+		} dir;
+		struct {
+			unchar _unused[16];	/* 16: */
+			dxd_t _dxd;		/* 16: */
+			unchar _inline[128];	/* 128: inline symlink */
+		} link;
+	} u;
+	struct inode	vfs_inode;
+};
+#define i_xtroot u.file._xtroot
+#define i_imap u.file._imap
+#define i_dirtable u.dir._table
+#define i_dtroot u.dir._dtroot
+#define i_inline u.link._inline
+
+/*
+ * cflag
+ */
+enum cflags {
+	COMMIT_New,		/* never committed inode   */
+	COMMIT_Nolink,		/* inode committed with zero link count */
+	COMMIT_Inlineea,	/* commit inode inline EA */
+	COMMIT_Freewmap,	/* free WMAP at iClose() */
+	COMMIT_Dirty,		/* Inode is really dirty */
+	COMMIT_Holdlock,	/* Hold the IWRITE_LOCK until commit is done */
+	COMMIT_Dirtable,	/* commit changes to di_dirtable */
+	COMMIT_Stale,		/* data extent is no longer valid */
+	COMMIT_Synclist,	/* metadata pages on group commit synclist */
+};
+
+#define set_cflag(flag, ip)	set_bit(flag, &(JFS_IP(ip)->cflag))
+#define clear_cflag(flag, ip)	clear_bit(flag, &(JFS_IP(ip)->cflag))
+#define test_cflag(flag, ip)	test_bit(flag, &(JFS_IP(ip)->cflag))
+#define test_and_clear_cflag(flag, ip) \
+	test_and_clear_bit(flag, &(JFS_IP(ip)->cflag))
+/*
+ * JFS-private superblock information.
+ */
+struct jfs_sb_info {
+	unsigned long	mntflag;	/* 4: aggregate attributes	*/
+	struct inode	*ipbmap;	/* 4: block map inode		*/
+	struct inode	*ipaimap;	/* 4: aggregate inode map inode	*/
+	struct inode	*ipaimap2;	/* 4: secondary aimap inode	*/
+	struct inode	*ipimap;	/* 4: aggregate inode map inode	*/
+	struct jfs_log	*log;		/* 4: log			*/
+	short		bsize;		/* 2: logical block size	*/
+	short		l2bsize;	/* 2: log2 logical block size	*/
+	short		nbperpage;	/* 2: blocks per page		*/
+	short		l2nbperpage;	/* 2: log2 blocks per page	*/
+	short		l2niperblk;	/* 2: log2 inodes per page	*/
+	short		reserved;	/* 2: log2 inodes per page	*/
+	pxd_t		logpxd;		/* 8: pxd describing log	*/
+	pxd_t		ait2;		/* 8: pxd describing AIT copy	*/
+	/* Formerly in ipimap */
+	uint		gengen;		/* 4: inode generation generator*/
+	uint		inostamp;	/* 4: shows inode belongs to fileset*/
+
+        /* Formerly in ipbmap */
+	struct bmap	*bmap;		/* 4: incore bmap descriptor	*/
+	struct nls_table *nls_tab;	/* 4: current codepage		*/
+	struct inode	*direct_inode;	/* 4: inode for physical I/O	*/
+	struct address_space *direct_mapping; /* 4: mapping for physical I/O */
+	uint		state;		/* 4: mount/recovery state	*/
+};
+
+static inline struct jfs_inode_info *JFS_IP(struct inode *inode)
+{
+	return list_entry(inode, struct jfs_inode_info, vfs_inode);
+}
+#define JFS_SBI(sb)	((struct jfs_sb_info *)(sb)->u.generic_sbp)
+
+#define isReadOnly(ip)	((JFS_SBI((ip)->i_sb)->log) ? 0 : 1)
+
+#endif /* _H_JFS_INCORE */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_inode.c linux-2.5.6-pre2/fs/jfs/jfs_inode.c
--- linux-2.5.6-pre1/fs/jfs/jfs_inode.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_inode.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,132 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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/fs.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_imap.h"
+#include "jfs_dinode.h"
+#include "jfs_debug.h"
+
+/*
+ * NAME:	ialloc()
+ *
+ * FUNCTION:	Allocate a new inode
+ *
+ */
+struct inode *ialloc(struct inode *parent, umode_t mode)
+{
+	struct super_block *sb = parent->i_sb;
+	struct inode *inode;
+	struct jfs_inode_info *jfs_inode;
+	int rc;
+
+	inode = new_inode(sb);
+	if (!inode) {
+		jERROR(1, ("ialloc: new_inode returned NULL!\n"));
+		return inode;
+	}
+
+	jfs_inode = JFS_IP(inode);
+
+	rc = diAlloc(parent, S_ISDIR(mode), inode);
+	if (rc) {
+		jERROR(1, ("ialloc: diAlloc returned %d!\n", rc));
+		make_bad_inode(inode);
+		iput(inode);
+		return NULL;
+	}
+
+	inode->i_uid = current->fsuid;
+	if (parent->i_mode & S_ISGID) {
+		inode->i_gid = parent->i_gid;
+		if (S_ISDIR(mode))
+			mode |= S_ISGID;
+	} else
+		inode->i_gid = current->fsgid;
+
+	inode->i_mode = mode;
+	if (S_ISDIR(mode))
+		jfs_inode->mode2 = IDIRECTORY | mode;
+	else
+		jfs_inode->mode2 = INLINEEA | ISPARSE | mode;
+	inode->i_blksize = sb->s_blocksize;
+	inode->i_blocks = 0;
+	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+	jfs_inode->otime = inode->i_ctime;
+	inode->i_version = ++event;
+	inode->i_generation = JFS_SBI(sb)->gengen++;
+
+	jfs_inode->cflag = 0;
+	set_cflag(COMMIT_New, inode);
+
+	/* Zero remaining fields */
+	memset(&jfs_inode->acl, 0, sizeof(dxd_t));
+	memset(&jfs_inode->ea, 0, sizeof(dxd_t));
+	jfs_inode->next_index = 0;
+	jfs_inode->acltype = 0;
+	jfs_inode->btorder = 0;
+	jfs_inode->btindex = 0;
+	jfs_inode->bxflag = 0;
+	jfs_inode->blid = 0;
+	jfs_inode->atlhead = 0;
+	jfs_inode->atltail = 0;
+	jfs_inode->xtlid = 0;
+
+	jFYI(1, ("ialloc returns inode = 0x%p\n", inode));
+
+	return inode;
+}
+
+/*
+ * NAME:	iwritelocklist()
+ *
+ * FUNCTION:	Lock multiple inodes in sorted order to avoid deadlock
+ *
+ */
+void iwritelocklist(int n, ...)
+{
+	va_list ilist;
+	struct inode *sort[4];
+	struct inode *ip;
+	int k, m;
+
+	va_start(ilist, n);
+	for (k = 0; k < n; k++)
+		sort[k] = va_arg(ilist, struct inode *);
+	va_end(ilist);
+
+	/* Bubble sort in descending order */
+	do {
+		m = 0;
+		for (k = 0; k < n; k++)
+			if ((k + 1) < n
+			    && sort[k + 1]->i_ino > sort[k]->i_ino) {
+				ip = sort[k];
+				sort[k] = sort[k + 1];
+				sort[k + 1] = ip;
+				m++;
+			}
+	} while (m);
+
+	/* Lock them */
+	for (k = 0; k < n; k++) {
+		IWRITE_LOCK(sort[k]);
+	}
+}
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_inode.h linux-2.5.6-pre2/fs/jfs/jfs_inode.h
--- linux-2.5.6-pre1/fs/jfs/jfs_inode.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_inode.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,23 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef	_H_JFS_INODE
+#define _H_JFS_INODE
+
+extern struct inode *ialloc(struct inode *, umode_t);
+
+#endif				/* _H_JFS_INODE */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_lock.h linux-2.5.6-pre2/fs/jfs/jfs_lock.h
--- linux-2.5.6-pre1/fs/jfs/jfs_lock.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_lock.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,106 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef _H_JFS_LOCK
+#define _H_JFS_LOCK
+
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+
+/*
+ *	jfs_lock.h
+ *
+ * JFS lock definition for globally referenced locks
+ */
+
+/* readers/writer lock: thread-thread */
+
+/*
+ * RW semaphores do not currently have a trylock function.  Since the
+ * implementation varies by platform, I have implemented a platform-independent
+ * wrapper around the rw_semaphore routines.  If this turns out to be the best
+ * way of avoiding our locking problems, I will push to get a trylock
+ * implemented in the kernel, but I'd rather find a way to avoid having to
+ * use it.
+ */
+#define RDWRLOCK_T jfs_rwlock_t
+static inline void RDWRLOCK_INIT(jfs_rwlock_t * Lock)
+{
+	init_rwsem(&Lock->rw_sem);
+	atomic_set(&Lock->in_use, 0);
+}
+static inline void READ_LOCK(jfs_rwlock_t * Lock)
+{
+	atomic_inc(&Lock->in_use);
+	down_read(&Lock->rw_sem);
+}
+static inline void READ_UNLOCK(jfs_rwlock_t * Lock)
+{
+	up_read(&Lock->rw_sem);
+	atomic_dec(&Lock->in_use);
+}
+static inline void WRITE_LOCK(jfs_rwlock_t * Lock)
+{
+	atomic_inc(&Lock->in_use);
+	down_write(&Lock->rw_sem);
+}
+
+static inline int WRITE_TRYLOCK(jfs_rwlock_t * Lock)
+{
+	if (atomic_read(&Lock->in_use))
+		return 0;
+	WRITE_LOCK(Lock);
+	return 1;
+}
+static inline void WRITE_UNLOCK(jfs_rwlock_t * Lock)
+{
+	up_write(&Lock->rw_sem);
+	atomic_dec(&Lock->in_use);
+}
+
+#define IREAD_LOCK(ip)		READ_LOCK(&JFS_IP(ip)->rdwrlock)
+#define IREAD_UNLOCK(ip)	READ_UNLOCK(&JFS_IP(ip)->rdwrlock)
+#define IWRITE_LOCK(ip)		WRITE_LOCK(&JFS_IP(ip)->rdwrlock)
+#define IWRITE_TRYLOCK(ip)	WRITE_TRYLOCK(&JFS_IP(ip)->rdwrlock)
+#define IWRITE_UNLOCK(ip)	WRITE_UNLOCK(&JFS_IP(ip)->rdwrlock)
+#define IWRITE_LOCK_LIST	iwritelocklist
+
+extern void iwritelocklist(int, ...);
+
+/*
+ * Conditional sleep where condition is protected by spinlock
+ *
+ * lock_cmd and unlock_cmd take and release the spinlock
+ */
+#define __SLEEP_COND(wq, cond, lock_cmd, unlock_cmd)	\
+do {							\
+	DECLARE_WAITQUEUE(__wait, current);		\
+							\
+	add_wait_queue(&wq, &__wait);			\
+	for (;;) {					\
+		set_current_state(TASK_UNINTERRUPTIBLE);\
+		if (cond)				\
+			break;				\
+		unlock_cmd;				\
+		schedule();				\
+		lock_cmd;				\
+	}						\
+	current->state = TASK_RUNNING;			\
+	remove_wait_queue(&wq, &__wait);		\
+} while (0)
+
+#endif				/* _H_JFS_LOCK */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_logmgr.c linux-2.5.6-pre2/fs/jfs/jfs_logmgr.c
--- linux-2.5.6-pre1/fs/jfs/jfs_logmgr.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_logmgr.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,2490 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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
+ *
+*/
+
+/*
+ *	jfs_logmgr.c: log manager
+ *
+ * for related information, see transaction manager (jfs_txnmgr.c), and
+ * recovery manager (jfs_logredo.c).
+ *
+ * note: for detail, RTFS.
+ *
+ *	log buffer manager:
+ * special purpose buffer manager supporting log i/o requirements.
+ * per log serial pageout of logpage
+ * queuing i/o requests and redrive i/o at iodone
+ * maintain current logpage buffer
+ * no caching since append only
+ * appropriate jfs buffer cache buffers as needed
+ *
+ *	group commit:
+ * transactions which wrote COMMIT records in the same in-memory
+ * log page during the pageout of previous/current log page(s) are
+ * committed together by the pageout of the page.
+ *
+ *	TBD lazy commit:
+ * transactions are committed asynchronously when the log page
+ * containing it COMMIT is paged out when it becomes full;
+ *
+ *	serialization:
+ * . a per log lock serialize log write.
+ * . a per log lock serialize group commit.
+ * . a per log lock serialize log open/close;
+ *
+ *	TBD log integrity:
+ * careful-write (ping-pong) of last logpage to recover from crash
+ * in overwrite.
+ * detection of split (out-of-order) write of physical sectors
+ * of last logpage via timestamp at end of each sector
+ * with its mirror data array at trailer).
+ *
+ *	alternatives:
+ * lsn - 64-bit monotonically increasing integer vs
+ * 32-bit lspn and page eor.
+ */
+
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_metapage.h"
+#include "jfs_txnmgr.h"
+#include "jfs_debug.h"
+
+
+/*
+ * lbuf's ready to be redriven.  Protected by log_redrive_lock (jfsIOtask)
+ */
+static lbuf_t *log_redrive_list;
+static spinlock_t log_redrive_lock = SPIN_LOCK_UNLOCKED;
+
+
+/*
+ *	log read/write serialization (per log)
+ */
+#define LOG_LOCK_INIT(log)	init_MUTEX(&(log)->loglock)
+#define LOG_LOCK(log)		down(&((log)->loglock))
+#define LOG_UNLOCK(log)		up(&((log)->loglock))
+
+
+/*
+ *	log group commit serialization (per log)
+ */
+
+#define LOGGC_LOCK_INIT(log)	spin_lock_init(&(log)->gclock)
+#define LOGGC_LOCK(log)		spin_lock_irq(&(log)->gclock)
+#define LOGGC_UNLOCK(log)	spin_unlock_irq(&(log)->gclock)
+#define LOGGC_WAKEUP(tblk)	wake_up(&(tblk)->gcwait)
+
+/*
+ *	log sync serialization (per log)
+ */
+#define	LOGSYNC_DELTA(logsize)		min((logsize)/8, 128*LOGPSIZE)
+#define	LOGSYNC_BARRIER(logsize)	((logsize)/4)
+/*
+#define	LOGSYNC_DELTA(logsize)		min((logsize)/4, 256*LOGPSIZE)
+#define	LOGSYNC_BARRIER(logsize)	((logsize)/2)
+*/
+
+
+/*
+ *	log buffer cache synchronization
+ */
+static spinlock_t jfsLCacheLock = SPIN_LOCK_UNLOCKED;
+
+#define	LCACHE_LOCK(flags)	spin_lock_irqsave(&jfsLCacheLock, flags)
+#define	LCACHE_UNLOCK(flags)	spin_unlock_irqrestore(&jfsLCacheLock, flags)
+
+/*
+ * See __SLEEP_COND in jfs_locks.h
+ */
+#define LCACHE_SLEEP_COND(wq, cond, flags)	\
+do {						\
+	if (cond)				\
+		break;				\
+	__SLEEP_COND(wq, cond, LCACHE_LOCK(flags), LCACHE_UNLOCK(flags)); \
+} while (0)
+
+#define	LCACHE_WAKEUP(event)	wake_up(event)
+
+
+/*
+ *	lbuf buffer cache (lCache) control
+ */
+/* log buffer manager pageout control (cumulative, inclusive) */
+#define	lbmREAD		0x0001
+#define	lbmWRITE	0x0002	/* enqueue at tail of write queue;
+				 * init pageout if at head of queue;
+				 */
+#define	lbmRELEASE	0x0004	/* remove from write queue
+				 * at completion of pageout;
+				 * do not free/recycle it yet:
+				 * caller will free it;
+				 */
+#define	lbmSYNC		0x0008	/* do not return to freelist
+				 * when removed from write queue;
+				 */
+#define lbmFREE		0x0010	/* return to freelist
+				 * at completion of pageout;
+				 * the buffer may be recycled;
+				 */
+#define	lbmDONE		0x0020
+#define	lbmERROR	0x0040
+#define lbmGC		0x0080	/* lbmIODone to perform post-GC processing
+				 * of log page
+				 */
+#define lbmDIRECT	0x0100
+
+/*
+ * external references
+ */
+extern void vPut(struct inode *ip);
+extern void txLazyUnlock(tblock_t * tblk);
+extern int jfs_thread_stopped(void);
+extern struct task_struct *jfsIOtask;
+extern struct completion jfsIOwait;
+
+/*
+ * forward references
+ */
+static int lmWriteRecord(log_t * log, tblock_t * tblk, lrd_t * lrd,
+			 tlock_t * tlck);
+
+static int lmNextPage(log_t * log);
+static int lmLogInit(log_t * log);
+static int lmLogShutdown(log_t * log);
+
+static int lbmLogInit(log_t * log);
+static void lbmLogShutdown(log_t * log);
+static lbuf_t *lbmAllocate(log_t * log, int);
+static void lbmFree(lbuf_t * bp);
+static void lbmfree(lbuf_t * bp);
+static int lbmRead(log_t * log, int pn, lbuf_t ** bpp);
+static void lbmWrite(log_t * log, lbuf_t * bp, int flag, int cant_block);
+static void lbmDirectWrite(log_t * log, lbuf_t * bp, int flag);
+static int lbmIOWait(lbuf_t * bp, int flag);
+static bio_end_io_t lbmIODone;
+#ifdef _STILL_TO_PORT
+static void lbmDirectIODone(iobuf_t * ddbp);
+#endif				/* _STILL_TO_PORT */
+void lbmStartIO(lbuf_t * bp);
+void lmGCwrite(log_t * log, int cant_block);
+
+
+/*
+ *	statistics
+ */
+#ifdef CONFIG_JFS_STATISTICS
+struct lmStat {
+	uint commit;		/* # of commit */
+	uint pagedone;		/* # of page written */
+	uint submitted;		/* # of pages submitted */
+} lmStat;
+#endif
+
+
+/*
+ * NAME:	lmLog()
+ *
+ * FUNCTION:	write a log record;
+ *
+ * PARAMETER:
+ *
+ * RETURN:	lsn - offset to the next log record to write (end-of-log);
+ *		-1  - error;
+ *
+ * note: todo: log error handler
+ */
+int lmLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck)
+{
+	int lsn;
+	int diffp, difft;
+	metapage_t *mp = NULL;
+
+	jFYI(1, ("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p\n",
+		 log, tblk, lrd, tlck));
+
+	LOG_LOCK(log);
+
+	/* log by (out-of-transaction) JFS ? */
+	if (tblk == NULL)
+		goto writeRecord;
+
+	/* log from page ? */
+	if (tlck == NULL ||
+	    tlck->type & tlckBTROOT || (mp = tlck->mp) == NULL)
+		goto writeRecord;
+
+	/*
+	 *      initialize/update page/transaction recovery lsn
+	 */
+	lsn = log->lsn;
+
+	LOGSYNC_LOCK(log);
+
+	/*
+	 * initialize page lsn if first log write of the page
+	 */
+	if (mp->lsn == 0) {
+		mp->log = log;
+		mp->lsn = lsn;
+		log->count++;
+
+		/* insert page at tail of logsynclist */
+		list_add_tail(&mp->synclist, &log->synclist);
+	}
+
+	/*
+	 *      initialize/update lsn of tblock of the page
+	 *
+	 * transaction inherits oldest lsn of pages associated
+	 * with allocation/deallocation of resources (their
+	 * log records are used to reconstruct allocation map
+	 * at recovery time: inode for inode allocation map,
+	 * B+-tree index of extent descriptors for block
+	 * allocation map);
+	 * allocation map pages inherit transaction lsn at
+	 * commit time to allow forwarding log syncpt past log
+	 * records associated with allocation/deallocation of
+	 * resources only after persistent map of these map pages
+	 * have been updated and propagated to home.
+	 */
+	/*
+	 * initialize transaction lsn:
+	 */
+	if (tblk->lsn == 0) {
+		/* inherit lsn of its first page logged */
+		tblk->lsn = mp->lsn;
+		log->count++;
+
+		/* insert tblock after the page on logsynclist */
+		list_add(&tblk->synclist, &mp->synclist);
+	}
+	/*
+	 * update transaction lsn:
+	 */
+	else {
+		/* inherit oldest/smallest lsn of page */
+		logdiff(diffp, mp->lsn, log);
+		logdiff(difft, tblk->lsn, log);
+		if (diffp < difft) {
+			/* update tblock lsn with page lsn */
+			tblk->lsn = mp->lsn;
+
+			/* move tblock after page on logsynclist */
+			list_del(&tblk->synclist);
+			list_add(&tblk->synclist, &mp->synclist);
+		}
+	}
+
+	LOGSYNC_UNLOCK(log);
+
+	/*
+	 *      write the log record
+	 */
+      writeRecord:
+	lsn = lmWriteRecord(log, tblk, lrd, tlck);
+
+	/*
+	 * forward log syncpt if log reached next syncpt trigger
+	 */
+	logdiff(diffp, lsn, log);
+	if (diffp >= log->nextsync)
+		lsn = lmLogSync(log, 0);
+
+	/* update end-of-log lsn */
+	log->lsn = lsn;
+
+	LOG_UNLOCK(log);
+
+	/* return end-of-log address */
+	return lsn;
+}
+
+
+/*
+ * NAME:	lmWriteRecord()
+ *
+ * FUNCTION:	move the log record to current log page
+ *
+ * PARAMETER:	cd	- commit descriptor
+ *
+ * RETURN:	end-of-log address
+ *			
+ * serialization: LOG_LOCK() held on entry/exit
+ */
+static int
+lmWriteRecord(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck)
+{
+	int lsn = 0;		/* end-of-log address */
+	lbuf_t *bp;		/* dst log page buffer */
+	logpage_t *lp;		/* dst log page */
+	caddr_t dst;		/* destination address in log page */
+	int dstoffset;		/* end-of-log offset in log page */
+	int freespace;		/* free space in log page */
+	caddr_t p;		/* src meta-data page */
+	caddr_t src;
+	int srclen;
+	int nbytes;		/* number of bytes to move */
+	int i;
+	int len;
+	linelock_t *linelock;
+	lv_t *lv;
+	lvd_t *lvd;
+	int l2linesize;
+
+	len = 0;
+
+	/* retrieve destination log page to write */
+	bp = (lbuf_t *) log->bp;
+	lp = (logpage_t *) bp->l_ldata;
+	dstoffset = log->eor;
+
+	/* any log data to write ? */
+	if (tlck == NULL)
+		goto moveLrd;
+
+	/*
+	 *      move log record data
+	 */
+	/* retrieve source meta-data page to log */
+	if (tlck->flag & tlckPAGELOCK) {
+		p = (caddr_t) (tlck->mp->data);
+		linelock = (linelock_t *) & tlck->lock;
+	}
+	/* retrieve source in-memory inode to log */
+	else if (tlck->flag & tlckINODELOCK) {
+		if (tlck->type & tlckDTREE)
+			p = (caddr_t) &JFS_IP(tlck->ip)->i_dtroot;
+		else
+			p = (caddr_t) &JFS_IP(tlck->ip)->i_xtroot;
+		linelock = (linelock_t *) & tlck->lock;
+	}
+#ifdef	_JFS_WIP
+	else if (tlck->flag & tlckINLINELOCK) {
+
+		inlinelock = (inlinelock_t *) & tlck;
+		p = (caddr_t) & inlinelock->pxd;
+		linelock = (linelock_t *) & tlck;
+	}
+#endif				/* _JFS_WIP */
+	else {
+		jERROR(2, ("lmWriteRecord: UFO tlck:0x%p\n", tlck));
+		return 0;	/* Probably should trap */
+	}
+	l2linesize = linelock->l2linesize;
+
+      moveData:
+	ASSERT(linelock->index <= linelock->maxcnt);
+
+	lv = (lv_t *) & linelock->lv;
+	for (i = 0; i < linelock->index; i++, lv++) {
+		if (lv->length == 0)
+			continue;
+
+		/* is page full ? */
+		if (dstoffset >= LOGPSIZE - LOGPTLRSIZE) {
+			/* page become full: move on to next page */
+			lmNextPage(log);
+
+			bp = log->bp;
+			lp = (logpage_t *) bp->l_ldata;
+			dstoffset = LOGPHDRSIZE;
+		}
+
+		/*
+		 * move log vector data
+		 */
+		src = (u8 *) p + (lv->offset << l2linesize);
+		srclen = lv->length << l2linesize;
+		len += srclen;
+		while (srclen > 0) {
+			freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset;
+			nbytes = min(freespace, srclen);
+			dst = (caddr_t) lp + dstoffset;
+			memcpy(dst, src, nbytes);
+			dstoffset += nbytes;
+
+			/* is page not full ? */
+			if (dstoffset < LOGPSIZE - LOGPTLRSIZE)
+				break;
+
+			/* page become full: move on to next page */
+			lmNextPage(log);
+
+			bp = (lbuf_t *) log->bp;
+			lp = (logpage_t *) bp->l_ldata;
+			dstoffset = LOGPHDRSIZE;
+
+			srclen -= nbytes;
+			src += nbytes;
+		}
+
+		/*
+		 * move log vector descriptor
+		 */
+		len += 4;
+		lvd = (lvd_t *) ((caddr_t) lp + dstoffset);
+		lvd->offset = cpu_to_le16(lv->offset);
+		lvd->length = cpu_to_le16(lv->length);
+		dstoffset += 4;
+		jFYI(1,
+		     ("lmWriteRecord: lv offset:%d length:%d\n",
+		      lv->offset, lv->length));
+	}
+
+	if ((i = linelock->next)) {
+		linelock = (linelock_t *) lid_to_tlock(i);
+		goto moveData;
+	}
+
+	/*
+	 *      move log record descriptor
+	 */
+      moveLrd:
+	lrd->length = cpu_to_le16(len);
+
+	src = (caddr_t) lrd;
+	srclen = LOGRDSIZE;
+
+	while (srclen > 0) {
+		freespace = (LOGPSIZE - LOGPTLRSIZE) - dstoffset;
+		nbytes = min(freespace, srclen);
+		dst = (caddr_t) lp + dstoffset;
+		memcpy(dst, src, nbytes);
+
+		dstoffset += nbytes;
+		srclen -= nbytes;
+
+		/* are there more to move than freespace of page ? */
+		if (srclen)
+			goto pageFull;
+
+		/*
+		 * end of log record descriptor
+		 */
+
+		/* update last log record eor */
+		log->eor = dstoffset;
+		bp->l_eor = dstoffset;
+		lsn = (log->page << L2LOGPSIZE) + dstoffset;
+
+		if (lrd->type & cpu_to_le16(LOG_COMMIT)) {
+			tblk->clsn = lsn;
+			jFYI(1,
+			     ("wr: tclsn:0x%x, beor:0x%x\n", tblk->clsn,
+			      bp->l_eor));
+
+			INCREMENT(lmStat.commit);	/* # of commit */
+
+			/*
+			 * enqueue tblock for group commit:
+			 *
+			 * enqueue tblock of non-trivial/synchronous COMMIT
+			 * at tail of group commit queue
+			 * (trivial/asynchronous COMMITs are ignored by
+			 * group commit.)
+			 */
+			LOGGC_LOCK(log);
+
+			/* init tblock gc state */
+			tblk->flag = tblkGC_QUEUE;
+			tblk->bp = log->bp;
+			tblk->pn = log->page;
+			tblk->eor = log->eor;
+			init_waitqueue_head(&tblk->gcwait);
+
+			/* enqueue transaction to commit queue */
+			tblk->cqnext = NULL;
+			if (log->cqueue.head) {
+				log->cqueue.tail->cqnext = tblk;
+				log->cqueue.tail = tblk;
+			} else
+				log->cqueue.head = log->cqueue.tail = tblk;
+
+			LOGGC_UNLOCK(log);
+		}
+
+		jFYI(1,
+		     ("lmWriteRecord: lrd:0x%04x bp:0x%p pn:%d eor:0x%x\n",
+		      le16_to_cpu(lrd->type), log->bp, log->page,
+		      dstoffset));
+
+		/* page not full ? */
+		if (dstoffset < LOGPSIZE - LOGPTLRSIZE)
+			return lsn;
+
+	      pageFull:
+		/* page become full: move on to next page */
+		lmNextPage(log);
+
+		bp = (lbuf_t *) log->bp;
+		lp = (logpage_t *) bp->l_ldata;
+		dstoffset = LOGPHDRSIZE;
+		src += nbytes;
+	}
+
+	return lsn;
+}
+
+
+/*
+ * NAME:	lmNextPage()
+ *
+ * FUNCTION:	write current page and allocate next page.
+ *
+ * PARAMETER:	log
+ *
+ * RETURN:	0
+ *			
+ * serialization: LOG_LOCK() held on entry/exit
+ */
+static int lmNextPage(log_t * log)
+{
+	logpage_t *lp;
+	int lspn;		/* log sequence page number */
+	int pn;			/* current page number */
+	lbuf_t *bp;
+	lbuf_t *nextbp;
+	tblock_t *tblk;
+
+	jFYI(1, ("lmNextPage\n"));
+
+	/* get current log page number and log sequence page number */
+	pn = log->page;
+	bp = log->bp;
+	lp = (logpage_t *) bp->l_ldata;
+	lspn = le32_to_cpu(lp->h.page);
+
+	LOGGC_LOCK(log);
+
+	/*
+	 *      write or queue the full page at the tail of write queue
+	 */
+	/* get the tail tblk on commit queue */
+	tblk = log->cqueue.tail;
+
+	/* every tblk who has COMMIT record on the current page,
+	 * and has not been committed, must be on commit queue
+	 * since tblk is queued at commit queueu at the time
+	 * of writing its COMMIT record on the page before
+	 * page becomes full (even though the tblk thread
+	 * who wrote COMMIT record may have been suspended
+	 * currently);
+	 */
+
+	/* is page bound with outstanding tail tblk ? */
+	if (tblk && tblk->pn == pn) {
+		/* mark tblk for end-of-page */
+		tblk->flag |= tblkGC_EOP;
+
+		/* if page is not already on write queue,
+		 * just enqueue (no lbmWRITE to prevent redrive)
+		 * buffer to wqueue to ensure correct serial order
+		 * of the pages since log pages will be added
+		 * continuously (tblk bound with the page hasn't
+		 * got around to init write of the page, either
+		 * preempted or the page got filled by its COMMIT
+		 * record);
+		 * pages with COMMIT are paged out explicitly by
+		 * tblk in lmGroupCommit();
+		 */
+		if (bp->l_wqnext == NULL) {
+			/* bp->l_ceor = bp->l_eor; */
+			/* lp->h.eor = lp->t.eor = bp->l_ceor; */
+			lbmWrite(log, bp, 0, 0);
+		}
+	}
+	/* page is not bound with outstanding tblk:
+	 * init write or mark it to be redriven (lbmWRITE)
+	 */
+	else {
+		/* finalize the page */
+		bp->l_ceor = bp->l_eor;
+		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
+		lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE, 0);
+	}
+	LOGGC_UNLOCK(log);
+
+	/*
+	 *      allocate/initialize next page
+	 */
+	/* if log wraps, the first data page of log is 2
+	 * (0 never used, 1 is superblock).
+	 */
+	log->page = (pn == log->size - 1) ? 2 : pn + 1;
+	log->eor = LOGPHDRSIZE;	/* ? valid page empty/full at logRedo() */
+
+	/* allocate/initialize next log page buffer */
+	nextbp = lbmAllocate(log, log->page);
+	nextbp->l_eor = log->eor;
+	log->bp = nextbp;
+
+	/* initialize next log page */
+	lp = (logpage_t *) nextbp->l_ldata;
+	lp->h.page = lp->t.page = cpu_to_le32(lspn + 1);
+	lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE);
+
+	jFYI(1, ("lmNextPage done\n"));
+	return 0;
+}
+
+
+/*
+ * NAME:	lmGroupCommit()
+ *
+ * FUNCTION:	group commit
+ *	initiate pageout of the pages with COMMIT in the order of
+ *	page number - redrive pageout of the page at the head of
+ *	pageout queue until full page has been written.
+ *
+ * RETURN:	
+ *
+ * NOTE:
+ *	LOGGC_LOCK serializes log group commit queue, and
+ *	transaction blocks on the commit queue.
+ *	N.B. LOG_LOCK is NOT held during lmGroupCommit().
+ */
+int lmGroupCommit(log_t * log, tblock_t * tblk)
+{
+	int rc = 0;
+
+	LOGGC_LOCK(log);
+
+	/* group committed already ? */
+	if (tblk->flag & tblkGC_COMMITTED) {
+		if (tblk->flag & tblkGC_ERROR)
+			rc = EIO;
+
+		LOGGC_UNLOCK(log);
+		return rc;
+	}
+	jFYI(1,
+	     ("lmGroup Commit: tblk = 0x%p, gcrtc = %d\n", tblk,
+	      log->gcrtc));
+
+	/*
+	 * group commit pageout in progress
+	 */
+	if ((!(log->cflag & logGC_PAGEOUT)) && log->cqueue.head) {
+		/*
+		 * only transaction in the commit queue:
+		 *
+		 * start one-transaction group commit as
+		 * its group leader.
+		 */
+		log->cflag |= logGC_PAGEOUT;
+
+		lmGCwrite(log, 0);
+	}
+	/* lmGCwrite gives up LOGGC_LOCK, check again */
+
+	if (tblk->flag & tblkGC_COMMITTED) {
+		if (tblk->flag & tblkGC_ERROR)
+			rc = EIO;
+
+		LOGGC_UNLOCK(log);
+		return rc;
+	}
+
+	/* upcount transaction waiting for completion
+	 */
+	log->gcrtc++;
+
+	if (tblk->xflag & COMMIT_LAZY) {
+		tblk->flag |= tblkGC_LAZY;
+		LOGGC_UNLOCK(log);
+		return 0;
+	}
+	tblk->flag |= tblkGC_READY;
+
+	__SLEEP_COND(tblk->gcwait, (tblk->flag & tblkGC_COMMITTED),
+		     LOGGC_LOCK(log), LOGGC_UNLOCK(log));
+
+	/* removed from commit queue */
+	if (tblk->flag & tblkGC_ERROR)
+		rc = EIO;
+
+	LOGGC_UNLOCK(log);
+	return rc;
+}
+
+/*
+ * NAME:	lmGCwrite()
+ *
+ * FUNCTION:	group commit write
+ *	initiate write of log page, building a group of all transactions
+ *	with commit records on that page.
+ *
+ * RETURN:	None
+ *
+ * NOTE:
+ *	LOGGC_LOCK must be held by caller.
+ *	N.B. LOG_LOCK is NOT held during lmGroupCommit().
+ */
+void lmGCwrite(log_t * log, int cant_write)
+{
+	lbuf_t *bp;
+	logpage_t *lp;
+	int gcpn;		/* group commit page number */
+	tblock_t *tblk;
+	tblock_t *xtblk;
+
+	/*
+	 * build the commit group of a log page
+	 *
+	 * scan commit queue and make a commit group of all
+	 * transactions with COMMIT records on the same log page.
+	 */
+	/* get the head tblk on the commit queue */
+	tblk = xtblk = log->cqueue.head;
+	gcpn = tblk->pn;
+
+	while (tblk && tblk->pn == gcpn) {
+		xtblk = tblk;
+
+		/* state transition: (QUEUE, READY) -> COMMIT */
+		tblk->flag |= tblkGC_COMMIT;
+		tblk = tblk->cqnext;
+	}
+	tblk = xtblk;		/* last tblk of the page */
+
+	/*
+	 * pageout to commit transactions on the log page.
+	 */
+	bp = (lbuf_t *) tblk->bp;
+	lp = (logpage_t *) bp->l_ldata;
+	/* is page already full ? */
+	if (tblk->flag & tblkGC_EOP) {
+		/* mark page to free at end of group commit of the page */
+		tblk->flag &= ~tblkGC_EOP;
+		tblk->flag |= tblkGC_FREE;
+		bp->l_ceor = bp->l_eor;
+		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
+		jEVENT(0,
+		       ("gc: tclsn:0x%x, bceor:0x%x\n", tblk->clsn,
+			bp->l_ceor));
+		lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmGC,
+			 cant_write);
+	}
+	/* page is not yet full */
+	else {
+		bp->l_ceor = tblk->eor;	/* ? bp->l_ceor = bp->l_eor; */
+		lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_ceor);
+		jEVENT(0,
+		       ("gc: tclsn:0x%x, bceor:0x%x\n", tblk->clsn,
+			bp->l_ceor));
+		lbmWrite(log, bp, lbmWRITE | lbmGC, cant_write);
+	}
+}
+
+/*
+ * NAME:	lmPostGC()
+ *
+ * FUNCTION:	group commit post-processing
+ *	Processes transactions after their commit records have been written
+ *	to disk, redriving log I/O if necessary.
+ *
+ * RETURN:	None
+ *
+ * NOTE:
+ *	This routine is called a interrupt time by lbmIODone
+ */
+void lmPostGC(lbuf_t * bp)
+{
+	unsigned long flags;
+	log_t *log = bp->l_log;
+	logpage_t *lp;
+	tblock_t *tblk;
+
+	//LOGGC_LOCK(log);
+	spin_lock_irqsave(&log->gclock, flags);
+	/*
+	 * current pageout of group commit completed.
+	 *
+	 * remove/wakeup transactions from commit queue who were
+	 * group committed with the current log page
+	 */
+	while ((tblk = log->cqueue.head) && (tblk->flag & tblkGC_COMMIT)) {
+		/* if transaction was marked GC_COMMIT then
+		 * it has been shipped in the current pageout
+		 * and made it to disk - it is committed.
+		 */
+
+		if (bp->l_flag & lbmERROR)
+			tblk->flag |= tblkGC_ERROR;
+
+		/* remove it from the commit queue */
+		log->cqueue.head = tblk->cqnext;
+		if (log->cqueue.head == NULL)
+			log->cqueue.tail = NULL;
+		tblk->flag &= ~tblkGC_QUEUE;
+		tblk->cqnext = 0;
+
+		jEVENT(0,
+		       ("lmPostGC: tblk = 0x%p, flag = 0x%x\n", tblk,
+			tblk->flag));
+
+		if (!(tblk->xflag & COMMIT_FORCE))
+			/*
+			 * Hand tblk over to lazy commit thread
+			 */
+			txLazyUnlock(tblk);
+		else {
+			/* state transition: COMMIT -> COMMITTED */
+			tblk->flag |= tblkGC_COMMITTED;
+
+			if (tblk->flag & tblkGC_READY) {
+				log->gcrtc--;
+				LOGGC_WAKEUP(tblk);
+			}
+		}
+
+		/* was page full before pageout ?
+		 * (and this is the last tblk bound with the page)
+		 */
+		if (tblk->flag & tblkGC_FREE)
+			lbmFree(bp);
+		/* did page become full after pageout ?
+		 * (and this is the last tblk bound with the page)
+		 */
+		else if (tblk->flag & tblkGC_EOP) {
+			/* finalize the page */
+			lp = (logpage_t *) bp->l_ldata;
+			bp->l_ceor = bp->l_eor;
+			lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
+			jEVENT(0, ("lmPostGC: calling lbmWrite\n"));
+			lbmWrite(log, bp, lbmWRITE | lbmRELEASE | lbmFREE,
+				 1);
+		}
+
+	}
+
+	/* are there any transactions who have entered lnGroupCommit()
+	 * (whose COMMITs are after that of the last log page written.
+	 * They are waiting for new group commit (above at (SLEEP 1)):
+	 * select the latest ready transaction as new group leader and
+	 * wake her up to lead her group.
+	 */
+	if ((log->gcrtc > 0) && log->cqueue.head)
+		/*
+		 * Call lmGCwrite with new group leader
+		 */
+		lmGCwrite(log, 1);
+
+	/* no transaction are ready yet (transactions are only just
+	 * queued (GC_QUEUE) and not entered for group commit yet).
+	 * let the first transaction entering group commit
+	 * will elect hetself as new group leader.
+	 */
+	else
+		log->cflag &= ~logGC_PAGEOUT;
+
+	//LOGGC_UNLOCK(log);
+	spin_unlock_irqrestore(&log->gclock, flags);
+	return;
+}
+
+/*
+ * NAME:	lmLogSync()
+ *
+ * FUNCTION:	write log SYNCPT record for specified log
+ *	if new sync address is available
+ *	(normally the case if sync() is executed by back-ground
+ *	process).
+ *	if not, explicitly run jfs_blogsync() to initiate
+ *	getting of new sync address.
+ *	calculate new value of i_nextsync which determines when
+ *	this code is called again.
+ *
+ *	this is called only from lmLog().
+ *
+ * PARAMETER:	ip	- pointer to logs inode.
+ *
+ * RETURN:	0
+ *			
+ * serialization: LOG_LOCK() held on entry/exit
+ */
+int lmLogSync(log_t * log, int nosyncwait)
+{
+	int logsize;
+	int written;		/* written since last syncpt */
+	int free;		/* free space left available */
+	int delta;		/* additional delta to write normally */
+	int more;		/* additional write granted */
+	lrd_t lrd;
+	int lsn;
+	struct logsyncblk *lp;
+
+	/*
+	 *      forward syncpt
+	 */
+	/* if last sync is same as last syncpt,
+	 * invoke sync point forward processing to update sync.
+	 */
+
+	if (log->sync == log->syncpt) {
+		LOGSYNC_LOCK(log);
+		/* ToDo: push dirty metapages out to disk */
+//              bmLogSync(log);
+
+		if (list_empty(&log->synclist))
+			log->sync = log->lsn;
+		else {
+			lp = list_entry(log->synclist.next,
+					struct logsyncblk, synclist);
+			log->sync = lp->lsn;
+		}
+		LOGSYNC_UNLOCK(log);
+
+	}
+
+	/* if sync is different from last syncpt,
+	 * write a SYNCPT record with syncpt = sync.
+	 * reset syncpt = sync
+	 */
+	if (log->sync != log->syncpt) {
+		struct jfs_sb_info	*sbi = JFS_SBI(log->sb);
+		/*
+		 * We need to make sure all of the "written" metapages
+		 * actually make it to disk
+		 */
+		fsync_inode_data_buffers(sbi->ipbmap);
+		fsync_inode_data_buffers(sbi->ipimap);
+		fsync_inode_data_buffers(sbi->direct_inode);
+
+		lrd.logtid = 0;
+		lrd.backchain = 0;
+		lrd.type = cpu_to_le16(LOG_SYNCPT);
+		lrd.length = 0;
+		lrd.log.syncpt.sync = cpu_to_le32(log->sync);
+		lsn = lmWriteRecord(log, NULL, &lrd, NULL);
+
+		log->syncpt = log->sync;
+	} else
+		lsn = log->lsn;
+
+	/*
+	 *      setup next syncpt trigger (SWAG)
+	 */
+	logsize = log->logsize;
+
+	logdiff(written, lsn, log);
+	free = logsize - written;
+	delta = LOGSYNC_DELTA(logsize);
+	more = min(free / 2, delta);
+	if (more < 2 * LOGPSIZE) {
+		jEVENT(1,
+		       ("\n ... Log Wrap ... Log Wrap ... Log Wrap ...\n\n"));
+		/*
+		 *      log wrapping
+		 *
+		 * option 1 - panic ? No.!
+		 * option 2 - shutdown file systems
+		 *            associated with log ?
+		 * option 3 - extend log ?
+		 */
+		/*
+		 * option 4 - second chance
+		 *
+		 * mark log wrapped, and continue.
+		 * when all active transactions are completed,
+		 * mark log vaild for recovery.
+		 * if crashed during invalid state, log state
+		 * implies invald log, forcing fsck().
+		 */
+		/* mark log state log wrap in log superblock */
+		/* log->state = LOGWRAP; */
+
+		/* reset sync point computation */
+		log->syncpt = log->sync = lsn;
+		log->nextsync = delta;
+	} else
+		/* next syncpt trigger = written + more */
+		log->nextsync = written + more;
+
+	/* return if lmLogSync() from outside of transaction, e.g., sync() */
+	if (nosyncwait)
+		return lsn;
+
+	/* if number of bytes written from last sync point is more
+	 * than 1/4 of the log size, stop new transactions from
+	 * starting until all current transactions are completed
+	 * by setting syncbarrier flag.
+	 */
+	if (written > LOGSYNC_BARRIER(logsize) && logsize > 32 * LOGPSIZE) {
+		log->syncbarrier = 1;
+		jFYI(1, ("log barrier on: lsn=0x%x syncpt=0x%x\n", lsn,
+			 log->syncpt));
+	}
+
+	return lsn;
+}
+
+
+/*
+ * NAME:	lmLogOpen()
+ *
+ * FUNCTION:    open the log on first open;
+ *	insert filesystem in the active list of the log.
+ *
+ * PARAMETER:	ipmnt	- file system mount inode
+ *		iplog 	- log inode (out)
+ *
+ * RETURN:
+ *
+ * serialization:
+ */
+int lmLogOpen(struct super_block *sb, log_t ** logptr)
+{
+	int rc;
+	kdev_t logdev;		/* dev_t of log device */
+	log_t *log;
+
+	logdev = sb->s_dev;
+
+#ifdef _STILL_TO_PORT
+	/*
+	 * open the inode representing the log device (aka log inode)
+	 */
+	if (logdev != fsdev)
+		goto externalLog;
+#endif				/* _STILL_TO_PORT */
+
+	/*
+	 *      in-line log in host file system
+	 *
+	 * file system to log have 1-to-1 relationship;
+	 */
+//    inlineLog:
+
+	*logptr = log = kmalloc(sizeof(log_t), GFP_KERNEL);
+	if (log == 0)
+		return ENOMEM;
+
+	memset(log, 0, sizeof(log_t));
+	log->sb = sb;		/* This should be a list */
+	log->flag = JFS_INLINELOG;
+	log->dev = logdev;
+	log->base = addressPXD(&JFS_SBI(sb)->logpxd);
+	log->size = lengthPXD(&JFS_SBI(sb)->logpxd) >>
+	    (L2LOGPSIZE - sb->s_blocksize_bits);
+	log->l2bsize = sb->s_blocksize_bits;
+	ASSERT(L2LOGPSIZE >= sb->s_blocksize_bits);
+	/*
+	 * initialize log.
+	 */
+	if ((rc = lmLogInit(log)))
+		goto errout10;
+
+#ifdef _STILL_TO_PORT
+	goto out;
+
+	/*
+	 *      external log as separate logical volume
+	 *
+	 * file systems to log may have n-to-1 relationship;
+	 */
+      externalLog:
+	/*
+	 * open log inode
+	 *
+	 * log inode is reserved inode of (dev_t = log device,
+	 * fileset number = 0, i_number = 0), which acquire
+	 * one i_count for each open by file system.
+	 *
+	 * hand craft dummy vfs to force iget() the special case of
+	 * an in-memory inode allocation without on-disk inode
+	 */
+	memset(&dummyvfs, 0, sizeof(struct vfs));
+	dummyvfs.filesetvfs.vfs_data = NULL;
+	dummyvfs.dummyvfs.dev = logdev;
+	dummyvfs.dummyvfs.ipmnt = NULL;
+	ICACHE_LOCK();
+	rc = iget((struct vfs *) &dummyvfs, 0, (inode_t **) & log, 0);
+	ICACHE_UNLOCK();
+	if (rc)
+		return rc;
+
+	log->flag = 0;
+	log->dev = logdev;
+	log->base = 0;
+	log->size = 0;
+
+	/*
+	 * serialize open/close between multiple file systems
+	 * bound with the log;
+	 */
+	ip = (inode_t *) log;
+	IWRITE_LOCK(ip);
+
+	/*
+	 * subsequent open: add file system to log active file system list
+	 */
+#ifdef	_JFS_OS2
+	if (log->strat2p)
+#endif				/* _JFS_OS2 */
+	{
+		if (rc = lmLogFileSystem(log, fsdev, 1))
+			goto errout10;
+
+		IWRITE_UNLOCK(ip);
+
+		*iplog = ip;
+		jFYI(1, ("lmLogOpen: exit(0)\n"));
+		return 0;
+	}
+
+	/* decouple log inode from dummy vfs */
+	vPut(ip);
+
+	/*
+	 * first open:
+	 */
+#ifdef	_JFS_OS2
+	/*
+	 * establish access to the single/shared (already open) log device
+	 */
+	logdevfp = (void *) logStrat2;
+	log->strat2p = logStrat2;
+	log->strat3p = logStrat3;
+
+	log->l2pbsize = 9;	/* todo: when OS/2 have multiple external log */
+#endif				/* _JFS_OS2 */
+
+	/*
+	 * initialize log:
+	 */
+	if (rc = lmLogInit(log))
+		goto errout20;
+
+	/*
+	 * add file system to log active file system list
+	 */
+	if (rc = lmLogFileSystem(log, fsdev, 1))
+		goto errout30;
+
+	/*
+	 *      insert log device into log device list
+	 */
+      out:
+#endif				/*  _STILL_TO_PORT */
+	jFYI(1, ("lmLogOpen: exit(0)\n"));
+	return 0;
+
+	/*
+	 *      unwind on error
+	 */
+#ifdef _STILL_TO_PORT
+      errout30:		/* unwind lbmLogInit() */
+	lbmLogShutdown(log);
+
+      errout20:		/* close external log device */
+
+#endif				/* _STILL_TO_PORT */
+      errout10:		/* free log inode */
+	kfree(log);
+
+	jFYI(1, ("lmLogOpen: exit(%d)\n", rc));
+	return rc;
+}
+
+
+/*
+ * NAME:	lmLogInit()
+ *
+ * FUNCTION:	log initialization at first log open.
+ *
+ *	logredo() (or logformat()) should have been run previously.
+ *	initialize the log inode from log superblock.
+ *	set the log state in the superblock to LOGMOUNT and
+ *	write SYNCPT log record.
+ *		
+ * PARAMETER:	log	- log structure
+ *
+ * RETURN:	0	- if ok
+ *		EINVAL	- bad log magic number or superblock dirty
+ *		error returned from logwait()
+ *			
+ * serialization: single first open thread
+ */
+static int lmLogInit(log_t * log)
+{
+	int rc = 0;
+	lrd_t lrd;
+	logsuper_t *logsuper;
+	lbuf_t *bpsuper;
+	lbuf_t *bp;
+	logpage_t *lp;
+	int lsn;
+
+	jFYI(1, ("lmLogInit: log:0x%p\n", log));
+
+	/*
+	 * log inode is overlaid on generic inode where
+	 * dinode have been zeroed out by iRead();
+	 */
+
+	/*
+	 * initialize log i/o
+	 */
+	if ((rc = lbmLogInit(log)))
+		return rc;
+
+	/*
+	 * validate log superblock
+	 */
+	if ((rc = lbmRead(log, 1, &bpsuper)))
+		goto errout10;
+
+	logsuper = (logsuper_t *) bpsuper->l_ldata;
+
+	if (logsuper->magic != cpu_to_le32(LOGMAGIC)) {
+		jERROR(1, ("*** Log Format Error ! ***\n"));
+		rc = EINVAL;
+		goto errout20;
+	}
+
+	/* logredo() should have been run successfully. */
+	if (logsuper->state != cpu_to_le32(LOGREDONE)) {
+		jERROR(1, ("*** Log Is Dirty ! ***\n"));
+		rc = EINVAL;
+		goto errout20;
+	}
+
+	/* initialize log inode from log superblock */
+	if (log->flag & JFS_INLINELOG) {
+		if (log->size != le32_to_cpu(logsuper->size)) {
+			rc = EINVAL;
+			goto errout20;
+		}
+		jFYI(0,
+		     ("lmLogInit: inline log:0x%p base:0x%Lx size:0x%x\n",
+		      log, (unsigned long long) log->base, log->size));
+	} else {
+		log->size = le32_to_cpu(logsuper->size);
+		jFYI(0,
+		     ("lmLogInit: external log:0x%p base:0x%Lx size:0x%x\n",
+		      log, (unsigned long long) log->base, log->size));
+	}
+
+	log->flag |= JFS_GROUPCOMMIT;
+/*
+	log->flag |= JFS_LAZYCOMMIT;
+*/
+	log->page = le32_to_cpu(logsuper->end) / LOGPSIZE;
+	log->eor = le32_to_cpu(logsuper->end) - (LOGPSIZE * log->page);
+
+	/*
+	 * initialize for log append write mode
+	 */
+	/* establish current/end-of-log page/buffer */
+	if ((rc = lbmRead(log, log->page, &bp)))
+		goto errout20;
+
+	lp = (logpage_t *) bp->l_ldata;
+
+	jFYI(1, ("lmLogInit: lsn:0x%x page:%d eor:%d:%d\n",
+		 le32_to_cpu(logsuper->end), log->page, log->eor,
+		 le16_to_cpu(lp->h.eor)));
+
+//      ASSERT(log->eor == lp->h.eor);
+
+	log->bp = bp;
+	bp->l_pn = log->page;
+	bp->l_eor = log->eor;
+
+	/* initialize the group commit serialization lock */
+	LOGGC_LOCK_INIT(log);
+
+	/* if current page is full, move on to next page */
+	if (log->eor >= LOGPSIZE - LOGPTLRSIZE)
+		lmNextPage(log);
+
+	/* allocate/initialize the log write serialization lock */
+	LOG_LOCK_INIT(log);
+
+	/*
+	 * initialize log syncpoint
+	 */
+	/*
+	 * write the first SYNCPT record with syncpoint = 0
+	 * (i.e., log redo up to HERE !);
+	 * remove current page from lbm write queue at end of pageout
+	 * (to write log superblock update), but do not release to freelist;
+	 */
+	lrd.logtid = 0;
+	lrd.backchain = 0;
+	lrd.type = cpu_to_le16(LOG_SYNCPT);
+	lrd.length = 0;
+	lrd.log.syncpt.sync = 0;
+	lsn = lmWriteRecord(log, NULL, &lrd, NULL);
+	bp = log->bp;
+	bp->l_ceor = bp->l_eor;
+	lp = (logpage_t *) bp->l_ldata;
+	lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
+	lbmWrite(log, bp, lbmWRITE | lbmSYNC, 0);
+	if ((rc = lbmIOWait(bp, 0)))
+		goto errout30;
+
+	/* initialize logsync parameters */
+	log->logsize = (log->size - 2) << L2LOGPSIZE;
+	log->lsn = lsn;
+	log->syncpt = lsn;
+	log->sync = log->syncpt;
+	log->nextsync = LOGSYNC_DELTA(log->logsize);
+	init_waitqueue_head(&log->syncwait);
+
+	jFYI(1, ("lmLogInit: lsn:0x%x syncpt:0x%x sync:0x%x\n",
+		 log->lsn, log->syncpt, log->sync));
+
+	LOGSYNC_LOCK_INIT(log);
+
+	INIT_LIST_HEAD(&log->synclist);
+
+	log->cqueue.head = log->cqueue.tail = 0;
+
+	log->count = 0;
+
+	/*
+	 * initialize for lazy/group commit
+	 */
+	log->clsn = lsn;
+
+	/*
+	 * update/write superblock
+	 */
+	logsuper->state = cpu_to_le32(LOGMOUNT);
+	log->serial = le32_to_cpu(logsuper->serial) + 1;
+	logsuper->serial = cpu_to_le32(log->serial);
+	lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
+	if ((rc = lbmIOWait(bpsuper, lbmFREE)))
+		goto errout30;
+
+	jFYI(1, ("lmLogInit: exit(%d)\n", rc));
+	return 0;
+
+	/*
+	 *      unwind on error
+	 */
+      errout30:		/* release log page */
+	lbmFree(bp);
+
+      errout20:		/* release log superblock */
+	lbmFree(bpsuper);
+
+      errout10:		/* unwind lbmLogInit() */
+	lbmLogShutdown(log);
+
+	jFYI(1, ("lmLogInit: exit(%d)\n", rc));
+	return rc;
+}
+
+
+/*
+ * NAME:	lmLogClose()
+ *
+ * FUNCTION:	remove file system <ipmnt> from active list of log <iplog>
+ *		and close it on last close.
+ *
+ * PARAMETER:	sb	- superblock
+ *		log	- log inode
+ *
+ * RETURN:	errors from subroutines
+ *
+ * serialization:
+ */
+int lmLogClose(struct super_block *sb, log_t * log)
+{
+	int rc;
+
+	jFYI(1, ("lmLogClose: log:0x%p\n", log));
+
+	/*
+	 *      in-line log in host file system
+	 */
+//      inlineLog:
+#ifdef _STILL_TO_PORT
+	if (log->flag & JFS_INLINELOG) {
+		rc = lmLogShutdown(log);
+
+		goto out1;
+	}
+
+	/*
+	 *      external log as separate logical volume
+	 */
+      externalLog:
+
+	/* serialize open/close between multiple file systems
+	 * associated with the log
+	 */
+	IWRITE_LOCK(iplog);
+
+	/*
+	 * remove file system from log active file system list
+	 */
+	rc = lmLogFileSystem(log, fsdev, 0);
+
+	if (iplog->i_count > 1)
+		goto out2;
+
+	/*
+	 *      last close: shut down log
+	 */
+	rc = ((rc1 = lmLogShutdown(log)) && rc == 0) ? rc1 : rc;
+
+      out1:
+#else				/* _STILL_TO_PORT */
+	rc = lmLogShutdown(log);
+#endif				/* _STILL_TO_PORT */
+
+//      out2:
+
+	jFYI(0, ("lmLogClose: exit(%d)\n", rc));
+	return rc;
+}
+
+
+/*
+ * NAME:	lmLogShutdown()
+ *
+ * FUNCTION:	log shutdown at last LogClose().
+ *
+ *		write log syncpt record.
+ *		update super block to set redone flag to 0.
+ *
+ * PARAMETER:	log	- log inode
+ *
+ * RETURN:	0	- success
+ *			
+ * serialization: single last close thread
+ */
+static int lmLogShutdown(log_t * log)
+{
+	int rc;
+	lrd_t lrd;
+	int lsn;
+	logsuper_t *logsuper;
+	lbuf_t *bpsuper;
+	lbuf_t *bp;
+	logpage_t *lp;
+
+	jFYI(1, ("lmLogShutdown: log:0x%p\n", log));
+
+	if (log->cqueue.head || !list_empty(&log->synclist)) {
+		/*
+		 * If there was very recent activity, we may need to wait
+		 * for the lazycommit thread to catch up
+		 */
+		int i;
+
+		for (i = 0; i < 800; i++) {	/* Too much? */
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(HZ / 4);
+			if ((log->cqueue.head == NULL) &&
+			    list_empty(&log->synclist))
+				break;
+		}
+	}
+	assert(log->cqueue.head == NULL);
+	assert(list_empty(&log->synclist));
+
+	/*
+	 * We need to make sure all of the "written" metapages
+	 * actually make it to disk
+	 */
+	fsync_no_super(log->sb->s_bdev);
+
+	/*
+	 * write the last SYNCPT record with syncpoint = 0
+	 * (i.e., log redo up to HERE !)
+	 */
+	lrd.logtid = 0;
+	lrd.backchain = 0;
+	lrd.type = cpu_to_le16(LOG_SYNCPT);
+	lrd.length = 0;
+	lrd.log.syncpt.sync = 0;
+	lsn = lmWriteRecord(log, NULL, &lrd, NULL);
+	bp = log->bp;
+	lp = (logpage_t *) bp->l_ldata;
+	lp->h.eor = lp->t.eor = cpu_to_le16(bp->l_eor);
+	lbmWrite(log, log->bp, lbmWRITE | lbmRELEASE | lbmSYNC, 0);
+	lbmIOWait(log->bp, lbmFREE);
+
+	/*
+	 * synchronous update log superblock
+	 * mark log state as shutdown cleanly
+	 * (i.e., Log does not need to be replayed).
+	 */
+	if ((rc = lbmRead(log, 1, &bpsuper)))
+		goto out;
+
+	logsuper = (logsuper_t *) bpsuper->l_ldata;
+	logsuper->state = cpu_to_le32(LOGREDONE);
+	logsuper->end = cpu_to_le32(lsn);
+	lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
+	rc = lbmIOWait(bpsuper, lbmFREE);
+
+	jFYI(1, ("lmLogShutdown: lsn:0x%x page:%d eor:%d\n",
+		 lsn, log->page, log->eor));
+
+      out:    
+	/*
+	 * shutdown per log i/o
+	 */
+	lbmLogShutdown(log);
+
+	if (rc) {
+		jFYI(1, ("lmLogShutdown: exit(%d)\n", rc));
+	}
+	return rc;
+}
+
+
+#ifdef _STILL_TO_PORT
+/*
+ * NAME:	lmLogFileSystem()
+ *
+ * FUNCTION:	insert (<activate> = true)/remove (<activate> = false)
+ *	file system into/from log active file system list.
+ *
+ * PARAMETE:	log	- pointer to logs inode.
+ *		fsdev	- dev_t of filesystem.
+ *		serial  - pointer to returned log serial number
+ *		activate - insert/remove device from active list.
+ *
+ * RETURN:	0	- success
+ *		errors returned by vms_iowait().
+ *			
+ * serialization: IWRITE_LOCK(log inode) held on entry/exit
+ */
+static int lmLogFileSystem(log_t * log, dev_t fsdev, int activate)
+{
+	int rc = 0;
+	int bit, word;
+	logsuper_t *logsuper;
+	lbuf_t *bpsuper;
+
+	/*
+	 * insert/remove file system device to log active file system list.
+	 */
+	if ((rc = lbmRead(log, 1, &bpsuper)))
+		return rc;
+
+	logsuper = (logsuper_t *) bpsuper->l_ldata;
+	bit = MINOR(fsdev);
+	word = bit / 32;
+	bit -= 32 * word;
+	if (activate)
+		logsuper->active[word] |=
+		    cpu_to_le32((LEFTMOSTONE >> bit));
+	else
+		logsuper->active[word] &=
+		    cpu_to_le32((~(LEFTMOSTONE >> bit)));
+
+	/*
+	 * synchronous write log superblock:
+	 *
+	 * write sidestream bypassing write queue:
+	 * at file system mount, log super block is updated for
+	 * activation of the file system before any log record
+	 * (MOUNT record) of the file system, and at file system
+	 * unmount, all meta data for the file system has been
+	 * flushed before log super block is updated for deactivation
+	 * of the file system.
+	 */
+	lbmDirectWrite(log, bpsuper, lbmWRITE | lbmRELEASE | lbmSYNC);
+	rc = lbmIOWait(bpsuper, lbmFREE);
+
+	return rc;
+}
+#endif				/* _STILL_TO_PORT */
+
+
+/*
+ *	lmLogQuiesce()
+ */
+int lmLogQuiesce(log_t * log)
+{
+	int rc;
+
+	rc = lmLogShutdown(log);
+
+	return rc;
+}
+
+
+/*
+ *	lmLogResume()
+ */
+int lmLogResume(log_t * log, struct super_block *sb)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	int rc;
+
+	log->base = addressPXD(&sbi->logpxd);
+	log->size =
+	    (lengthPXD(&sbi->logpxd) << sb->s_blocksize_bits) >> L2LOGPSIZE;
+	rc = lmLogInit(log);
+
+	return rc;
+}
+
+
+/*
+ *		log buffer manager (lbm)
+ *		------------------------
+ *
+ * special purpose buffer manager supporting log i/o requirements.
+ *
+ * per log write queue:
+ * log pageout occurs in serial order by fifo write queue and
+ * restricting to a single i/o in pregress at any one time.
+ * a circular singly-linked list
+ * (log->wrqueue points to the tail, and buffers are linked via
+ * bp->wrqueue field), and
+ * maintains log page in pageout ot waiting for pageout in serial pageout.
+ */
+
+/*
+ *	lbmLogInit()
+ *
+ * initialize per log I/O setup at lmLogInit()
+ */
+static int lbmLogInit(log_t * log)
+{				/* log inode */
+	int i;
+	lbuf_t *lbuf;
+
+	jFYI(1, ("lbmLogInit: log:0x%p\n", log));
+
+	/* initialize current buffer cursor */
+	log->bp = NULL;
+
+	/* initialize log device write queue */
+	log->wqueue = NULL;
+
+	/*
+	 * Each log has its own buffer pages allocated to it.  These are
+	 * not managed by the page cache.  This ensures that a transaction
+	 * writing to the log does not block trying to allocate a page from
+	 * the page cache (for the log).  This would be bad, since page
+	 * allocation waits on the kswapd thread that may be committing inodes
+	 * which would cause log activity.  Was that clear?  I'm trying to
+	 * avoid deadlock here.
+	 */
+	init_waitqueue_head(&log->free_wait);
+
+	log->lbuf_free = NULL;
+
+	for (i = 0; i < LOGPAGES; i++) {
+		lbuf = kmalloc(sizeof(lbuf_t), GFP_KERNEL);
+		if (lbuf == 0)
+			goto error;
+		lbuf->l_ldata = (char *) __get_free_page(GFP_KERNEL);
+		if (lbuf->l_ldata == 0) {
+			kfree(lbuf);
+			goto error;
+		}
+		lbuf->l_log = log;
+		init_waitqueue_head(&lbuf->l_ioevent);
+
+		lbuf->l_freelist = log->lbuf_free;
+		log->lbuf_free = lbuf;
+	}
+
+	return (0);
+
+      error:
+	lbmLogShutdown(log);
+	return (ENOMEM);
+}
+
+
+/*
+ *	lbmLogShutdown()
+ *
+ * finalize per log I/O setup at lmLogShutdown()
+ */
+static void lbmLogShutdown(log_t * log)
+{
+	lbuf_t *lbuf;
+
+	jFYI(1, ("lbmLogShutdown: log:0x%p\n", log));
+
+	lbuf = log->lbuf_free;
+	while (lbuf) {
+		lbuf_t *next = lbuf->l_freelist;
+		free_page((unsigned long) lbuf->l_ldata);
+		kfree(lbuf);
+		lbuf = next;
+	}
+
+	log->bp = NULL;
+}
+
+
+/*
+ *	lbmAllocate()
+ *
+ * allocate an empty log buffer
+ */
+static lbuf_t *lbmAllocate(log_t * log, int pn)
+{
+	lbuf_t *bp;
+	unsigned long flags;
+
+	/*
+	 * recycle from log buffer freelist if any
+	 */
+	LCACHE_LOCK(flags);
+	LCACHE_SLEEP_COND(log->free_wait, (bp = log->lbuf_free), flags);
+	log->lbuf_free = bp->l_freelist;
+	LCACHE_UNLOCK(flags);
+
+	bp->l_flag = 0;
+
+	bp->l_wqnext = NULL;
+	bp->l_freelist = NULL;
+
+	bp->l_pn = pn;
+	bp->l_blkno = log->base + (pn << (L2LOGPSIZE - log->l2bsize));
+	bp->l_ceor = 0;
+
+	return bp;
+}
+
+
+/*
+ *	lbmFree()
+ *
+ * release a log buffer to freelist
+ */
+static void lbmFree(lbuf_t * bp)
+{
+	unsigned long flags;
+
+	LCACHE_LOCK(flags);
+
+	lbmfree(bp);
+
+	LCACHE_UNLOCK(flags);
+}
+
+static void lbmfree(lbuf_t * bp)
+{
+	log_t *log = bp->l_log;
+
+	assert(bp->l_wqnext == NULL);
+
+	/*
+	 * return the buffer to head of freelist
+	 */
+	bp->l_freelist = log->lbuf_free;
+	log->lbuf_free = bp;
+
+	wake_up(&log->free_wait);
+	return;
+}
+
+
+#ifdef _THIS_IS_NOT_USED
+/*
+ *	lbmRelease()
+ *
+ * remove the log buffer from log device write queue;
+ */
+static void lbmRelease(log_t * log, uint flag)
+{
+	lbuf_t *bp, *tail;
+	unsigned long flags;
+
+	bp = log->bp;
+
+	LCACHE_LOCK(flags);
+
+	tail = log->wqueue;
+
+	/* single element queue */
+	if (bp == tail) {
+		log->wqueue = NULL;
+		bp->l_wqnext = NULL;
+	}
+	/* multi element queue */
+	else {
+		tail->l_wqnext = bp->l_wqnext;
+		bp->l_wqnext = NULL;
+	}
+
+	if (flag & lbmFREE)
+		lbmfree(bp);
+
+	LCACHE_UNLOCK(flags);
+}
+#endif				/* _THIS_IS_NOT_USED */
+
+
+/*
+ * NAME:	lbmRedrive
+ *
+ * FUNCTION:	add a log buffer to the the log redrive list
+ *
+ * PARAMETER:
+ *     bp	- log buffer
+ *
+ * NOTES:
+ *	Takes log_redrive_lock.
+ */
+static inline void lbmRedrive(lbuf_t *bp)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&log_redrive_lock, flags);
+	bp->l_redrive_next = log_redrive_list;
+	log_redrive_list = bp;
+	spin_unlock_irqrestore(&log_redrive_lock, flags);
+
+	wake_up_process(jfsIOtask);
+}
+
+
+/*
+ *	lbmRead()
+ */
+static int lbmRead(log_t * log, int pn, lbuf_t ** bpp)
+{
+	struct bio *bio;
+	lbuf_t *bp;
+
+	/*
+	 * allocate a log buffer
+	 */
+	*bpp = bp = lbmAllocate(log, pn);
+	jFYI(1, ("lbmRead: bp:0x%p pn:0x%x\n", bp, pn));
+
+	bp->l_flag |= lbmREAD;
+
+	bio = bio_alloc(GFP_NOFS, 1);
+
+	bio->bi_sector = bp->l_blkno << (log->l2bsize - 9);
+	bio->bi_dev = log->dev;
+	bio->bi_io_vec[0].bv_page = virt_to_page(bp->l_ldata);
+	bio->bi_io_vec[0].bv_len = LOGPSIZE;
+	bio->bi_io_vec[0].bv_offset = 0;
+
+	bio->bi_vcnt = 1;
+	bio->bi_idx = 0;
+	bio->bi_size = LOGPSIZE;
+
+	bio->bi_end_io = lbmIODone;
+	bio->bi_private = bp;
+	submit_bio(READ, bio);
+	run_task_queue(&tq_disk);
+
+	wait_event(bp->l_ioevent, (bp->l_flag != lbmREAD));
+
+	return 0;
+}
+
+
+/*
+ *	lbmWrite()
+ *
+ * buffer at head of pageout queue stays after completion of
+ * partial-page pageout and redriven by explicit initiation of
+ * pageout by caller until full-page pageout is completed and
+ * released.
+ *
+ * device driver i/o done redrives pageout of new buffer at
+ * head of pageout queue when current buffer at head of pageout
+ * queue is released at the completion of its full-page pageout.
+ *
+ * LOGGC_LOCK() serializes lbmWrite() by lmNextPage() and lmGroupCommit().
+ * LCACHE_LOCK() serializes xflag between lbmWrite() and lbmIODone()
+ */
+static void lbmWrite(log_t * log, lbuf_t * bp, int flag, int cant_block)
+{
+	lbuf_t *tail;
+	unsigned long flags;
+
+	jFYI(1, ("lbmWrite: bp:0x%p flag:0x%x pn:0x%x\n",
+		 bp, flag, bp->l_pn));
+
+	/* map the logical block address to physical block address */
+	bp->l_blkno =
+	    log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize));
+
+	LCACHE_LOCK(flags);		/* disable+lock */
+
+	/*
+	 * initialize buffer for device driver
+	 */
+	bp->l_flag = flag;
+
+	/*
+	 *      insert bp at tail of write queue associated with log
+	 *
+	 * (request is either for bp already/currently at head of queue
+	 * or new bp to be inserted at tail)
+	 */
+	tail = log->wqueue;
+
+	/* is buffer not already on write queue ? */
+	if (bp->l_wqnext == NULL) {
+		/* insert at tail of wqueue */
+		if (tail == NULL) {
+			log->wqueue = bp;
+			bp->l_wqnext = bp;
+		} else {
+			log->wqueue = bp;
+			bp->l_wqnext = tail->l_wqnext;
+			tail->l_wqnext = bp;
+		}
+
+		tail = bp;
+	}
+
+	/* is buffer at head of wqueue and for write ? */
+	if ((bp != tail->l_wqnext) || !(flag & lbmWRITE)) {
+		LCACHE_UNLOCK(flags);	/* unlock+enable */
+		return;
+	}
+
+	LCACHE_UNLOCK(flags);	/* unlock+enable */
+
+	if (cant_block)
+		lbmRedrive(bp);
+	else if (flag & lbmSYNC)
+		lbmStartIO(bp);
+	else {
+		LOGGC_UNLOCK(log);
+		lbmStartIO(bp);
+		LOGGC_LOCK(log);
+	}
+}
+
+
+/*
+ *	lbmDirectWrite()
+ *
+ * initiate pageout bypassing write queue for sidestream
+ * (e.g., log superblock) write;
+ */
+static void lbmDirectWrite(log_t * log, lbuf_t * bp, int flag)
+{
+	jEVENT(0, ("lbmDirectWrite: bp:0x%p flag:0x%x pn:0x%x\n",
+		   bp, flag, bp->l_pn));
+
+	/*
+	 * initialize buffer for device driver
+	 */
+	bp->l_flag = flag | lbmDIRECT;
+
+	/* map the logical block address to physical block address */
+	bp->l_blkno =
+	    log->base + (bp->l_pn << (L2LOGPSIZE - log->l2bsize));
+
+	/*
+	 *      initiate pageout of the page
+	 */
+	lbmStartIO(bp);
+}
+
+
+/*
+ * NAME:	lbmStartIO()
+ *
+ * FUNCTION:	Interface to DD strategy routine
+ *
+ * RETURN:      none
+ *
+ * serialization: LCACHE_LOCK() is NOT held during log i/o;
+ */
+void lbmStartIO(lbuf_t * bp)
+{
+	struct bio *bio;
+	log_t *log = bp->l_log;
+
+	jFYI(1, ("lbmStartIO\n"));
+
+	bio = bio_alloc(GFP_NOFS, 1);
+	bio->bi_sector = bp->l_blkno << (log->l2bsize - 9);
+	bio->bi_dev = log->dev;
+	bio->bi_io_vec[0].bv_page = virt_to_page(bp->l_ldata);
+	bio->bi_io_vec[0].bv_len = LOGPSIZE;
+	bio->bi_io_vec[0].bv_offset = 0;
+
+	bio->bi_vcnt = 1;
+	bio->bi_idx = 0;
+	bio->bi_size = LOGPSIZE;
+
+	bio->bi_end_io = lbmIODone;
+	bio->bi_private = bp;
+
+	submit_bio(WRITE, bio);
+
+	INCREMENT(lmStat.submitted);
+	run_task_queue(&tq_disk);
+
+	jFYI(1, ("lbmStartIO done\n"));
+}
+
+
+/*
+ *	lbmIOWait()
+ */
+static int lbmIOWait(lbuf_t * bp, int flag)
+{
+	unsigned long flags;
+	int rc = 0;
+
+	jFYI(1,
+	     ("lbmIOWait1: bp:0x%p flag:0x%x:0x%x\n", bp, bp->l_flag,
+	      flag));
+
+	LCACHE_LOCK(flags);		/* disable+lock */
+
+	LCACHE_SLEEP_COND(bp->l_ioevent, (bp->l_flag & lbmDONE), flags);
+
+	rc = (bp->l_flag & lbmERROR) ? EIO : 0;
+
+	if (flag & lbmFREE)
+		lbmfree(bp);
+
+	LCACHE_UNLOCK(flags);	/* unlock+enable */
+
+	jFYI(1,
+	     ("lbmIOWait2: bp:0x%p flag:0x%x:0x%x\n", bp, bp->l_flag,
+	      flag));
+	return rc;
+}
+
+/*
+ *	lbmIODone()
+ *
+ * executed at INTIODONE level
+ */
+static void lbmIODone(struct bio *bio)
+{
+	lbuf_t *bp = bio->bi_private;
+	lbuf_t *nextbp, *tail;
+	log_t *log;
+	unsigned long flags;
+
+	/*
+	 * get back jfs buffer bound to the i/o buffer
+	 */
+	jEVENT(0, ("lbmIODone: bp:0x%p flag:0x%x\n", bp, bp->l_flag));
+
+	LCACHE_LOCK(flags);		/* disable+lock */
+
+	bp->l_flag |= lbmDONE;
+
+	if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+		bp->l_flag |= lbmERROR;
+
+		jERROR(1, ("lbmIODone: I/O error in JFS log\n"));
+	}
+	bio_put(bio);
+
+	/*
+	 *      pagein completion
+	 */
+	if (bp->l_flag & lbmREAD) {
+		bp->l_flag &= ~lbmREAD;
+
+		LCACHE_UNLOCK(flags);	/* unlock+enable */
+
+		/* wakeup I/O initiator */
+		LCACHE_WAKEUP(&bp->l_ioevent);
+
+		return;
+	}
+
+	/*
+	 *      pageout completion
+	 *
+	 * the bp at the head of write queue has completed pageout.
+	 *
+	 * if single-commit/full-page pageout, remove the current buffer
+	 * from head of pageout queue, and redrive pageout with
+	 * the new buffer at head of pageout queue;
+	 * otherwise, the partial-page pageout buffer stays at
+	 * the head of pageout queue to be redriven for pageout
+	 * by lmGroupCommit() until full-page pageout is completed.
+	 */
+	bp->l_flag &= ~lbmWRITE;
+	INCREMENT(lmStat.pagedone);
+
+	/* update committed lsn */
+	log = bp->l_log;
+	log->clsn = (bp->l_pn << L2LOGPSIZE) + bp->l_ceor;
+
+	if (bp->l_flag & lbmDIRECT) {
+		LCACHE_WAKEUP(&bp->l_ioevent);
+		LCACHE_UNLOCK(flags);
+		return;
+	}
+
+	tail = log->wqueue;
+
+	/* single element queue */
+	if (bp == tail) {
+		/* remove head buffer of full-page pageout
+		 * from log device write queue
+		 */
+		if (bp->l_flag & lbmRELEASE) {
+			log->wqueue = NULL;
+			bp->l_wqnext = NULL;
+		}
+	}
+	/* multi element queue */
+	else {
+		/* remove head buffer of full-page pageout
+		 * from log device write queue
+		 */
+		if (bp->l_flag & lbmRELEASE) {
+			nextbp = tail->l_wqnext = bp->l_wqnext;
+			bp->l_wqnext = NULL;
+
+			/*
+			 * redrive pageout of next page at head of write queue:
+			 * redrive next page without any bound tblk
+			 * (i.e., page w/o any COMMIT records), or
+			 * first page of new group commit which has been
+			 * queued after current page (subsequent pageout
+			 * is performed synchronously, except page without
+			 * any COMMITs) by lmGroupCommit() as indicated
+			 * by lbmWRITE flag;
+			 */
+			if (nextbp->l_flag & lbmWRITE) {
+				/*
+				 * We can't do the I/O at interrupt time.
+				 * The jfsIO thread can do it
+				 */
+				lbmRedrive(nextbp);
+			}
+		}
+	}
+
+	/*
+	 *      synchronous pageout:
+	 *
+	 * buffer has not necessarily been removed from write queue
+	 * (e.g., synchronous write of partial-page with COMMIT):
+	 * leave buffer for i/o initiator to dispose
+	 */
+	if (bp->l_flag & lbmSYNC) {
+		LCACHE_UNLOCK(flags);	/* unlock+enable */
+
+		/* wakeup I/O initiator */
+		LCACHE_WAKEUP(&bp->l_ioevent);
+	}
+
+	/*
+	 *      Group Commit pageout:
+	 */
+	else if (bp->l_flag & lbmGC) {
+		LCACHE_UNLOCK(flags);
+		lmPostGC(bp);
+	}
+
+	/*
+	 *      asynchronous pageout:
+	 *
+	 * buffer must have been removed from write queue:
+	 * insert buffer at head of freelist where it can be recycled
+	 */
+	else {
+		assert(bp->l_flag & lbmRELEASE);
+		assert(bp->l_flag & lbmFREE);
+		lbmfree(bp);
+
+		LCACHE_UNLOCK(flags);	/* unlock+enable */
+	}
+	return;
+}
+
+int jfsIOWait(void *arg)
+{
+	lbuf_t *bp;
+
+	jFYI(1, ("jfsIOWait is here!\n"));
+
+	lock_kernel();
+
+	daemonize();
+	current->tty = NULL;
+	strcpy(current->comm, "jfsIO");
+
+	unlock_kernel();
+
+	jfsIOtask = current;
+
+	spin_lock_irq(&current->sigmask_lock);
+	siginitsetinv(&current->blocked,
+		      sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP)
+		      | sigmask(SIGCONT));
+	spin_unlock_irq(&current->sigmask_lock);
+
+	complete(&jfsIOwait);
+
+	do {
+		spin_lock_irq(&log_redrive_lock);
+		while ((bp = log_redrive_list)) {
+			log_redrive_list = bp->l_redrive_next;
+			bp->l_redrive_next = NULL;
+			spin_unlock_irq(&log_redrive_lock);
+			lbmStartIO(bp);
+			spin_lock_irq(&log_redrive_lock);
+		}
+		spin_unlock_irq(&log_redrive_lock);
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule();
+	} while (!jfs_thread_stopped());
+
+	jFYI(1,("jfsIOWait being killed!\n"));
+	complete(&jfsIOwait);
+	return 0;
+}
+
+
+#ifdef _STILL_TO_PORT
+/*
+ *	lbmDirectIODone()
+ *
+ * iodone() for lbmDirectWrite() to bypass write queue;
+ * executed at INTIODONE level;
+ */
+static void lbmDirectIODone(iobuf_t * iobp)
+{
+	lbuf_t *bp;
+	unsigned long flags;
+
+	/*
+	 * get back jfs buffer bound to the io buffer
+	 */
+	bp = (lbuf_t *) iobp->b_jfsbp;
+	jEVENT(0,
+	       ("lbmDirectIODone: bp:0x%p flag:0x%x\n", bp, bp->l_flag));
+
+	LCACHE_LOCK(flags);		/* disable+lock */
+
+	bp->l_flag |= lbmDONE;
+
+	if (iobp->b_flags & B_ERROR) {
+		bp->l_flag |= lbmERROR;
+#ifdef _JFS_OS2
+		SysLogError();
+#endif
+	}
+
+	/*
+	 *      pageout completion
+	 */
+	bp->l_flag &= ~lbmWRITE;
+
+	/*
+	 *      synchronous pageout:
+	 */
+	if (bp->l_flag & lbmSYNC) {
+		LCACHE_UNLOCK(flags);	/* unlock+enable */
+
+		/* wakeup I/O initiator */
+		LCACHE_WAKEUP(&bp->l_ioevent);
+	}
+	/*
+	 *      asynchronous pageout:
+	 */
+	else {
+		assert(bp->l_flag & lbmRELEASE);
+		assert(bp->l_flag & lbmFREE);
+		lbmfree(bp);
+
+		LCACHE_UNLOCK(flags);	/* unlock+enable */
+	}
+}
+#endif				/* _STILL_TO_PORT */
+
+#ifdef _STILL_TO_PORT
+/*
+ * NAME:	lmLogFormat()/jfs_logform()
+ *
+ * FUNCTION:	format file system log (ref. jfs_logform()).
+ *
+ * PARAMETERS:
+ *	log	- log inode (with common mount inode base);
+ *	logAddress - start address of log space in FS block;
+ *	logSize	- length of log space in FS block;
+ *
+ * RETURN:	0 -	success
+ *		-1 -	i/o error
+ */
+int lmLogFormat(inode_t * ipmnt, s64 logAddress, int logSize)
+{
+	int rc = 0;
+	cbuf_t *bp;
+	logsuper_t *logsuper;
+	logpage_t *lp;
+	int lspn;		/* log sequence page number */
+	struct lrd *lrd_ptr;
+	int npbperpage, npages;
+
+	jFYI(0, ("lmLogFormat: logAddress:%Ld logSize:%d\n",
+		 logAddress, logSize));
+
+	/* allocate a JFS buffer */
+	bp = rawAllocate();
+
+	/* map the logical block address to physical block address */
+	bp->cm_blkno = logAddress << ipmnt->i_l2bfactor;
+
+	npbperpage = LOGPSIZE >> ipmnt->i_l2pbsize;
+	npages = logSize / (LOGPSIZE >> ipmnt->i_l2bsize);
+
+	/*
+	 *      log space:
+	 *
+	 * page 0 - reserved;
+	 * page 1 - log superblock;
+	 * page 2 - log data page: A SYNC log record is written
+	 *          into this page at logform time;
+	 * pages 3-N - log data page: set to empty log data pages;
+	 */
+	/*
+	 *      init log superblock: log page 1
+	 */
+	logsuper = (logsuper_t *) bp->cm_cdata;
+
+	logsuper->magic = cpu_to_le32(LOGMAGIC);
+	logsuper->version = cpu_to_le32(LOGVERSION);
+	logsuper->state = cpu_to_le32(LOGREDONE);
+	logsuper->flag = cpu_to_le32(ipmnt->i_mntflag);	/* ? */
+	logsuper->size = cpu_to_le32(npages);
+	logsuper->bsize = cpu_to_le32(ipmnt->i_bsize);
+	logsuper->l2bsize = cpu_to_le32(ipmnt->i_l2bsize);
+	logsuper->end =
+	    cpu_to_le32(2 * LOGPSIZE + LOGPHDRSIZE + LOGRDSIZE);
+
+	bp->cm_blkno += npbperpage;
+	rawWrite(ipmnt, bp, 0);
+
+	/*
+	 *      init pages 2 to npages-1 as log data pages:
+	 *
+	 * log page sequence number (lpsn) initialization:
+	 *
+	 * pn:   0     1     2     3                 n-1
+	 *       +-----+-----+=====+=====+===.....===+=====+
+	 * lspn:             N-1   0     1           N-2
+	 *                   <--- N page circular file ---->
+	 *
+	 * the N (= npages-2) data pages of the log is maintained as
+	 * a circular file for the log records;
+	 * lpsn grows by 1 monotonically as each log page is written
+	 * to the circular file of the log;
+	 * Since the AIX DUMMY log record is dropped for this XJFS,
+	 * and setLogpage() will not reset the page number even if
+	 * the eor is equal to LOGPHDRSIZE. In order for binary search
+	 * still work in find log end process, we have to simulate the
+	 * log wrap situation at the log format time.
+	 * The 1st log page written will have the highest lpsn. Then
+	 * the succeeding log pages will have ascending order of
+	 * the lspn starting from 0, ... (N-2)
+	 */
+	lp = (logpage_t *) bp->cm_cdata;
+
+	/*
+	 * initialize 1st log page to be written: lpsn = N - 1,
+	 * write a SYNCPT log record is written to this page
+	 */
+	lp->h.page = lp->t.page = cpu_to_le32(npages - 3);
+	lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE + LOGRDSIZE);
+
+	lrd_ptr = (struct lrd *) &lp->data;
+	lrd_ptr->logtid = 0;
+	lrd_ptr->backchain = 0;
+	lrd_ptr->type = cpu_to_le16(LOG_SYNCPT);
+	lrd_ptr->length = 0;
+	lrd_ptr->log.syncpt.sync = 0;
+
+	bp->cm_blkno += npbperpage;
+	rawWrite(ipmnt, bp, 0);
+
+	/*
+	 *      initialize succeeding log pages: lpsn = 0, 1, ..., (N-2)
+	 */
+	for (lspn = 0; lspn < npages - 3; lspn++) {
+		lp->h.page = lp->t.page = cpu_to_le32(lspn);
+		lp->h.eor = lp->t.eor = cpu_to_le16(LOGPHDRSIZE);
+
+		bp->cm_blkno += npbperpage;
+		rawWrite(ipmnt, bp, 0);
+	}
+
+	/*
+	 *      finalize log
+	 */
+	/* release the buffer */
+	rawRelease(bp);
+
+	return rc;
+}
+#endif				/* _STILL_TO_PORT */
+
+
+#ifdef CONFIG_JFS_STATISTICS
+int jfs_lmstats_read(char *buffer, char **start, off_t offset, int length,
+		      int *eof, void *data)
+{
+	int len = 0;
+	off_t begin;
+
+	len += sprintf(buffer,
+		       "JFS Logmgr stats\n"
+		       "================\n"
+		       "commits = %d\n"
+		       "writes submitted = %d\n"
+		       "writes completed = %d\n",
+		       lmStat.commit,
+		       lmStat.submitted,
+		       lmStat.pagedone);
+
+	begin = offset;
+	*start = buffer + begin;
+	len -= begin;
+
+	if (len > length)
+		len = length;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+#endif /* CONFIG_JFS_STATISTICS */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_logmgr.h linux-2.5.6-pre2/fs/jfs/jfs_logmgr.h
--- linux-2.5.6-pre1/fs/jfs/jfs_logmgr.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_logmgr.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,499 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef	_H_JFS_LOGMGR
+#define _H_JFS_LOGMGR
+
+
+#include "jfs_filsys.h"
+#include "jfs_lock.h"
+
+/*
+ *	log manager configuration parameters
+ */
+
+/* log page size */
+#define	LOGPSIZE	4096
+#define	L2LOGPSIZE	12
+
+#define LOGPAGES	16	/* Log pages per mounted file system */
+
+/*
+ *	log logical volume
+ *
+ * a log is used to make the commit operation on journalled 
+ * files within the same logical volume group atomic.
+ * a log is implemented with a logical volume.
+ * there is one log per logical volume group. 
+ *
+ * block 0 of the log logical volume is not used (ipl etc).
+ * block 1 contains a log "superblock" and is used by logFormat(),
+ * lmLogInit(), lmLogShutdown(), and logRedo() to record status 
+ * of the log but is not otherwise used during normal processing. 
+ * blocks 2 - (N-1) are used to contain log records.
+ *
+ * when a volume group is varied-on-line, logRedo() must have 
+ * been executed before the file systems (logical volumes) in 
+ * the volume group can be mounted.
+ */
+/*
+ *	log superblock (block 1 of logical volume)
+ */
+#define	LOGSUPER_B	1
+#define	LOGSTART_B	2
+
+#define	LOGMAGIC	0x87654321
+#define	LOGVERSION	1
+
+typedef struct {
+	u32 magic;		/* 4: log lv identifier */
+	s32 version;		/* 4: version number */
+	s32 serial;		/* 4: log open/mount counter */
+	s32 size;		/* 4: size in number of LOGPSIZE blocks */
+	s32 bsize;		/* 4: logical block size in byte */
+	s32 l2bsize;		/* 4: log2 of bsize */
+
+	u32 flag;		/* 4: option */
+	u32 state;		/* 4: state - see below */
+
+	s32 end;		/* 4: addr of last log record set by logredo */
+	u32 active[8];		/* 32: active file systems bit vector */
+	s32 rsrvd[LOGPSIZE / 4 - 17];
+} logsuper_t;
+
+/* log flag: commit option (see jfs_filsys.h) */
+
+/* log state */
+#define	LOGMOUNT	0	/* log mounted by lmLogInit() */
+#define LOGREDONE	1	/* log shutdown by lmLogShutdown().
+				 * log redo completed by logredo().
+				 */
+#define LOGWRAP		2	/* log wrapped */
+#define LOGREADERR	3	/* log read error detected in logredo() */
+
+
+/*
+ *	log logical page
+ *
+ * (this comment should be rewritten !)
+ * the header and trailer structures (h,t) will normally have 
+ * the same page and eor value.
+ * An exception to this occurs when a complete page write is not 
+ * accomplished on a power failure. Since the hardware may "split write"
+ * sectors in the page, any out of order sequence may occur during powerfail 
+ * and needs to be recognized during log replay.  The xor value is
+ * an "exclusive or" of all log words in the page up to eor.  This
+ * 32 bit eor is stored with the top 16 bits in the header and the
+ * bottom 16 bits in the trailer.  logredo can easily recognize pages
+ * that were not completed by reconstructing this eor and checking 
+ * the log page.
+ *
+ * Previous versions of the operating system did not allow split 
+ * writes and detected partially written records in logredo by 
+ * ordering the updates to the header, trailer, and the move of data 
+ * into the logdata area.  The order: (1) data is moved (2) header 
+ * is updated (3) trailer is updated.  In logredo, when the header 
+ * differed from the trailer, the header and trailer were reconciled 
+ * as follows: if h.page != t.page they were set to the smaller of 
+ * the two and h.eor and t.eor set to 8 (i.e. empty page). if (only) 
+ * h.eor != t.eor they were set to the smaller of their two values.
+ */
+typedef struct {
+	struct {		/* header */
+		s32 page;	/* 4: log sequence page number */
+		s16 rsrvd;	/* 2: */
+		s16 eor;	/* 2: end-of-log offset of lasrt record write */
+	} h;
+
+	s32 data[LOGPSIZE / 4 - 4];	/* log record area */
+
+	struct {		/* trailer */
+		s32 page;	/* 4: normally the same as h.page */
+		s16 rsrvd;	/* 2: */
+		s16 eor;	/* 2: normally the same as h.eor */
+	} t;
+} logpage_t;
+
+#define LOGPHDRSIZE	8	/* log page header size */
+#define LOGPTLRSIZE	8	/* log page trailer size */
+
+
+/*
+ *	log record
+ *
+ * (this comment should be rewritten !)
+ * jfs uses only "after" log records (only a single writer is allowed
+ * in a  page, pages are written to temporary paging space if
+ * if they must be written to disk before commit, and i/o is
+ * scheduled for modified pages to their home location after
+ * the log records containing the after values and the commit 
+ * record is written to the log on disk, undo discards the copy
+ * in main-memory.)
+ *
+ * a log record consists of a data area of variable length followed by 
+ * a descriptor of fixed size LOGRDSIZE bytes.
+ * the  data area is rounded up to an integral number of 4-bytes and 
+ * must be no longer than LOGPSIZE.
+ * the descriptor is of size of multiple of 4-bytes and aligned on a 
+ * 4-byte boundary. 
+ * records are packed one after the other in the data area of log pages.
+ * (sometimes a DUMMY record is inserted so that at least one record ends 
+ * on every page or the longest record is placed on at most two pages).
+ * the field eor in page header/trailer points to the byte following 
+ * the last record on a page.
+ */
+
+/* log record types */
+#define LOG_COMMIT		0x8000
+#define LOG_SYNCPT		0x4000
+#define LOG_MOUNT		0x2000
+#define LOG_REDOPAGE		0x0800
+#define LOG_NOREDOPAGE		0x0080
+#define LOG_NOREDOINOEXT	0x0040
+#define LOG_UPDATEMAP		0x0008
+#define LOG_NOREDOFILE		0x0001
+
+/* REDOPAGE/NOREDOPAGE log record data type */
+#define	LOG_INODE		0x0001
+#define	LOG_XTREE		0x0002
+#define	LOG_DTREE		0x0004
+#define	LOG_BTROOT		0x0010
+#define	LOG_EA			0x0020
+#define	LOG_ACL			0x0040
+#define	LOG_DATA		0x0080
+#define	LOG_NEW			0x0100
+#define	LOG_EXTEND		0x0200
+#define LOG_RELOCATE		0x0400
+#define LOG_DIR_XTREE		0x0800	/* Xtree is in directory inode */
+
+/* UPDATEMAP log record descriptor type */
+#define	LOG_ALLOCXADLIST	0x0080
+#define	LOG_ALLOCPXDLIST	0x0040
+#define	LOG_ALLOCXAD		0x0020
+#define	LOG_ALLOCPXD		0x0010
+#define	LOG_FREEXADLIST		0x0008
+#define	LOG_FREEPXDLIST		0x0004
+#define	LOG_FREEXAD		0x0002
+#define	LOG_FREEPXD		0x0001
+
+
+typedef struct lrd {
+	/*
+	 * type independent area
+	 */
+	s32 logtid;		/* 4: log transaction identifier */
+	s32 backchain;		/* 4: ptr to prev record of same transaction */
+	u16 type;		/* 2: record type */
+	s16 length;		/* 2: length of data in record (in byte) */
+	s32 aggregate;		/* 4: file system lv/aggregate */
+	/* (16) */
+
+	/*
+	 * type dependent area (20)
+	 */
+	union {
+
+		/*
+		 *      COMMIT: commit
+		 *
+		 * transaction commit: no type-dependent information;
+		 */
+
+		/*
+		 *      REDOPAGE: after-image
+		 *
+		 * apply after-image;
+		 *
+		 * N.B. REDOPAGE, NOREDOPAGE, and UPDATEMAP must be same format;
+		 */
+		struct {
+			u32 fileset;	/* 4: fileset number */
+			u32 inode;	/* 4: inode number */
+			u16 type;	/* 2: REDOPAGE record type */
+			s16 l2linesize;	/* 2: log2 of line size */
+			pxd_t pxd;	/* 8: on-disk page pxd */
+		} redopage;	/* (20) */
+
+		/*
+		 *      NOREDOPAGE: the page is freed
+		 *
+		 * do not apply after-image records which precede this record
+		 * in the log with the same page block number to this page.
+		 *
+		 * N.B. REDOPAGE, NOREDOPAGE, and UPDATEMAP must be same format;
+		 */
+		struct {
+			s32 fileset;	/* 4: fileset number */
+			u32 inode;	/* 4: inode number */
+			u16 type;	/* 2: NOREDOPAGE record type */
+			s16 rsrvd;	/* 2: reserved */
+			pxd_t pxd;	/* 8: on-disk page pxd */
+		} noredopage;	/* (20) */
+
+		/*
+		 *      UPDATEMAP: update block allocation map
+		 *
+		 * either in-line PXD,
+		 * or     out-of-line  XADLIST;
+		 *
+		 * N.B. REDOPAGE, NOREDOPAGE, and UPDATEMAP must be same format;
+		 */
+		struct {
+			u32 fileset;	/* 4: fileset number */
+			u32 inode;	/* 4: inode number */
+			u16 type;	/* 2: UPDATEMAP record type */
+			s16 nxd;	/* 2: number of extents */
+			pxd_t pxd;	/* 8: pxd */
+		} updatemap;	/* (20) */
+
+		/*
+		 *      NOREDOINOEXT: the inode extent is freed
+		 *
+		 * do not apply after-image records which precede this 
+		 * record in the log with the any of the 4 page block 
+		 * numbers in this inode extent. 
+		 * 
+		 * NOTE: The fileset and pxd fields MUST remain in 
+		 *       the same fields in the REDOPAGE record format.
+		 *
+		 */
+		struct {
+			s32 fileset;	/* 4: fileset number */
+			s32 iagnum;	/* 4: IAG number     */
+			s32 inoext_idx;	/* 4: inode extent index */
+			pxd_t pxd;	/* 8: on-disk page pxd */
+		} noredoinoext;	/* (20) */
+
+		/*
+		 *      SYNCPT: log sync point
+		 *
+		 * replay log upto syncpt address specified;
+		 */
+		struct {
+			s32 sync;	/* 4: syncpt address (0 = here) */
+		} syncpt;
+
+		/*
+		 *      MOUNT: file system mount
+		 *
+		 * file system mount: no type-dependent information;
+		 */
+
+		/*
+		 *      ? FREEXTENT: free specified extent(s)
+		 *
+		 * free specified extent(s) from block allocation map
+		 * N.B.: nextents should be length of data/sizeof(xad_t)
+		 */
+		struct {
+			s32 type;	/* 4: FREEXTENT record type */
+			s32 nextent;	/* 4: number of extents */
+
+			/* data: PXD or XAD list */
+		} freextent;
+
+		/*
+		 *      ? NOREDOFILE: this file is freed
+		 *
+		 * do not apply records which precede this record in the log
+		 * with the same inode number.
+		 *
+		 * NOREDILE must be the first to be written at commit
+		 * (last to be read in logredo()) - it prevents
+		 * replay of preceding updates of all preceding generations
+		 * of the inumber esp. the on-disk inode itself, 
+		 * but does NOT prevent
+		 * replay of the 
+		 */
+		struct {
+			s32 fileset;	/* 4: fileset number */
+			u32 inode;	/* 4: inode number */
+		} noredofile;
+
+		/*
+		 *      ? NEWPAGE: 
+		 *
+		 * metadata type dependent
+		 */
+		struct {
+			s32 fileset;	/* 4: fileset number */
+			u32 inode;	/* 4: inode number */
+			s32 type;	/* 4: NEWPAGE record type */
+			pxd_t pxd;	/* 8: on-disk page pxd */
+		} newpage;
+
+		/*
+		 *      ? DUMMY: filler
+		 *
+		 * no type-dependent information
+		 */
+	} log;
+} lrd_t;			/* (36) */
+
+#define	LOGRDSIZE	(sizeof(struct lrd))
+
+/*
+ *	line vector descriptor
+ */
+typedef struct {
+	s16 offset;
+	s16 length;
+} lvd_t;
+
+
+/*
+ *	log logical volume
+ */
+typedef struct jfs_log {
+
+	struct super_block *sb;	/* 4: This is used to sync metadata
+				 *    before writing syncpt.  Will
+				 *    need to be a list if we share
+				 *    the log between fs's
+				 */
+	kdev_t dev;		/* 4: log lv number */
+	struct file *devfp;	/* 4: log device file */
+	s32 serial;		/* 4: log mount serial number */
+
+	s64 base;		/* @8: log extent address (inline log ) */
+	int size;		/* 4: log size in log page (in page) */
+	int l2bsize;		/* 4: log2 of bsize */
+
+	uint flag;		/* 4: flag */
+	uint state;		/* 4: state */
+
+	struct lbuf *lbuf_free;	/* 4: free lbufs */
+	wait_queue_head_t free_wait;	/* 4: */
+
+	/* log write */
+	int logtid;		/* 4: log tid */
+	int page;		/* 4: page number of eol page */
+	int eor;		/* 4: eor of last record in eol page */
+	struct lbuf *bp;	/* 4: current log page buffer */
+
+	struct semaphore loglock;	/* 4: log write serialization lock */
+
+	/* syncpt */
+	int nextsync;		/* 4: bytes to write before next syncpt */
+	int active;		/* 4: */
+	int syncbarrier;	/* 4: */
+	wait_queue_head_t syncwait;	/* 4: */
+
+	/* commit */
+	uint cflag;		/* 4: */
+	struct {		/* 8: FIFO commit queue header */
+		struct tblock *head;
+		struct tblock *tail;
+	} cqueue;
+	int gcrtc;		/* 4: GC_READY transaction count */
+	struct tblock *gclrt;	/* 4: latest GC_READY transaction */
+	spinlock_t gclock;	/* 4: group commit lock */
+	int logsize;		/* 4: log data area size in byte */
+	int lsn;		/* 4: end-of-log */
+	int clsn;		/* 4: clsn */
+	int syncpt;		/* 4: addr of last syncpt record */
+	int sync;		/* 4: addr from last logsync() */
+	struct list_head synclist;	/* 8: logsynclist anchor */
+	spinlock_t synclock;	/* 4: synclist lock */
+	struct lbuf *wqueue;	/* 4: log pageout queue */
+	int count;		/* 4: count */
+} log_t;
+
+/*
+ * group commit flag
+ */
+/* log_t */
+#define logGC_PAGEOUT	0x00000001
+
+/* tblock_t/lbuf_t */
+#define tblkGC_QUEUE		0x0001
+#define tblkGC_READY		0x0002
+#define tblkGC_COMMIT		0x0004
+#define tblkGC_COMMITTED	0x0008
+#define tblkGC_EOP		0x0010
+#define tblkGC_FREE		0x0020
+#define tblkGC_LEADER		0x0040
+#define tblkGC_ERROR		0x0080
+#define tblkGC_LAZY		0x0100	// D230860
+#define tblkGC_UNLOCKED		0x0200	// D230860
+
+/*
+ *		log cache buffer header
+ */
+typedef struct lbuf {
+	log_t *l_log;		/* 4: log associated with buffer */
+
+	/*
+	 * data buffer base area
+	 */
+	uint l_flag;		/* 4: pageout control flags */
+
+	struct lbuf *l_wqnext;	/* 4: write queue link */
+	struct lbuf *l_freelist;	/* 4: freelistlink */
+
+	int l_pn;		/* 4: log page number */
+	int l_eor;		/* 4: log record eor */
+	int l_ceor;		/* 4: committed log record eor */
+
+	s64 l_blkno;		/* 8: log page block number */
+	caddr_t l_ldata;	/* 4: data page */
+
+	wait_queue_head_t l_ioevent;	/* 4: i/o done event */
+	struct page *l_page;	/* The page itself */
+} lbuf_t;
+
+/* Reuse l_freelist for redrive list */
+#define l_redrive_next l_freelist
+
+/*
+ *	logsynclist block
+ *
+ * common logsyncblk prefix for jbuf_t and tblock_t
+ */
+typedef struct logsyncblk {
+	u16 xflag;		/* flags */
+	u16 flag;		/* only meaninful in tblock_t */
+	lid_t lid;		/* lock id */
+	s32 lsn;		/* log sequence number */
+	struct list_head synclist;	/* log sync list link */
+} logsyncblk_t;
+
+/*
+ *	logsynclist serialization (per log)
+ */
+
+#define LOGSYNC_LOCK_INIT(log) spin_lock_init(&(log)->synclock)
+#define LOGSYNC_LOCK(log) spin_lock(&(log)->synclock)
+#define LOGSYNC_UNLOCK(log) spin_unlock(&(log)->synclock)
+
+/* compute the difference in bytes of lsn from sync point */
+#define logdiff(diff, lsn, log)\
+{\
+	diff = (lsn) - (log)->syncpt;\
+	if (diff < 0)\
+		diff += (log)->logsize;\
+}
+
+extern int lmLogOpen(struct super_block *sb, log_t ** log);
+extern int lmLogClose(struct super_block *sb, log_t * log);
+extern int lmLogSync(log_t * log, int nosyncwait);
+extern int lmLogQuiesce(log_t * log);
+extern int lmLogResume(log_t * log, struct super_block *sb);
+extern int lmLogFormat(struct super_block *sb, s64 logAddress, int logSize);
+
+#endif				/* _H_JFS_LOGMGR */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_metapage.c linux-2.5.6-pre2/fs/jfs/jfs_metapage.c
--- linux-2.5.6-pre1/fs/jfs/jfs_metapage.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_metapage.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,686 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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
+ *
+ * Module: jfs/jfs_metapage.c
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_metapage.h"
+#include "jfs_txnmgr.h"
+#include "jfs_debug.h"
+
+extern struct task_struct *jfsCommitTask;
+static unsigned int metapages = 1024;	/* ??? Need a better number */
+static unsigned int free_metapages;
+static metapage_t *metapage_buf;
+static unsigned long meta_order;
+static metapage_t *meta_free_list = NULL;
+static spinlock_t meta_lock = SPIN_LOCK_UNLOCKED;
+static wait_queue_head_t meta_wait;
+
+#ifdef CONFIG_JFS_STATISTICS
+struct {
+	uint	pagealloc;	/* # of page allocations */
+	uint	pagefree;	/* # of page frees */
+	uint	lockwait;	/* # of sleeping lock_metapage() calls */
+	uint	allocwait;	/* # of sleeping alloc_metapage() calls */
+} mpStat;
+#endif
+
+
+#define HASH_BITS 10		/* This makes hash_table 1 4K page */
+#define HASH_SIZE (1 << HASH_BITS)
+static metapage_t **hash_table = NULL;
+static unsigned long hash_order;
+
+
+static inline int metapage_locked(struct metapage *mp)
+{
+	return test_bit(META_locked, &mp->flag);
+}
+
+static inline int trylock_metapage(struct metapage *mp)
+{
+	return test_and_set_bit(META_locked, &mp->flag);
+}
+
+static inline void unlock_metapage(struct metapage *mp)
+{
+	clear_bit(META_locked, &mp->flag);
+	wake_up(&mp->wait);
+}
+
+static void __lock_metapage(struct metapage *mp)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	INCREMENT(mpStat.lockwait);
+
+	add_wait_queue_exclusive(&mp->wait, &wait);
+	do {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		if (metapage_locked(mp)) {
+			spin_unlock(&meta_lock);
+			schedule();
+			spin_lock(&meta_lock);
+		}
+	} while (trylock_metapage(mp));
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&mp->wait, &wait);
+}
+
+/* needs meta_lock */
+static inline void lock_metapage(struct metapage *mp)
+{
+	if (trylock_metapage(mp))
+		__lock_metapage(mp);
+}
+
+/* We're currently re-evaluating the method we use to write metadata
+ * pages.  Currently, we have to make sure there no dirty buffer_heads
+ * hanging around after we free the metadata page, since the same
+ * physical disk blocks may be used in a different address space and we
+ * can't write old data over the good data.
+ *
+ * The best way to do this now is with block_invalidate_page.  However,
+ * this is only available in the newer kernels and is not exported
+ * to modules.  block_flushpage is the next best, but it too is not exported
+ * to modules.
+ *
+ * In a module, about the best we have is generic_buffer_fdatasync.  This
+ * synchronously writes any dirty buffers.  This is not optimal, but it will
+ * keep old dirty buffers from overwriting newer data.
+ */
+static inline void invalidate_page(metapage_t *mp)
+{
+#ifdef MODULE
+	generic_buffer_fdatasync(mp->mapping->host, mp->index, mp->index + 1);
+#else
+	lock_page(mp->page);
+	block_flushpage(mp->page, 0);
+	UnlockPage(mp->page);
+#endif
+}
+
+int __init metapage_init(void)
+{
+	int i;
+	metapage_t *last = NULL;
+	metapage_t *mp;
+
+	/*
+	 * Initialize wait queue
+	 */
+	init_waitqueue_head(&meta_wait);
+
+	/*
+	 * Allocate the metapage structures
+	 */
+	for (meta_order = 0;
+	     ((PAGE_SIZE << meta_order) / sizeof(metapage_t)) < metapages;
+	     meta_order++);
+	metapages = (PAGE_SIZE << meta_order) / sizeof(metapage_t);
+
+	jFYI(1, ("metapage_init: metapage size = %Zd, metapages = %d\n",
+		 sizeof(metapage_t), metapages));
+
+	metapage_buf =
+	    (metapage_t *) __get_free_pages(GFP_KERNEL, meta_order);
+	assert(metapage_buf);
+	memset(metapage_buf, 0, PAGE_SIZE << meta_order);
+
+	mp = metapage_buf;
+	for (i = 0; i < metapages; i++, mp++) {
+		mp->flag = 0;
+		set_bit(META_free, &mp->flag);
+		init_waitqueue_head(&mp->wait);
+		mp->hash_next = last;
+		last = mp;
+	}
+	meta_free_list = last;
+	free_metapages = metapages;
+
+	/*
+	 * Now the hash list
+	 */
+	for (hash_order = 0;
+	     ((PAGE_SIZE << hash_order) / sizeof(void *)) < HASH_SIZE;
+	     hash_order++);
+	hash_table =
+	    (metapage_t **) __get_free_pages(GFP_KERNEL, hash_order);
+	assert(hash_table);
+	memset(hash_table, 0, PAGE_SIZE << hash_order);
+
+	return 0;
+}
+
+void metapage_exit(void)
+{
+	free_pages((unsigned long) metapage_buf, meta_order);
+	free_pages((unsigned long) hash_table, hash_order);
+	metapage_buf = 0;	/* This is a signal to the jfsIOwait thread */
+}
+
+/*
+ * Get metapage structure from freelist
+ * 
+ * Caller holds meta_lock
+ */
+static metapage_t *alloc_metapage(int *dropped_lock)
+{
+	metapage_t *new;
+
+	*dropped_lock = FALSE;
+
+	/*
+	 * Reserve two metapages for the lazy commit thread.  Otherwise
+	 * we may deadlock with holders of metapages waiting for tlocks
+	 * that lazy thread should be freeing.
+	 */
+	if ((free_metapages < 3) && (current != jfsCommitTask)) {
+		INCREMENT(mpStat.allocwait);
+		*dropped_lock = TRUE;
+		__SLEEP_COND(meta_wait, (free_metapages > 2),
+			     spin_lock(&meta_lock), spin_unlock(&meta_lock));
+	}
+
+	assert(meta_free_list);
+
+	new = meta_free_list;
+	meta_free_list = new->hash_next;
+	free_metapages--;
+
+	return new;
+}
+
+/*
+ * Put metapage on freelist (holding meta_lock)
+ */
+static inline void __free_metapage(metapage_t * mp)
+{
+	mp->flag = 0;
+	set_bit(META_free, &mp->flag);
+	mp->hash_next = meta_free_list;
+	meta_free_list = mp;
+	free_metapages++;
+	wake_up(&meta_wait);
+}
+
+/*
+ * Put metapage on freelist (not holding meta_lock)
+ */
+static inline void free_metapage(metapage_t * mp)
+{
+	spin_lock(&meta_lock);
+	__free_metapage(mp);
+	spin_unlock(&meta_lock);
+}
+
+/*
+ * Basically same hash as in pagemap.h, but using our hash table
+ */
+static metapage_t **meta_hash(struct address_space *mapping,
+			      unsigned long index)
+{
+#define i (((unsigned long)mapping)/ \
+	   (sizeof(struct inode) & ~(sizeof(struct inode) -1 )))
+#define s(x) ((x) + ((x) >> HASH_BITS))
+	return hash_table + (s(i + index) & (HASH_SIZE - 1));
+#undef i
+#undef s
+}
+
+static metapage_t *search_hash(metapage_t ** hash_ptr,
+			       struct address_space *mapping,
+			       unsigned long index)
+{
+	metapage_t *ptr;
+
+	for (ptr = *hash_ptr; ptr; ptr = ptr->hash_next) {
+		if ((ptr->mapping == mapping) && (ptr->index == index))
+			return ptr;
+	}
+
+	return NULL;
+}
+
+static void add_to_hash(metapage_t * mp, metapage_t ** hash_ptr)
+{
+	if (*hash_ptr)
+		(*hash_ptr)->hash_prev = mp;
+
+	mp->hash_prev = NULL;
+	mp->hash_next = *hash_ptr;
+	*hash_ptr = mp;
+	list_add(&mp->inode_list, &JFS_IP(mp->mapping->host)->mp_list);
+}
+
+static void remove_from_hash(metapage_t * mp, metapage_t ** hash_ptr)
+{
+	list_del(&mp->inode_list);
+
+	if (mp->hash_prev)
+		mp->hash_prev->hash_next = mp->hash_next;
+	else {
+		assert(*hash_ptr == mp);
+		*hash_ptr = mp->hash_next;
+	}
+
+	if (mp->hash_next)
+		mp->hash_next->hash_prev = mp->hash_prev;
+}
+
+/*
+ * Direct address space operations
+ */
+
+static int direct_get_block(struct inode *ip, sector_t lblock,
+			    struct buffer_head *bh_result, int create)
+{
+	if (create)
+		bh_result->b_state |= (1UL << BH_New);
+
+	map_bh(bh_result, ip->i_sb, lblock);
+
+	return 0;
+}
+
+static int direct_writepage(struct page *page)
+{
+	return block_write_full_page(page, direct_get_block);
+}
+
+static int direct_readpage(struct file *fp, struct page *page)
+{
+	return block_read_full_page(page, direct_get_block);
+}
+
+static int direct_prepare_write(struct file *file, struct page *page,
+				unsigned from, unsigned to)
+{
+	return block_prepare_write(page, from, to, direct_get_block);
+}
+
+static int direct_bmap(struct address_space *mapping, long block)
+{
+	return generic_block_bmap(mapping, block, direct_get_block);
+}
+
+struct address_space_operations direct_aops = {
+	readpage:	direct_readpage,
+	writepage:	direct_writepage,
+	sync_page:	block_sync_page,
+	prepare_write:	direct_prepare_write,
+	commit_write:	generic_commit_write,
+	bmap:		direct_bmap,
+};
+
+metapage_t *__get_metapage(struct inode *inode,
+			   unsigned long lblock, unsigned int size,
+			   int absolute, unsigned long new)
+{
+	int dropped_lock;
+	metapage_t **hash_ptr;
+	int l2BlocksPerPage;
+	int l2bsize;
+	struct address_space *mapping;
+	metapage_t *mp;
+	unsigned long page_index;
+	unsigned long page_offset;
+
+	jFYI(1, ("__get_metapage: inode = 0x%p, lblock = 0x%lx\n",
+		 inode, lblock));
+
+	if (absolute)
+		mapping = JFS_SBI(inode->i_sb)->direct_mapping;
+	else
+		mapping = inode->i_mapping;
+
+	spin_lock(&meta_lock);
+
+	hash_ptr = meta_hash(mapping, lblock);
+
+	mp = search_hash(hash_ptr, mapping, lblock);
+	if (mp) {
+	      page_found:
+		if (test_bit(META_discard, &mp->flag)) {
+			assert(new);	/* It's okay to reuse a discarded
+					 * if we expect it to be empty
+					 */
+			clear_bit(META_discard, &mp->flag);
+		}
+		mp->count++;
+		jFYI(1, ("__get_metapage: found 0x%p, in hash\n", mp));
+		assert(mp->logical_size == size);
+		lock_metapage(mp);
+		spin_unlock(&meta_lock);
+	} else {
+		l2bsize = inode->i_sb->s_blocksize_bits;
+		l2BlocksPerPage = PAGE_CACHE_SHIFT - l2bsize;
+		page_index = lblock >> l2BlocksPerPage;
+		page_offset = (lblock - (page_index << l2BlocksPerPage)) <<
+		    l2bsize;
+		if ((page_offset + size) > PAGE_SIZE) {
+			spin_unlock(&meta_lock);
+			jERROR(1, ("MetaData crosses page boundary!!\n"));
+			return NULL;
+		}
+
+		mp = alloc_metapage(&dropped_lock);
+		if (dropped_lock) {
+			/* alloc_metapage blocked, we need to search the hash
+			 * again.  (The goto is ugly, maybe we'll clean this
+			 * up in the future.)
+			 */
+			metapage_t *mp2;
+			mp2 = search_hash(hash_ptr, mapping, lblock);
+			if (mp2) {
+				__free_metapage(mp);
+				mp = mp2;
+				goto page_found;
+			}
+		}
+		mp->flag = 0;
+		lock_metapage(mp);
+		if (absolute)
+			set_bit(META_absolute, &mp->flag);
+		mp->xflag = COMMIT_PAGE;
+		mp->count = 1;
+		atomic_set(&mp->nohomeok,0);
+		mp->mapping = mapping;
+		mp->index = lblock;
+		mp->page = 0;
+		mp->logical_size = size;
+		add_to_hash(mp, hash_ptr);
+		spin_unlock(&meta_lock);
+
+		if (new) {
+			jFYI(1,
+			     ("__get_metapage: Calling grab_cache_page\n"));
+			mp->page = grab_cache_page(mapping, page_index);
+			if (!mp->page) {
+				jERROR(1, ("grab_cache_page failed!\n"));
+				spin_lock(&meta_lock);
+				remove_from_hash(mp, hash_ptr);
+				__free_metapage(mp);
+				spin_unlock(&meta_lock);
+				return NULL;
+			} else
+				INCREMENT(mpStat.pagealloc);
+		} else {
+			jFYI(1,
+			     ("__get_metapage: Calling read_cache_page\n"));
+			mp->page =
+			    read_cache_page(mapping, lblock,
+					    (filler_t *) mapping->a_ops->
+					    readpage, NULL);
+			if (IS_ERR(mp->page)) {
+				jERROR(1, ("read_cache_page failed!\n"));
+				spin_lock(&meta_lock);
+				remove_from_hash(mp, hash_ptr);
+				__free_metapage(mp);
+				spin_unlock(&meta_lock);
+				return NULL;
+			} else
+				INCREMENT(mpStat.pagealloc);
+			lock_page(mp->page);
+		}
+		mp->data = (void *) (kmap(mp->page) + page_offset);
+	}
+	jFYI(1, ("__get_metapage: returning = 0x%p\n", mp));
+	return mp;
+}
+
+void hold_metapage(metapage_t * mp, int force)
+{
+	spin_lock(&meta_lock);
+
+	mp->count++;
+
+	if (force) {
+		ASSERT (!(test_bit(META_forced, &mp->flag)));
+		if (trylock_metapage(mp))
+			set_bit(META_forced, &mp->flag);
+	} else
+		lock_metapage(mp);
+
+	spin_unlock(&meta_lock);
+}
+
+static void __write_metapage(metapage_t * mp)
+{
+	struct inode *ip = (struct inode *) mp->mapping->host;
+	unsigned long page_index;
+	unsigned long page_offset;
+	int rc;
+	int l2bsize = ip->i_sb->s_blocksize_bits;
+	int l2BlocksPerPage = PAGE_CACHE_SHIFT - l2bsize;
+
+	jFYI(1, ("__write_metapage: mp = 0x%p\n", mp));
+
+	if (test_bit(META_discard, &mp->flag)) {
+		/*
+		 * This metadata is no longer valid
+		 */
+		clear_bit(META_dirty, &mp->flag);
+		return;
+	}
+
+	page_index = mp->page->index;
+	page_offset =
+	    (mp->index - (page_index << l2BlocksPerPage)) << l2bsize;
+
+	rc = mp->mapping->a_ops->prepare_write(NULL, mp->page, page_offset,
+					       page_offset +
+					       mp->logical_size);
+	if (rc) {
+		jERROR(1, ("prepare_write return %d!\n", rc));
+		ClearPageUptodate(mp->page);
+		kunmap(mp->page);
+		clear_bit(META_dirty, &mp->flag);
+		return;
+	}
+	rc = mp->mapping->a_ops->commit_write(NULL, mp->page, page_offset,
+					      page_offset +
+					      mp->logical_size);
+	if (rc) {
+		jERROR(1, ("commit_write returned %d\n", rc));
+	}
+
+	clear_bit(META_dirty, &mp->flag);
+
+	jFYI(1, ("__write_metapage done\n"));
+}
+
+void release_metapage(metapage_t * mp)
+{
+	log_t *log;
+	struct inode *ip;
+
+	jFYI(1,
+	     ("release_metapage: mp = 0x%p, flag = 0x%lx\n", mp,
+	      mp->flag));
+
+	spin_lock(&meta_lock);
+	if (test_bit(META_forced, &mp->flag)) {
+		clear_bit(META_forced, &mp->flag);
+		mp->count--;
+		spin_unlock(&meta_lock);
+		return;
+	}
+
+	ip = (struct inode *) mp->mapping->host;
+
+	assert(mp->count);
+	if (--mp->count || atomic_read(&mp->nohomeok)) {
+		unlock_metapage(mp);
+		spin_unlock(&meta_lock);
+	} else {
+		remove_from_hash(mp, meta_hash(mp->mapping, mp->index));
+		spin_unlock(&meta_lock);
+
+		if (mp->page) {
+			kunmap(mp->page);
+			mp->data = 0;
+			if (test_bit(META_dirty, &mp->flag))
+				__write_metapage(mp);
+			UnlockPage(mp->page);
+			if (test_bit(META_sync, &mp->flag)) {
+				sync_metapage(mp);
+				clear_bit(META_sync, &mp->flag);
+			}
+
+			if (test_bit(META_discard, &mp->flag))
+				invalidate_page(mp);
+
+			page_cache_release(mp->page);
+			INCREMENT(mpStat.pagefree);
+		}
+
+		if (mp->lsn) {
+			/*
+			 * Remove metapage from logsynclist.
+			 */
+			log = mp->log;
+			LOGSYNC_LOCK(log);
+			mp->log = 0;
+			mp->lsn = 0;
+			mp->clsn = 0;
+			log->count--;
+			list_del(&mp->synclist);
+			LOGSYNC_UNLOCK(log);
+		}
+
+		free_metapage(mp);
+	}
+	jFYI(1, ("release_metapage: done\n"));
+}
+
+void invalidate_metapages(struct inode *ip, unsigned long addr,
+			 unsigned long len)
+{
+	metapage_t **hash_ptr;
+	unsigned long lblock;
+	int l2BlocksPerPage = PAGE_CACHE_SHIFT - ip->i_sb->s_blocksize_bits;
+	struct address_space *mapping = ip->i_mapping;
+	metapage_t *mp;
+#ifndef MODULE
+	struct page *page;
+#endif
+
+	/*
+	 * First, mark metapages to discard.  They will eventually be
+	 * released, but should not be written.
+	 */
+	for (lblock = addr; lblock < addr + len;
+	     lblock += 1 << l2BlocksPerPage) {
+		hash_ptr = meta_hash(mapping, lblock);
+		spin_lock(&meta_lock);
+		mp = search_hash(hash_ptr, mapping, lblock);
+		if (mp) {
+			set_bit(META_discard, &mp->flag);
+			spin_unlock(&meta_lock);
+			/*
+			 * If in the metapage cache, we've got the page locked
+			 */
+#ifdef MODULE
+			UnlockPage(mp->page);
+			generic_buffer_fdatasync(mp->mapping->host, mp->index,
+						 mp->index+1);
+			lock_page(mp->page);
+#else
+			block_flushpage(mp->page, 0);
+#endif
+		} else {
+			spin_unlock(&meta_lock);
+#ifdef MODULE
+			generic_buffer_fdatasync(ip, lblock << l2BlocksPerPage,
+					(lblock + 1) << l2BlocksPerPage);
+#else
+			page = find_lock_page(mapping,
+					      lblock >> l2BlocksPerPage);
+			if (page) {
+				block_flushpage(page, 0);
+				UnlockPage(page);
+			}
+#endif
+		}
+	}
+}
+
+void invalidate_inode_metapages(struct inode *inode)
+{
+	struct list_head *ptr;
+	metapage_t *mp;
+
+	spin_lock(&meta_lock);
+	list_for_each(ptr, &JFS_IP(inode)->mp_list) {
+		mp = list_entry(ptr, metapage_t, inode_list);
+		clear_bit(META_dirty, &mp->flag);
+		set_bit(META_discard, &mp->flag);
+		kunmap(mp->page);
+		UnlockPage(mp->page);
+		page_cache_release(mp->page);
+		INCREMENT(mpStat.pagefree);
+		mp->data = 0;
+		mp->page = 0;
+	}
+	spin_unlock(&meta_lock);
+	truncate_inode_pages(inode->i_mapping, 0);
+}
+
+#ifdef CONFIG_JFS_STATISTICS
+int jfs_mpstat_read(char *buffer, char **start, off_t offset, int length,
+		    int *eof, void *data)
+{
+	int len = 0;
+	off_t begin;
+
+	len += sprintf(buffer,
+		       "JFS Metapage statistics\n"
+		       "=======================\n"
+		       "metapages in use = %d\n"
+		       "page allocations = %d\n"
+		       "page frees = %d\n"
+		       "lock waits = %d\n"
+		       "allocation waits = %d\n",
+		       metapages - free_metapages,
+		       mpStat.pagealloc,
+		       mpStat.pagefree,
+		       mpStat.lockwait,
+		       mpStat.allocwait);
+
+	begin = offset;
+	*start = buffer + begin;
+	len -= begin;
+
+	if (len > length)
+		len = length;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+#endif
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_metapage.h linux-2.5.6-pre2/fs/jfs/jfs_metapage.h
--- linux-2.5.6-pre1/fs/jfs/jfs_metapage.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_metapage.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,123 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef	_H_JFS_METAPAGE
+#define _H_JFS_METAPAGE
+
+#include <linux/pagemap.h>
+
+typedef struct metapage {
+	/* Common logsyncblk prefix (see jfs_logmgr.h) */
+	u16 xflag;
+	u16 unused;
+	lid_t lid;
+	int lsn;
+	struct list_head synclist;
+	/* End of logsyncblk prefix */
+
+	unsigned long flag;	/* See Below */
+	unsigned long count;	/* Reference count */
+	void *data;		/* Data pointer */
+
+	/* list management stuff */
+	struct metapage *hash_prev;
+	struct metapage *hash_next;	/* Also used for free list */
+
+	struct list_head inode_list;	/* per-inode metapage list */
+	/*
+	 * mapping & index become redundant, but we need these here to
+	 * add the metapage to the hash before we have the real page
+	 */
+	struct address_space *mapping;
+	unsigned long index;
+	wait_queue_head_t wait;
+
+	/* implementation */
+	struct page *page;
+	unsigned long logical_size;
+
+	/* Journal management */
+	int clsn;
+	atomic_t nohomeok;
+	struct jfs_log *log;
+} metapage_t;
+
+/*
+ * Direct-access address space operations
+ */
+extern struct address_space_operations direct_aops;
+
+/* metapage flag */
+#define META_locked	0
+#define META_absolute	1
+#define META_free	2
+#define META_dirty	3
+#define META_sync	4
+#define META_discard	5
+#define META_forced	6
+
+#define mark_metapage_dirty(mp) set_bit(META_dirty, &(mp)->flag)
+
+/* function prototypes */
+extern metapage_t *__get_metapage(struct inode *inode,
+				  unsigned long lblock, unsigned int size,
+				  int absolute, unsigned long new);
+
+#define read_metapage(inode, lblock, size, absolute)\
+	 __get_metapage(inode, lblock, size, absolute, FALSE)
+
+#define get_metapage(inode, lblock, size, absolute)\
+	 __get_metapage(inode, lblock, size, absolute, TRUE)
+
+extern void release_metapage(metapage_t *);
+
+#define flush_metapage(mp) \
+{\
+	set_bit(META_dirty, &(mp)->flag);\
+	set_bit(META_sync, &(mp)->flag);\
+	release_metapage(mp);\
+}
+
+#define sync_metapage(mp) \
+	generic_buffer_fdatasync((struct inode *)mp->mapping->host,\
+				 mp->page->index, mp->page->index + 1)
+
+#define write_metapage(mp) \
+{\
+	set_bit(META_dirty, &(mp)->flag);\
+	release_metapage(mp);\
+}
+
+#define discard_metapage(mp) \
+{\
+	clear_bit(META_dirty, &(mp)->flag);\
+	set_bit(META_discard, &(mp)->flag);\
+	release_metapage(mp);\
+}
+
+extern void hold_metapage(metapage_t *, int);
+
+/*
+ * This routine uses hash to explicitly find small number of pages
+ */
+extern void invalidate_metapages(struct inode *, unsigned long, unsigned long);
+
+/*
+ * This one uses mp_list to invalidate all pages for an inode
+ */
+extern void invalidate_inode_metapages(struct inode *inode);
+#endif				/* _H_JFS_METAPAGE */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_mount.c linux-2.5.6-pre2/fs/jfs/jfs_mount.c
--- linux-2.5.6-pre1/fs/jfs/jfs_mount.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_mount.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,541 @@
+/*
+ *   MODULE_NAME:		jfs_mount.c
+ *
+ *   COMPONENT_NAME:		sysjfs
+ *
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Change History :
+ *
+ */
+
+/*
+ * Module: jfs_mount.c
+ *
+ * note: file system in transition to aggregate/fileset:
+ *
+ * file system mount is interpreted as the mount of aggregate, 
+ * if not already mounted, and mount of the single/only fileset in 
+ * the aggregate;
+ *
+ * a file system/aggregate is represented by an internal inode
+ * (aka mount inode) initialized with aggregate superblock;
+ * each vfs represents a fileset, and points to its "fileset inode 
+ * allocation map inode" (aka fileset inode):
+ * (an aggregate itself is structured recursively as a filset: 
+ * an internal vfs is constructed and points to its "fileset inode 
+ * allocation map inode" (aka aggregate inode) where each inode 
+ * represents a fileset inode) so that inode number is mapped to 
+ * on-disk inode in uniform way at both aggregate and fileset level;
+ *
+ * each vnode/inode of a fileset is linked to its vfs (to facilitate
+ * per fileset inode operations, e.g., unmount of a fileset, etc.);
+ * each inode points to the mount inode (to facilitate access to
+ * per aggregate information, e.g., block size, etc.) as well as
+ * its file set inode.
+ *
+ *   aggregate 
+ *   ipmnt
+ *   mntvfs -> fileset ipimap+ -> aggregate ipbmap -> aggregate ipaimap;
+ *             fileset vfs     -> vp(1) <-> ... <-> vp(n) <->vproot;
+ */
+
+#include <linux/fs.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_superblock.h"
+#include "jfs_dmap.h"
+#include "jfs_imap.h"
+#include "jfs_metapage.h"
+#include "jfs_debug.h"
+
+
+/*
+ * forward references
+ */
+static int chkSuper(struct super_block *);
+static int logMOUNT(struct super_block *sb);
+
+/*
+ * NAME:	jfs_mount(sb)
+ *
+ * FUNCTION:	vfs_mount()
+ *
+ * PARAMETER:	sb	- super block
+ *
+ * RETURN:	EBUSY	- device already mounted or open for write
+ *		EBUSY	- cvrdvp already mounted;
+ *		EBUSY	- mount table full
+ *		ENOTDIR	- cvrdvp not directory on a device mount
+ *		ENXIO	- device open failure
+ */
+int jfs_mount(struct super_block *sb)
+{
+	int rc = 0;		/* Return code          */
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	struct inode *ipaimap = NULL;
+	struct inode *ipaimap2 = NULL;
+	struct inode *ipimap = NULL;
+	struct inode *ipbmap = NULL;
+
+	jFYI(1, ("\nMount JFS\n"));
+
+	/*
+	 * read/validate superblock 
+	 * (initialize mount inode from the superblock)
+	 */
+	if ((rc = chkSuper(sb))) {
+		goto errout20;
+	}
+
+	ipaimap = diReadSpecial(sb, AGGREGATE_I);
+	if (ipaimap == NULL) {
+		jERROR(1, ("jfs_mount: Faild to read AGGREGATE_I\n"));
+		rc = EIO;
+		goto errout20;
+	}
+	sbi->ipaimap = ipaimap;
+
+	jFYI(1, ("jfs_mount: ipaimap:0x%p\n", ipaimap));
+
+	/*
+	 * initialize aggregate inode allocation map
+	 */
+	if ((rc = diMount(ipaimap))) {
+		jERROR(1,
+		       ("jfs_mount: diMount(ipaimap) failed w/rc = %d\n",
+			rc));
+		goto errout21;
+	}
+
+	/*
+	 * open aggregate block allocation map
+	 */
+	ipbmap = diReadSpecial(sb, BMAP_I);
+	if (ipbmap == NULL) {
+		rc = EIO;
+		goto errout22;
+	}
+
+	jFYI(1, ("jfs_mount: ipbmap:0x%p\n", ipbmap));
+
+	sbi->ipbmap = ipbmap;
+
+	/*
+	 * initialize aggregate block allocation map
+	 */
+	if ((rc = dbMount(ipbmap))) {
+		jERROR(1, ("jfs_mount: dbMount failed w/rc = %d\n", rc));
+		goto errout22;
+	}
+
+	/*
+	 * open the secondary aggregate inode allocation map
+	 *
+	 * This is a duplicate of the aggregate inode allocation map.
+	 *
+	 * hand craft a vfs in the same fashion as we did to read ipaimap.
+	 * By adding INOSPEREXT (32) to the inode number, we are telling
+	 * diReadSpecial that we are reading from the secondary aggregate
+	 * inode table.  This also creates a unique entry in the inode hash
+	 * table.
+	 */
+	if ((sbi->mntflag & JFS_BAD_SAIT) == 0) {
+		ipaimap2 = diReadSpecial(sb, AGGREGATE_I + INOSPEREXT);
+		if (ipaimap2 == 0) {
+			jERROR(1,
+			       ("jfs_mount: Faild to read AGGREGATE_I\n"));
+			rc = EIO;
+			goto errout35;
+		}
+		sbi->ipaimap2 = ipaimap2;
+
+		jFYI(1, ("jfs_mount: ipaimap2:0x%p\n", ipaimap2));
+
+		/*
+		 * initialize secondary aggregate inode allocation map
+		 */
+		if ((rc = diMount(ipaimap2))) {
+			jERROR(1,
+			       ("jfs_mount: diMount(ipaimap2) failed, rc = %d\n",
+				rc));
+			goto errout35;
+		}
+	} else
+		/* Secondary aggregate inode table is not valid */
+		sbi->ipaimap2 = 0;
+
+	/*
+	 *      mount (the only/single) fileset
+	 */
+	/*
+	 * open fileset inode allocation map (aka fileset inode)
+	 */
+	ipimap = diReadSpecial(sb, FILESYSTEM_I);
+	if (ipimap == NULL) {
+		jERROR(1, ("jfs_mount: Failed to read FILESYSTEM_I\n"));
+		/* open fileset secondary inode allocation map */
+		rc = EIO;
+		goto errout40;
+	}
+	jFYI(1, ("jfs_mount: ipimap:0x%p\n", ipimap));
+
+	/* map further access of per fileset inodes by the fileset inode */
+	sbi->ipimap = ipimap;
+
+	/* initialize fileset inode allocation map */
+	if ((rc = diMount(ipimap))) {
+		jERROR(1, ("jfs_mount: diMount failed w/rc = %d\n", rc));
+		goto errout41;
+	}
+
+	jFYI(1, ("Mount JFS Complete.\n"));
+	goto out;
+
+	/*
+	 *      unwind on error
+	 */
+//errout42: /* close fileset inode allocation map */
+	diUnmount(ipimap, 1);
+
+      errout41:		/* close fileset inode allocation map inode */
+	diFreeSpecial(ipimap);
+
+      errout40:		/* fileset closed */
+
+	/* close secondary aggregate inode allocation map */
+	if (ipaimap2) {
+		diUnmount(ipaimap2, 1);
+		diFreeSpecial(ipaimap2);
+	}
+
+      errout35:
+
+	/* close aggregate block allocation map */
+	dbUnmount(ipbmap, 1);
+	diFreeSpecial(ipbmap);
+
+      errout22:		/* close aggregate inode allocation map */
+
+	diUnmount(ipaimap, 1);
+
+      errout21:		/* close aggregate inodes */
+	diFreeSpecial(ipaimap);
+      errout20:		/* aggregate closed */
+
+      out:
+
+	if (rc) {
+		jERROR(1, ("Mount JFS Failure: %d\n", rc));
+	}
+	return rc;
+}
+
+/*
+ * NAME:	jfs_mount_rw(sb, remount)
+ *
+ * FUNCTION:	Completes read-write mount, or remounts read-only volume
+ *		as read-write
+ */
+int jfs_mount_rw(struct super_block *sb, int remount)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);  
+	log_t *log;
+	int rc;
+
+	/*
+	 * If we are re-mounting a previously read-only volume, we want to
+	 * re-read the inode and block maps, since fsck.jfs may have updated
+	 * them.
+	 */
+	if (remount) {
+		if (chkSuper(sb) || (sbi->state != FM_CLEAN))
+			return -EINVAL;
+
+		truncate_inode_pages(sbi->ipimap->i_mapping, 0);
+		truncate_inode_pages(sbi->ipbmap->i_mapping, 0);
+		diUnmount(sbi->ipimap, 1);
+		if ((rc = diMount(sbi->ipimap))) {
+			jERROR(1,("jfs_mount_rw: diMount failed!\n"));
+			return rc;
+		}
+
+		dbUnmount(sbi->ipbmap, 1);
+		if ((rc = dbMount(sbi->ipbmap))) {
+			jERROR(1,("jfs_mount_rw: dbMount failed!\n"));
+			return rc;
+		}
+	}
+#ifdef _STILL_TO_PORT
+	/*
+	 * get log device associated with the fs being mounted;
+	 */
+	if (ipmnt->i_mntflag & JFS_INLINELOG) {
+		vfsp->vfs_logVPB = vfsp->vfs_hVPB;
+		vfsp->vfs_logvpfs = vfsp->vfs_vpfsi;
+	} else if (vfsp->vfs_logvpfs == NULL) {
+		/*
+		 * XXX: there's only one external log per system;
+		 */
+		jERROR(1, ("jfs_mount: Mount Failure! No Log Device.\n"));
+		goto errout30;
+	}
+
+	logdev = vfsp->vfs_logvpfs->vpi_unit;
+	ipmnt->i_logdev = logdev;
+#endif				/* _STILL_TO_PORT */
+
+	/*
+	 * open/initialize log
+	 */
+	if ((rc = lmLogOpen(sb, &log)))
+		return rc;
+
+	JFS_SBI(sb)->log = log;
+
+	/*
+	 * update file system superblock;
+	 */
+	if ((rc = updateSuper(sb, FM_MOUNT))) {
+		jERROR(1,
+		       ("jfs_mount: updateSuper failed w/rc = %d\n", rc));
+		lmLogClose(sb, log);
+		JFS_SBI(sb)->log = 0;
+		return rc;
+	}
+
+	/*
+	 * write MOUNT log record of the file system
+	 */
+	logMOUNT(sb);
+
+	return rc;
+}
+
+/*
+ *	chkSuper()
+ *
+ * validate the superblock of the file system to be mounted and 
+ * get the file system parameters.
+ *
+ * returns
+ *	0 with fragsize set if check successful
+ *	error code if not successful
+ */
+static int chkSuper(struct super_block *sb)
+{
+	int rc = 0;
+	metapage_t *mp;
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	struct jfs_superblock *j_sb;
+	int AIM_bytesize, AIT_bytesize;
+	int expected_AIM_bytesize, expected_AIT_bytesize;
+	s64 AIM_byte_addr, AIT_byte_addr, fsckwsp_addr;
+	s64 byte_addr_diff0, byte_addr_diff1;
+	s32 bsize;
+
+	if ((rc = readSuper(sb, &mp)))
+		return rc;
+	j_sb = (struct jfs_superblock *) (mp->data);
+
+	/*
+	 * validate superblock
+	 */
+	/* validate fs signature */
+	if (strncmp(j_sb->s_magic, JFS_MAGIC, 4) ||
+	    j_sb->s_version != cpu_to_le32(JFS_VERSION)) {
+		//rc = EFORMAT;
+		rc = EINVAL;
+		goto out;
+	}
+
+	bsize = le32_to_cpu(j_sb->s_bsize);
+#ifdef _JFS_4K
+	if (bsize != PSIZE) {
+		jERROR(1, ("Currently only 4K block size supported!\n"));
+		rc = EINVAL;
+		goto out;
+	}
+#endif				/* _JFS_4K */
+
+	jFYI(1, ("superblock: flag:0x%08x state:0x%08x size:0x%Lx\n",
+		 le32_to_cpu(j_sb->s_flag), le32_to_cpu(j_sb->s_state),
+		 (unsigned long long) le64_to_cpu(j_sb->s_size)));
+
+	/* validate the descriptors for Secondary AIM and AIT */
+	if ((j_sb->s_flag & cpu_to_le32(JFS_BAD_SAIT)) !=
+	    cpu_to_le32(JFS_BAD_SAIT)) {
+		expected_AIM_bytesize = 2 * PSIZE;
+		AIM_bytesize = lengthPXD(&(j_sb->s_aim2)) * bsize;
+		expected_AIT_bytesize = 4 * PSIZE;
+		AIT_bytesize = lengthPXD(&(j_sb->s_ait2)) * bsize;
+		AIM_byte_addr = addressPXD(&(j_sb->s_aim2)) * bsize;
+		AIT_byte_addr = addressPXD(&(j_sb->s_ait2)) * bsize;
+		byte_addr_diff0 = AIT_byte_addr - AIM_byte_addr;
+		fsckwsp_addr = addressPXD(&(j_sb->s_fsckpxd)) * bsize;
+		byte_addr_diff1 = fsckwsp_addr - AIT_byte_addr;
+		if ((AIM_bytesize != expected_AIM_bytesize) ||
+		    (AIT_bytesize != expected_AIT_bytesize) ||
+		    (byte_addr_diff0 != AIM_bytesize) ||
+		    (byte_addr_diff1 <= AIT_bytesize))
+			j_sb->s_flag |= cpu_to_le32(JFS_BAD_SAIT);
+	}
+
+	/* in release 1, the flag MUST reflect inline log, and group commit */
+	if ((j_sb->s_flag & cpu_to_le32(JFS_INLINELOG)) !=
+	    cpu_to_le32(JFS_INLINELOG))
+		j_sb->s_flag |= cpu_to_le32(JFS_INLINELOG);
+	if ((j_sb->s_flag & cpu_to_le32(JFS_GROUPCOMMIT)) !=
+	    cpu_to_le32(JFS_GROUPCOMMIT))
+		j_sb->s_flag |= cpu_to_le32(JFS_GROUPCOMMIT);
+	jFYI(0, ("superblock: flag:0x%08x state:0x%08x size:0x%Lx\n",
+		 le32_to_cpu(j_sb->s_flag), le32_to_cpu(j_sb->s_state),
+		 (unsigned long long) le64_to_cpu(j_sb->s_size)));
+
+	/* validate fs state */
+	if (j_sb->s_state != cpu_to_le32(FM_CLEAN) &&
+	    !(sb->s_flags & MS_RDONLY)) {
+		jERROR(1,
+		       ("jfs_mount: Mount Failure: File System Dirty.\n"));
+		rc = EINVAL;
+		goto out;
+	}
+
+	sbi->state = le32_to_cpu(j_sb->s_state);
+	sbi->mntflag = le32_to_cpu(j_sb->s_flag);
+
+	/*
+	 * JFS always does I/O by 4K pages.  Don't tell the buffer cache
+	 * that we use anything else (leave s_blocksize alone).
+	 */
+	sbi->bsize = bsize;
+	sbi->l2bsize = le16_to_cpu(j_sb->s_l2bsize);
+
+	/*
+	 * For now, ignore s_pbsize, l2bfactor.  All I/O going through buffer
+	 * cache.
+	 */
+	sbi->nbperpage = PSIZE >> sbi->l2bsize;
+	sbi->l2nbperpage = L2PSIZE - sbi->l2bsize;
+	sbi->l2niperblk = sbi->l2bsize - L2DISIZE;
+	if (sbi->mntflag & JFS_INLINELOG)
+		sbi->logpxd = j_sb->s_logpxd;
+	sbi->ait2 = j_sb->s_ait2;
+
+      out:
+	release_metapage(mp);
+
+	return rc;
+}
+
+
+/*
+ *	updateSuper()
+ *
+ * update synchronously superblock if it is mounted read-write.
+ */
+int updateSuper(struct super_block *sb, uint state)
+{
+	int rc;
+	metapage_t *mp;
+	struct jfs_superblock *j_sb;
+
+	/*
+	 * Only fsck can fix dirty state
+	 */
+	if (JFS_SBI(sb)->state == FM_DIRTY)
+		return 0;
+
+	if ((rc = readSuper(sb, &mp)))
+		return rc;
+
+	j_sb = (struct jfs_superblock *) (mp->data);
+
+	j_sb->s_state = cpu_to_le32(state);
+	JFS_SBI(sb)->state = state;
+
+	if (state == FM_MOUNT) {
+		/* record log's dev_t and mount serial number */
+		j_sb->s_logdev =
+			cpu_to_le32(kdev_t_to_nr(JFS_SBI(sb)->log->dev));
+		j_sb->s_logserial = cpu_to_le32(JFS_SBI(sb)->log->serial);
+	} else if (state == FM_CLEAN) {
+		/*
+		 * If this volume is shared with OS/2, OS/2 will need to
+		 * recalculate DASD usage, since we don't deal with it.
+		 */
+		if (j_sb->s_flag & cpu_to_le32(JFS_DASD_ENABLED))
+			j_sb->s_flag |= cpu_to_le32(JFS_DASD_PRIME);
+	}
+
+	flush_metapage(mp);
+
+	return 0;
+}
+
+
+/*
+ *	readSuper()
+ *
+ * read superblock by raw sector address
+ */
+int readSuper(struct super_block *sb, metapage_t ** mpp)
+{
+	/* read in primary superblock */
+	*mpp = read_metapage(JFS_SBI(sb)->direct_inode,
+			     SUPER1_OFF >> sb->s_blocksize_bits, PSIZE, 1);
+	if (*mpp == NULL) {
+		/* read in secondary/replicated superblock */
+		*mpp = read_metapage(JFS_SBI(sb)->direct_inode,
+				     SUPER2_OFF >> sb->s_blocksize_bits,
+				     PSIZE, 1);
+	}
+	return *mpp ? 0 : 1;
+}
+
+
+/*
+ *	logMOUNT()
+ *
+ * function: write a MOUNT log record for file system.
+ *
+ * MOUNT record keeps logredo() from processing log records
+ * for this file system past this point in log.
+ * it is harmless if mount fails.
+ *
+ * note: MOUNT record is at aggregate level, not at fileset level, 
+ * since log records of previous mounts of a fileset
+ * (e.g., AFTER record of extent allocation) have to be processed 
+ * to update block allocation map at aggregate level.
+ */
+static int logMOUNT(struct super_block *sb)
+{
+	log_t *log = JFS_SBI(sb)->log;
+	lrd_t lrd;
+
+	lrd.logtid = 0;
+	lrd.backchain = 0;
+	lrd.type = cpu_to_le16(LOG_MOUNT);
+	lrd.length = 0;
+	lrd.aggregate = cpu_to_le32(kdev_t_to_nr(sb->s_dev));
+	lmLog(log, NULL, &lrd, NULL);
+
+	return 0;
+}
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_superblock.h linux-2.5.6-pre2/fs/jfs/jfs_superblock.h
--- linux-2.5.6-pre1/fs/jfs/jfs_superblock.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_superblock.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,143 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef	_H_JFS_SUPERBLOCK
+#define _H_JFS_SUPERBLOCK
+/*
+ *	jfs_superblock.h
+ */
+
+/*
+ * make the magic number something a human could read
+ */
+#define JFS_MAGIC 	"JFS1"	/* Magic word: Version 1 */
+
+#define JFS_VERSION	1	/* Version number: Version 1 */
+
+#define LV_NAME_SIZE	11	/* MUST BE 11 for OS/2 boot sector */
+
+/* 
+ *	aggregate superblock 
+ *
+ * The name superblock is too close to super_block, so the name has been
+ * changed to jfs_superblock.  The utilities are still using the old name.
+ */
+struct jfs_superblock {
+	char s_magic[4];	/* 4: magic number */
+	u32 s_version;		/* 4: version number */
+
+	s64 s_size;		/* 8: aggregate size in hardware/LVM blocks;
+				 * VFS: number of blocks
+				 */
+	s32 s_bsize;		/* 4: aggregate block size in bytes; 
+				 * VFS: fragment size
+				 */
+	s16 s_l2bsize;		/* 2: log2 of s_bsize */
+	s16 s_l2bfactor;	/* 2: log2(s_bsize/hardware block size) */
+	s32 s_pbsize;		/* 4: hardware/LVM block size in bytes */
+	s16 s_l2pbsize;		/* 2: log2 of s_pbsize */
+	s16 pad;		/* 2: padding necessary for alignment */
+
+	u32 s_agsize;		/* 4: allocation group size in aggr. blocks */
+
+	u32 s_flag;		/* 4: aggregate attributes:
+				 *    see jfs_filsys.h
+				 */
+	u32 s_state;		/* 4: mount/unmount/recovery state: 
+				 *    see jfs_filsys.h
+				 */
+	s32 s_compress;		/* 4: > 0 if data compression */
+
+	pxd_t s_ait2;		/* 8: first extent of secondary
+				 *    aggregate inode table
+				 */
+
+	pxd_t s_aim2;		/* 8: first extent of secondary
+				 *    aggregate inode map
+				 */
+	u32 s_logdev;		/* 4: device address of log */
+	s32 s_logserial;	/* 4: log serial number at aggregate mount */
+	pxd_t s_logpxd;		/* 8: inline log extent */
+
+	pxd_t s_fsckpxd;	/* 8: inline fsck work space extent */
+
+	struct timestruc_t s_time;	/* 8: time last updated */
+
+	s32 s_fsckloglen;	/* 4: Number of filesystem blocks reserved for
+				 *    the fsck service log.  
+				 *    N.B. These blocks are divided among the
+				 *         versions kept.  This is not a per
+				 *         version size.
+				 *    N.B. These blocks are included in the 
+				 *         length field of s_fsckpxd.
+				 */
+	s8 s_fscklog;		/* 1: which fsck service log is most recent
+				 *    0 => no service log data yet
+				 *    1 => the first one
+				 *    2 => the 2nd one
+				 */
+	char s_fpack[11];	/* 11: file system volume name 
+				 *     N.B. This must be 11 bytes to
+				 *          conform with the OS/2 BootSector
+				 *          requirements
+				 */
+
+	/* extendfs() parameter under s_state & FM_EXTENDFS */
+	s64 s_xsize;		/* 8: extendfs s_size */
+	pxd_t s_xfsckpxd;	/* 8: extendfs fsckpxd */
+	pxd_t s_xlogpxd;	/* 8: extendfs logpxd */
+	/* - 128 byte boundary - */
+
+	/*
+	 *      DFS VFS support (preliminary) 
+	 */
+	char s_attach;		/* 1: VFS: flag: set when aggregate is attached
+				 */
+	u8 rsrvd4[7];		/* 7: reserved - set to 0 */
+
+	u64 totalUsable;	/* 8: VFS: total of 1K blocks which are
+				 * available to "normal" (non-root) users.
+				 */
+	u64 minFree;		/* 8: VFS: # of 1K blocks held in reserve for 
+				 * exclusive use of root.  This value can be 0,
+				 * and if it is then totalUsable will be equal 
+				 * to # of blocks in aggregate.  I believe this
+				 * means that minFree + totalUsable = # blocks.
+				 * In that case, we don't need to store both 
+				 * totalUsable and minFree since we can compute
+				 * one from the other.  I would guess minFree 
+				 * would be the one we should store, and 
+				 * totalUsable would be the one we should 
+				 * compute.  (Just a guess...)
+				 */
+
+	u64 realFree;		/* 8: VFS: # of free 1K blocks can be used by 
+				 * "normal" users.  It may be this is something
+				 * we should compute when asked for instead of 
+				 * storing in the superblock.  I don't know how
+				 * often this information is needed.
+				 */
+	/*
+	 *      graffiti area
+	 */
+};
+
+extern int readSuper(struct super_block *, struct metapage **);
+extern int updateSuper(struct super_block *, uint);
+
+#endif /*_H_JFS_SUPERBLOCK */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_txnmgr.c linux-2.5.6-pre2/fs/jfs/jfs_txnmgr.c
--- linux-2.5.6-pre1/fs/jfs/jfs_txnmgr.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_txnmgr.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,3021 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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
+ */
+
+/*
+ *      jfs_txnmgr.c: transaction manager
+ *
+ * notes:
+ * transaction starts with txBegin() and ends with txCommit()
+ * or txAbort().
+ *
+ * tlock is acquired at the time of update;
+ * (obviate scan at commit time for xtree and dtree)
+ * tlock and mp points to each other;
+ * (no hashlist for mp -> tlock).
+ *
+ * special cases:
+ * tlock on in-memory inode:
+ * in-place tlock in the in-memory inode itself;
+ * converted to page lock by iWrite() at commit time.
+ *
+ * tlock during write()/mmap() under anonymous transaction (tid = 0):
+ * transferred (?) to transaction at commit time.
+ *
+ * use the page itself to update allocation maps
+ * (obviate intermediate replication of allocation/deallocation data)
+ * hold on to mp+lock thru update of maps
+ */
+
+
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_metapage.h"
+#include "jfs_dinode.h"
+#include "jfs_imap.h"
+#include "jfs_dmap.h"
+#include "jfs_superblock.h"
+#include "jfs_debug.h"
+
+/*
+ *      transaction management structures
+ */
+static struct {
+	/* tblock */
+	int freetid;		/* 4: index of a free tid structure */
+	wait_queue_head_t freewait;	/* 4: eventlist of free tblock */
+
+	/* tlock */
+	int freelock;		/* 4: index first free lock word */
+	wait_queue_head_t freelockwait;	/* 4: eventlist of free tlock */
+	wait_queue_head_t lowlockwait;	/* 4: eventlist of ample tlocks */
+	int tlocksInUse;	/* 4: Number of tlocks in use */
+	spinlock_t LazyLock;	/* 4: synchronize sync_queue & unlock_queue */
+/*	tblock_t *sync_queue;	 * 4: Transactions waiting for data sync */
+	tblock_t *unlock_queue;	/* 4: Transactions waiting to be released */
+	tblock_t *unlock_tail;	/* 4: Tail of unlock_queue */
+	struct list_head anon_list;	/* inodes having anonymous txns */
+	struct list_head anon_list2;	/* inodes having anonymous txns
+					   that couldn't be sync'ed */
+} TxAnchor;
+
+static int nTxBlock = 512;	/* number of transaction blocks */
+struct tblock *TxBlock;	        /* transaction block table */
+
+static int nTxLock = 2048;	/* number of transaction locks */
+static int TxLockLWM = 2048*.4;	/* Low water mark for number of txLocks used */
+static int TxLockHWM = 2048*.8;	/* High water mark for number of txLocks used */
+struct tlock *TxLock;           /* transaction lock table */
+static int TlocksLow = 0;	/* Indicates low number of available tlocks */
+
+
+/*
+ *      transaction management lock
+ */
+static spinlock_t jfsTxnLock = SPIN_LOCK_UNLOCKED;
+
+#define TXN_LOCK()              spin_lock(&jfsTxnLock)
+#define TXN_UNLOCK()            spin_unlock(&jfsTxnLock)
+
+#define LAZY_LOCK_INIT()	spin_lock_init(&TxAnchor.LazyLock);
+#define LAZY_LOCK(flags)	spin_lock_irqsave(&TxAnchor.LazyLock, flags)
+#define LAZY_UNLOCK(flags) spin_unlock_irqrestore(&TxAnchor.LazyLock, flags)
+
+/*
+ * Retry logic exist outside these macros to protect from spurrious wakeups.
+ */
+static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	add_wait_queue(event, &wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	TXN_UNLOCK();
+	schedule();
+	current->state = TASK_RUNNING;
+	remove_wait_queue(event, &wait);
+}
+
+#define TXN_SLEEP(event)\
+{\
+	TXN_SLEEP_DROP_LOCK(event);\
+	TXN_LOCK();\
+}
+
+#define TXN_WAKEUP(event) wake_up_all(event)
+
+
+/*
+ *      statistics
+ */
+struct {
+	tid_t maxtid;		/* 4: biggest tid ever used */
+	lid_t maxlid;		/* 4: biggest lid ever used */
+	int ntid;		/* 4: # of transactions performed */
+	int nlid;		/* 4: # of tlocks acquired */
+	int waitlock;		/* 4: # of tlock wait */
+} stattx;
+
+
+/*
+ * external references
+ */
+extern int lmGroupCommit(log_t * log, tblock_t * tblk);
+extern void lmSync(log_t *);
+extern int readSuper(struct super_block *sb, metapage_t ** bpp);
+extern int jfs_commit_inode(struct inode *, int);
+extern int jfs_thread_stopped(void);
+
+extern struct task_struct *jfsCommitTask;
+extern struct completion jfsIOwait;
+extern struct task_struct *jfsSyncTask;
+
+/*
+ * forward references
+ */
+int diLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck,
+	  commit_t * cd);
+int dataLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck);
+void dtLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck);
+void inlineLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck);
+void mapLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck);
+void txAbortCommit(commit_t * cd, int exval);
+static void txAllocPMap(struct inode *ip, maplock_t * maplock,
+			tblock_t * tblk);
+void txForce(tblock_t * tblk);
+static int txLog(log_t * log, tblock_t * tblk, commit_t * cd);
+int txMoreLock(void);
+static void txUpdateMap(tblock_t * tblk);
+static void txRelease(tblock_t * tblk);
+void xtLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck);
+static void LogSyncRelease(metapage_t * mp);
+
+/*
+ *              transaction block/lock management
+ *              ---------------------------------
+ */
+
+/*
+ * Get a transaction lock from the free list.  If the number in use is
+ * greater than the high water mark, wake up the sync daemon.  This should
+ * free some anonymous transaction locks.  (TXN_LOCK must be held.)
+ */
+static lid_t txLockAlloc(void)
+{
+	lid_t lid;
+
+	while (!(lid = TxAnchor.freelock))
+		TXN_SLEEP(&TxAnchor.freelockwait);
+	TxAnchor.freelock = TxLock[lid].next;
+	HIGHWATERMARK(stattx.maxlid, lid);
+	if ((++TxAnchor.tlocksInUse > TxLockHWM) && (TlocksLow == 0)) {
+		jEVENT(0,("txLockAlloc TlocksLow\n"));
+		TlocksLow = 1;
+	wake_up_process(jfsSyncTask);
+	}
+
+	return lid;
+}
+
+static void txLockFree(lid_t lid)
+{
+	TxLock[lid].next = TxAnchor.freelock;
+	TxAnchor.freelock = lid;
+	TxAnchor.tlocksInUse--;
+	if (TlocksLow && (TxAnchor.tlocksInUse < TxLockLWM)) {
+		jEVENT(0,("txLockFree TlocksLow no more\n"));
+		TlocksLow = 0;
+		TXN_WAKEUP(&TxAnchor.lowlockwait);
+	}
+	TXN_WAKEUP(&TxAnchor.freelockwait);
+}
+
+/*
+ * NAME:        txInit()
+ *
+ * FUNCTION:    initialize transaction management structures
+ *
+ * RETURN:
+ *
+ * serialization: single thread at jfs_init()
+ */
+int txInit(void)
+{
+	int k, size;
+
+	/*
+	 * initialize transaction block (tblock) table
+	 *
+	 * transaction id (tid) = tblock index
+	 * tid = 0 is reserved.
+	 */
+	size = sizeof(tblock_t) * nTxBlock;
+	TxBlock = (tblock_t *) vmalloc(size);
+	if (TxBlock == NULL)
+		return ENOMEM;
+
+	for (k = 1; k < nTxBlock - 1; k++) {
+		TxBlock[k].next = k + 1;
+		init_waitqueue_head(&TxBlock[k].gcwait);
+		init_waitqueue_head(&TxBlock[k].waitor);
+	}
+	TxBlock[k].next = 0;
+	init_waitqueue_head(&TxBlock[k].gcwait);
+	init_waitqueue_head(&TxBlock[k].waitor);
+
+	TxAnchor.freetid = 1;
+	init_waitqueue_head(&TxAnchor.freewait);
+
+	stattx.maxtid = 1;	/* statistics */
+
+	/*
+	 * initialize transaction lock (tlock) table
+	 *
+	 * transaction lock id = tlock index
+	 * tlock id = 0 is reserved.
+	 */
+	size = sizeof(tlock_t) * nTxLock;
+	TxLock = (tlock_t *) vmalloc(size);
+	if (TxLock == NULL) {
+		vfree(TxBlock);
+		return ENOMEM;
+	}
+
+	/* initialize tlock table */
+	for (k = 1; k < nTxLock - 1; k++)
+		TxLock[k].next = k + 1;
+	TxLock[k].next = 0;
+	init_waitqueue_head(&TxAnchor.freelockwait);
+	init_waitqueue_head(&TxAnchor.lowlockwait);
+
+	TxAnchor.freelock = 1;
+	TxAnchor.tlocksInUse = 0;
+	INIT_LIST_HEAD(&TxAnchor.anon_list);
+	INIT_LIST_HEAD(&TxAnchor.anon_list2);
+
+	stattx.maxlid = 1;	/* statistics */
+
+	return 0;
+}
+
+/*
+ * NAME:        txExit()
+ *
+ * FUNCTION:    clean up when module is unloaded
+ */
+void txExit(void)
+{
+	vfree(TxLock);
+	TxLock = 0;
+	vfree(TxBlock);
+	TxBlock = 0;
+}
+
+
+/*
+ * NAME:        txBegin()
+ *
+ * FUNCTION:    start a transaction.
+ *
+ * PARAMETER:   sb	- superblock
+ *              flag	- force for nested tx;
+ *
+ * RETURN:	tid	- transaction id
+ *
+ * note: flag force allows to start tx for nested tx
+ * to prevent deadlock on logsync barrier;
+ */
+tid_t txBegin(struct super_block *sb, int flag)
+{
+	tid_t t;
+	tblock_t *tblk;
+	log_t *log;
+
+	jFYI(1, ("txBegin: flag = 0x%x\n", flag));
+	log = (log_t *) JFS_SBI(sb)->log;
+
+	TXN_LOCK();
+
+      retry:
+	if (flag != COMMIT_FORCE) {
+		/*
+		 * synchronize with logsync barrier
+		 */
+		if (log->syncbarrier) {
+			TXN_SLEEP(&log->syncwait);
+			goto retry;
+		}
+	}
+	if (flag == 0) {
+		/*
+		 * Don't begin transaction if we're getting starved for tlocks
+		 * unless COMMIT_FORCE (imap changes) or COMMIT_INODE (which
+		 * may ultimately free tlocks)
+		 */
+		if (TlocksLow) {
+			TXN_SLEEP(&TxAnchor.lowlockwait);
+			goto retry;
+		}
+	}
+
+	/*
+	 * allocate transaction id/block
+	 */
+	if ((t = TxAnchor.freetid) == 0) {
+		jFYI(1, ("txBegin: waiting for free tid\n"));
+		TXN_SLEEP(&TxAnchor.freewait);
+		goto retry;
+	}
+
+	tblk = tid_to_tblock(t);
+
+	if ((tblk->next == 0) && (current != jfsCommitTask)) {
+		/* Save one tblk for jfsCommit thread */
+		jFYI(1, ("txBegin: waiting for free tid\n"));
+		TXN_SLEEP(&TxAnchor.freewait);
+		goto retry;
+	}
+
+	TxAnchor.freetid = tblk->next;
+
+	/*
+	 * initialize transaction
+	 */
+
+	/*
+	 * We can't zero the whole thing or we screw up another thread being
+	 * awakened after sleeping on tblk->waitor
+	 *
+	 * memset(tblk, 0, sizeof(tblock_t));
+	 */
+	tblk->next = tblk->last = tblk->xflag = tblk->flag = tblk->lsn = 0;
+
+	tblk->sb = sb;
+	++log->logtid;
+	tblk->logtid = log->logtid;
+
+	++log->active;
+
+	HIGHWATERMARK(stattx.maxtid, t);	/* statistics */
+	INCREMENT(stattx.ntid);	/* statistics */
+
+	TXN_UNLOCK();
+
+	jFYI(1, ("txBegin: returning tid = %d\n", t));
+
+	return t;
+}
+
+
+/*
+ * NAME:        txBeginAnon()
+ *
+ * FUNCTION:    start an anonymous transaction.
+ *		Blocks if logsync or available tlocks are low to prevent
+ *		anonymous tlocks from depleting supply.
+ *
+ * PARAMETER:   sb	- superblock
+ *
+ * RETURN:	none
+ */
+void txBeginAnon(struct super_block *sb)
+{
+	log_t *log;
+
+	log = (log_t *) JFS_SBI(sb)->log;
+
+	TXN_LOCK();
+
+      retry:
+	/*
+	 * synchronize with logsync barrier
+	 */
+	if (log->syncbarrier) {
+		TXN_SLEEP(&log->syncwait);
+		goto retry;
+	}
+
+	/*
+	 * Don't begin transaction if we're getting starved for tlocks
+	 */
+	if (TlocksLow) {
+		TXN_SLEEP(&TxAnchor.lowlockwait);
+		goto retry;
+	}
+	TXN_UNLOCK();
+}
+
+
+/*
+ *      txEnd()
+ *
+ * function: free specified transaction block.
+ *
+ *      logsync barrier processing:
+ *
+ * serialization:
+ */
+void txEnd(tid_t tid)
+{
+	tblock_t *tblk = tid_to_tblock(tid);
+	log_t *log;
+
+	jFYI(1, ("txEnd: tid = %d\n", tid));
+	TXN_LOCK();
+
+	/*
+	 * wakeup transactions waiting on the page locked
+	 * by the current transaction
+	 */
+	TXN_WAKEUP(&tblk->waitor);
+
+	log = (log_t *) JFS_SBI(tblk->sb)->log;
+
+	/*
+	 * Lazy commit thread can't free this guy until we mark it UNLOCKED,
+	 * otherwise, we would be left with a transaction that may have been
+	 * reused.
+	 *
+	 * Lazy commit thread will turn off tblkGC_LAZY before calling this
+	 * routine.
+	 */
+	if (tblk->flag & tblkGC_LAZY) {
+		jFYI(1,
+		     ("txEnd called w/lazy tid: %d, tblk = 0x%p\n",
+		      tid, tblk));
+		TXN_UNLOCK();
+
+		spin_lock_irq(&log->gclock);	// LOGGC_LOCK
+		tblk->flag |= tblkGC_UNLOCKED;
+		spin_unlock_irq(&log->gclock);	// LOGGC_UNLOCK
+		return;
+	}
+
+	jFYI(1, ("txEnd: tid: %d, tblk = 0x%p\n", tid, tblk));
+
+	assert(tblk->next == 0);
+
+	/*
+	 * insert tblock back on freelist
+	 */
+	tblk->next = TxAnchor.freetid;
+	TxAnchor.freetid = tid;
+
+	/*
+	 * mark the tblock not active
+	 */
+	--log->active;
+
+	/*
+	 * synchronize with logsync barrier
+	 */
+	if (log->syncbarrier && log->active == 0) {
+		/* forward log syncpt */
+		/* lmSync(log); */
+
+		jFYI(1, ("     log barrier off: 0x%x\n", log->lsn));
+
+		/* enable new transactions start */
+		log->syncbarrier = 0;
+
+		/* wakeup all waitors for logsync barrier */
+		TXN_WAKEUP(&log->syncwait);
+	}
+
+	/*
+	 * wakeup all waitors for a free tblock
+	 */
+	TXN_WAKEUP(&TxAnchor.freewait);
+
+	TXN_UNLOCK();
+	jFYI(1, ("txEnd: exitting\n"));
+}
+
+
+/*
+ *      txLock()
+ *
+ * function: acquire a transaction lock on the specified <mp>
+ *
+ * parameter:
+ *
+ * return:      transaction lock id
+ *
+ * serialization:
+ */
+tlock_t *txLock(tid_t tid, struct inode *ip, metapage_t * mp, int type)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	int dir_xtree = 0;
+	lid_t lid;
+	tid_t xtid;
+	tlock_t *tlck;
+	xtlock_t *xtlck;
+	linelock_t *linelock;
+	xtpage_t *p;
+	tblock_t *tblk;
+
+	TXN_LOCK();
+
+	if (S_ISDIR(ip->i_mode) && (type & tlckXTREE) &&
+	    !(mp->xflag & COMMIT_PAGE)) {
+		/*
+		 * Directory inode is special.  It can have both an xtree tlock
+		 * and a dtree tlock associated with it.
+		 */
+		dir_xtree = 1;
+		lid = jfs_ip->xtlid;
+	} else
+		lid = mp->lid;
+
+	/* is page not locked by a transaction ? */
+	if (lid == 0)
+		goto allocateLock;
+
+	jFYI(1, ("txLock: tid:%d ip:0x%p mp:0x%p lid:%d\n",
+		 tid, ip, mp, lid));
+
+	/* is page locked by the requester transaction ? */
+	tlck = lid_to_tlock(lid);
+	if ((xtid = tlck->tid) == tid)
+		goto grantLock;
+
+	/*
+	 * is page locked by anonymous transaction/lock ?
+	 *
+	 * (page update without transaction (i.e., file write) is
+	 * locked under anonymous transaction tid = 0:
+	 * anonymous tlocks maintained on anonymous tlock list of
+	 * the inode of the page and available to all anonymous
+	 * transactions until txCommit() time at which point
+	 * they are transferred to the transaction tlock list of
+	 * the commiting transaction of the inode)
+	 */
+	if (xtid == 0) {
+		tlck->tid = tid;
+		tblk = tid_to_tblock(tid);
+		/*
+		 * The order of the tlocks in the transaction is important
+		 * (during truncate, child xtree pages must be freed before
+		 * parent's tlocks change the working map).
+		 * Take tlock off anonymous list and add to tail of
+		 * transaction list
+		 *
+		 * Note:  We really need to get rid of the tid & lid and
+		 * use list_head's.  This code is getting UGLY!
+		 */
+		if (jfs_ip->atlhead == lid) {
+			if (jfs_ip->atltail == lid) {
+				/* only anonymous txn.
+				 * Remove from anon_list
+				 */
+				list_del_init(&jfs_ip->anon_inode_list);
+			}
+			jfs_ip->atlhead = tlck->next;
+		} else {
+			lid_t last;
+			for (last = jfs_ip->atlhead;
+			     lid_to_tlock(last)->next != lid;
+			     last = lid_to_tlock(last)->next) {
+				assert(last);
+			}
+			lid_to_tlock(last)->next = tlck->next;
+			if (jfs_ip->atltail == lid)
+				jfs_ip->atltail = last;
+		}
+
+		/* insert the tlock at tail of transaction tlock list */
+
+		if (tblk->next)
+			lid_to_tlock(tblk->last)->next = lid;
+		else
+			tblk->next = lid;
+		tlck->next = 0;
+		tblk->last = lid;
+
+		goto grantLock;
+	}
+
+	goto waitLock;
+
+	/*
+	 * allocate a tlock
+	 */
+      allocateLock:
+	lid = txLockAlloc();
+	tlck = lid_to_tlock(lid);
+
+	/*
+	 * initialize tlock
+	 */
+	tlck->tid = tid;
+
+	/* mark tlock for meta-data page */
+	if (mp->xflag & COMMIT_PAGE) {
+
+		tlck->flag = tlckPAGELOCK;
+
+		/* mark the page dirty and nohomeok */
+		mark_metapage_dirty(mp);
+		atomic_inc(&mp->nohomeok);
+
+		jFYI(1,
+		     ("locking mp = 0x%p, nohomeok = %d tid = %d tlck = 0x%p\n",
+		      mp, atomic_read(&mp->nohomeok), tid, tlck));
+
+		/* if anonymous transaction, and buffer is on the group
+		 * commit synclist, mark inode to show this.  This will
+		 * prevent the buffer from being marked nohomeok for too
+		 * long a time.
+		 */
+		if ((tid == 0) && mp->lsn)
+			set_cflag(COMMIT_Synclist, ip);
+	}
+	/* mark tlock for in-memory inode */
+	else
+		tlck->flag = tlckINODELOCK;
+
+	tlck->type = 0;
+
+	/* bind the tlock and the page */
+	tlck->ip = ip;
+	tlck->mp = mp;
+	if (dir_xtree)
+		jfs_ip->xtlid = lid;
+	else
+		mp->lid = lid;
+
+	/*
+	 * enqueue transaction lock to transaction/inode
+	 */
+	/* insert the tlock at tail of transaction tlock list */
+	if (tid) {
+		tblk = tid_to_tblock(tid);
+		if (tblk->next)
+			lid_to_tlock(tblk->last)->next = lid;
+		else
+			tblk->next = lid;
+		tlck->next = 0;
+		tblk->last = lid;
+	}
+	/* anonymous transaction:
+	 * insert the tlock at head of inode anonymous tlock list
+	 */
+	else {
+		tlck->next = jfs_ip->atlhead;
+		jfs_ip->atlhead = lid;
+		if (tlck->next == 0) {
+			/* This inode's first anonymous transaction */
+			jfs_ip->atltail = lid;
+			list_add_tail(&jfs_ip->anon_inode_list,
+				      &TxAnchor.anon_list);
+		}
+	}
+
+	/* initialize type dependent area for linelock */
+	linelock = (linelock_t *) & tlck->lock;
+	linelock->next = 0;
+	linelock->flag = tlckLINELOCK;
+	linelock->maxcnt = TLOCKSHORT;
+	linelock->index = 0;
+
+	switch (type & tlckTYPE) {
+	case tlckDTREE:
+		linelock->l2linesize = L2DTSLOTSIZE;
+		break;
+
+	case tlckXTREE:
+		linelock->l2linesize = L2XTSLOTSIZE;
+
+		xtlck = (xtlock_t *) linelock;
+		xtlck->header.offset = 0;
+		xtlck->header.length = 2;
+
+		if (type & tlckNEW) {
+			xtlck->lwm.offset = XTENTRYSTART;
+		} else {
+			if (mp->xflag & COMMIT_PAGE)
+				p = (xtpage_t *) mp->data;
+			else
+				p = &jfs_ip->i_xtroot;
+			xtlck->lwm.offset =
+			    le16_to_cpu(p->header.nextindex);
+		}
+		xtlck->lwm.length = 0;	/* ! */
+
+		xtlck->index = 2;
+		break;
+
+	case tlckINODE:
+		linelock->l2linesize = L2INODESLOTSIZE;
+		break;
+
+	case tlckDATA:
+		linelock->l2linesize = L2DATASLOTSIZE;
+		break;
+
+	default:
+		jERROR(1, ("UFO tlock:0x%p\n", tlck));
+	}
+
+	/*
+	 * update tlock vector
+	 */
+      grantLock:
+	tlck->type |= type;
+
+	TXN_UNLOCK();
+
+	return tlck;
+
+	/*
+	 * page is being locked by another transaction:
+	 */
+      waitLock:
+	/* Only locks on ipimap or ipaimap should reach here */
+	/* assert(jfs_ip->fileset == AGGREGATE_I); */
+	if (jfs_ip->fileset != AGGREGATE_I) {
+		jERROR(1, ("txLock: trying to lock locked page!\n"));
+		dump_mem("ip", ip, sizeof(struct inode));
+		dump_mem("mp", mp, sizeof(metapage_t));
+		dump_mem("Locker's tblk", tid_to_tblock(tid),
+			 sizeof(tblock_t));
+		dump_mem("Tlock", tlck, sizeof(tlock_t));
+		BUG();
+	}
+	INCREMENT(stattx.waitlock);	/* statistics */
+	release_metapage(mp);
+
+	jEVENT(0, ("txLock: in waitLock, tid = %d, xtid = %d, lid = %d\n",
+		   tid, xtid, lid));
+	TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor);
+	jEVENT(0, ("txLock: awakened     tid = %d, lid = %d\n", tid, lid));
+
+	return NULL;
+}
+
+
+/*
+ * NAME:        txRelease()
+ *
+ * FUNCTION:    Release buffers associated with transaction locks, but don't
+ *		mark homeok yet.  The allows other transactions to modify
+ *		buffers, but won't let them go to disk until commit record
+ *		actually gets written.
+ *
+ * PARAMETER:
+ *              tblk    -
+ *
+ * RETURN:      Errors from subroutines.
+ */
+static void txRelease(tblock_t * tblk)
+{
+	metapage_t *mp;
+	lid_t lid;
+	tlock_t *tlck;
+
+	TXN_LOCK();
+
+	for (lid = tblk->next; lid; lid = tlck->next) {
+		tlck = lid_to_tlock(lid);
+		if ((mp = tlck->mp) != NULL &&
+		    (tlck->type & tlckBTROOT) == 0) {
+			assert(mp->xflag & COMMIT_PAGE);
+			mp->lid = 0;
+		}
+	}
+
+	/*
+	 * wakeup transactions waiting on a page locked
+	 * by the current transaction
+	 */
+	TXN_WAKEUP(&tblk->waitor);
+
+	TXN_UNLOCK();
+}
+
+
+/*
+ * NAME:        txUnlock()
+ *
+ * FUNCTION:    Initiates pageout of pages modified by tid in journalled
+ *              objects and frees their lockwords.
+ *
+ * PARAMETER:
+ *              flag    -
+ *
+ * RETURN:      Errors from subroutines.
+ */
+static void txUnlock(tblock_t * tblk, int flag)
+{
+	tlock_t *tlck;
+	linelock_t *linelock;
+	lid_t lid, next, llid, k;
+	metapage_t *mp;
+	log_t *log;
+	int force;
+	int difft, diffp;
+
+	jFYI(1, ("txUnlock: tblk = 0x%p\n", tblk));
+	log = (log_t *) JFS_SBI(tblk->sb)->log;
+	force = flag & COMMIT_FLUSH;
+	if (log->syncbarrier)
+		force |= COMMIT_FORCE;
+
+	/*
+	 * mark page under tlock homeok (its log has been written):
+	 * if caller has specified FORCE (e.g., iRecycle()), or
+	 * if syncwait for the log is set (i.e., the log sync point
+	 * has fallen behind), or
+	 * if syncpt is set for the page, or
+	 * if the page is new, initiate pageout;
+	 * otherwise, leave the page in memory.
+	 */
+	for (lid = tblk->next; lid; lid = next) {
+		tlck = lid_to_tlock(lid);
+		next = tlck->next;
+
+		jFYI(1, ("unlocking lid = %d, tlck = 0x%p\n", lid, tlck));
+
+		/* unbind page from tlock */
+		if ((mp = tlck->mp) != NULL &&
+		    (tlck->type & tlckBTROOT) == 0) {
+			assert(mp->xflag & COMMIT_PAGE);
+
+			/* hold buffer
+			 *
+			 * It's possible that someone else has the metapage.
+			 * The only things were changing are nohomeok, which
+			 * is handled atomically, and clsn which is protected
+			 * by the LOGSYNC_LOCK.
+			 */
+			hold_metapage(mp, 1);
+
+			assert(atomic_read(&mp->nohomeok) > 0);
+			atomic_dec(&mp->nohomeok);
+
+			/* inherit younger/larger clsn */
+			LOGSYNC_LOCK(log);
+			if (mp->clsn) {
+				logdiff(difft, tblk->clsn, log);
+				logdiff(diffp, mp->clsn, log);
+				if (difft > diffp)
+					mp->clsn = tblk->clsn;
+			} else
+				mp->clsn = tblk->clsn;
+			LOGSYNC_UNLOCK(log);
+
+			assert(!(tlck->flag & tlckFREEPAGE));
+
+			if (tlck->flag & tlckWRITEPAGE) {
+				write_metapage(mp);
+			} else {
+				/* release page which has been forced */
+				release_metapage(mp);
+			}
+		}
+
+		/* insert tlock, and linelock(s) of the tlock if any,
+		 * at head of freelist
+		 */
+		TXN_LOCK();
+
+		llid = ((linelock_t *) & tlck->lock)->next;
+		while (llid) {
+			linelock = (linelock_t *) lid_to_tlock(llid);
+			k = linelock->next;
+			txLockFree(llid);
+			llid = k;
+		}
+		txLockFree(lid);
+
+		TXN_UNLOCK();
+	}
+	tblk->next = tblk->last = 0;
+
+	/*
+	 * remove tblock from logsynclist
+	 * (allocation map pages inherited lsn of tblk and
+	 * has been inserted in logsync list at txUpdateMap())
+	 */
+	if (tblk->lsn) {
+		LOGSYNC_LOCK(log);
+		log->count--;
+		list_del(&tblk->synclist);
+		LOGSYNC_UNLOCK(log);
+	}
+}
+
+
+/*
+ *      txMaplock()
+ *
+ * function: allocate a transaction lock for freed page/entry;
+ *      for freed page, maplock is used as xtlock/dtlock type;
+ */
+tlock_t *txMaplock(tid_t tid, struct inode *ip, int type)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	lid_t lid;
+	tblock_t *tblk;
+	tlock_t *tlck;
+	maplock_t *maplock;
+
+	TXN_LOCK();
+
+	/*
+	 * allocate a tlock
+	 */
+	lid = txLockAlloc();
+	tlck = lid_to_tlock(lid);
+
+	/*
+	 * initialize tlock
+	 */
+	tlck->tid = tid;
+
+	/* bind the tlock and the object */
+	tlck->flag = tlckINODELOCK;
+	tlck->ip = ip;
+	tlck->mp = NULL;
+
+	tlck->type = type;
+
+	/*
+	 * enqueue transaction lock to transaction/inode
+	 */
+	/* insert the tlock at tail of transaction tlock list */
+	if (tid) {
+		tblk = tid_to_tblock(tid);
+		if (tblk->next)
+			lid_to_tlock(tblk->last)->next = lid;
+		else
+			tblk->next = lid;
+		tlck->next = 0;
+		tblk->last = lid;
+	}
+	/* anonymous transaction:
+	 * insert the tlock at head of inode anonymous tlock list
+	 */
+	else {
+		tlck->next = jfs_ip->atlhead;
+		jfs_ip->atlhead = lid;
+		if (tlck->next == 0) {
+			/* This inode's first anonymous transaction */
+			jfs_ip->atltail = lid;
+			list_add_tail(&jfs_ip->anon_inode_list,
+				      &TxAnchor.anon_list);
+		}
+	}
+
+	TXN_UNLOCK();
+
+	/* initialize type dependent area for maplock */
+	maplock = (maplock_t *) & tlck->lock;
+	maplock->next = 0;
+	maplock->maxcnt = 0;
+	maplock->index = 0;
+
+	return tlck;
+}
+
+
+/*
+ *      txLinelock()
+ *
+ * function: allocate a transaction lock for log vector list
+ */
+linelock_t *txLinelock(linelock_t * tlock)
+{
+	lid_t lid;
+	tlock_t *tlck;
+	linelock_t *linelock;
+
+	TXN_LOCK();
+
+	/* allocate a TxLock structure */
+	lid = txLockAlloc();
+	tlck = lid_to_tlock(lid);
+
+	TXN_UNLOCK();
+
+	/* initialize linelock */
+	linelock = (linelock_t *) tlck;
+	linelock->next = 0;
+	linelock->flag = tlckLINELOCK;
+	linelock->maxcnt = TLOCKLONG;
+	linelock->index = 0;
+
+	/* append linelock after tlock */
+	linelock->next = tlock->next;
+	tlock->next = lid;
+
+	return linelock;
+}
+
+
+
+/*
+ *              transaction commit management
+ *              -----------------------------
+ */
+
+/*
+ * NAME:        txCommit()
+ *
+ * FUNCTION:    commit the changes to the objects specified in
+ *              clist.  For journalled segments only the
+ *              changes of the caller are committed, ie by tid.
+ *              for non-journalled segments the data are flushed to
+ *              disk and then the change to the disk inode and indirect
+ *              blocks committed (so blocks newly allocated to the
+ *              segment will be made a part of the segment atomically).
+ *
+ *              all of the segments specified in clist must be in
+ *              one file system. no more than 6 segments are needed
+ *              to handle all unix svcs.
+ *
+ *              if the i_nlink field (i.e. disk inode link count)
+ *              is zero, and the type of inode is a regular file or
+ *              directory, or symbolic link , the inode is truncated
+ *              to zero length. the truncation is committed but the
+ *              VM resources are unaffected until it is closed (see
+ *              iput and iclose).
+ *
+ * PARAMETER:
+ *
+ * RETURN:
+ *
+ * serialization:
+ *              on entry the inode lock on each segment is assumed
+ *              to be held.
+ *
+ * i/o error:
+ */
+int txCommit(tid_t tid,		/* transaction identifier */
+	     int nip,		/* number of inodes to commit */
+	     struct inode **iplist,	/* list of inode to commit */
+	     int flag)
+{
+	int rc = 0, rc1 = 0;
+	commit_t cd;
+	log_t *log;
+	tblock_t *tblk;
+	lrd_t *lrd;
+	int lsn;
+	struct inode *ip;
+	struct jfs_inode_info *jfs_ip;
+	int k, n;
+	ino_t top;
+	struct super_block *sb;
+
+	jFYI(1, ("txCommit, tid = %d, flag = %d\n", tid, flag));
+	/* is read-only file system ? */
+	if (isReadOnly(iplist[0])) {
+		rc = EROFS;
+		goto TheEnd;
+	}
+
+	sb = cd.sb = iplist[0]->i_sb;
+	cd.tid = tid;
+
+	if (tid == 0)
+		tid = txBegin(sb, 0);
+	tblk = tid_to_tblock(tid);
+
+	/*
+	 * initialize commit structure
+	 */
+	log = (log_t *) JFS_SBI(sb)->log;
+	cd.log = log;
+
+	/* initialize log record descriptor in commit */
+	lrd = &cd.lrd;
+	lrd->logtid = cpu_to_le32(tblk->logtid);
+	lrd->backchain = 0;
+
+	tblk->xflag |= flag;
+
+	if ((flag & (COMMIT_FORCE | COMMIT_SYNC)) == 0)
+		tblk->xflag |= COMMIT_LAZY;
+	/*
+	 *      prepare non-journaled objects for commit
+	 *
+	 * flush data pages of non-journaled file
+	 * to prevent the file getting non-initialized disk blocks
+	 * in case of crash.
+	 * (new blocks - )
+	 */
+	cd.iplist = iplist;
+	cd.nip = nip;
+
+	/*
+	 *      acquire transaction lock on (on-disk) inodes
+	 *
+	 * update on-disk inode from in-memory inode
+	 * acquiring transaction locks for AFTER records
+	 * on the on-disk inode of file object
+	 *
+	 * sort the inodes array by inode number in descending order
+	 * to prevent deadlock when acquiring transaction lock
+	 * of on-disk inodes on multiple on-disk inode pages by
+	 * multiple concurrent transactions
+	 */
+	for (k = 0; k < cd.nip; k++) {
+		top = (cd.iplist[k])->i_ino;
+		for (n = k + 1; n < cd.nip; n++) {
+			ip = cd.iplist[n];
+			if (ip->i_ino > top) {
+				top = ip->i_ino;
+				cd.iplist[n] = cd.iplist[k];
+				cd.iplist[k] = ip;
+			}
+		}
+
+		ip = cd.iplist[k];
+		jfs_ip = JFS_IP(ip);
+
+		/*
+		 * BUGBUG - Should we call filemap_fdatasync here instead
+		 * of fsync_inode_data?
+		 * If we do, we have a deadlock condition since we may end
+		 * up recursively calling jfs_get_block with the IWRITELOCK
+		 * held.  We may be able to do away with IWRITELOCK while
+		 * committing transactions and use i_sem instead.
+		 */
+		if ((!S_ISDIR(ip->i_mode))
+		    && (tblk->flag & COMMIT_DELETE) == 0)
+			fsync_inode_data_buffers(ip);
+
+		/*
+		 * Mark inode as not dirty.  It will still be on the dirty
+		 * inode list, but we'll know not to commit it again unless
+		 * it gets marked dirty again
+		 */
+		clear_cflag(COMMIT_Dirty, ip);
+
+		/* inherit anonymous tlock(s) of inode */
+		if (jfs_ip->atlhead) {
+			lid_to_tlock(jfs_ip->atltail)->next = tblk->next;
+			tblk->next = jfs_ip->atlhead;
+			if (!tblk->last)
+				tblk->last = jfs_ip->atltail;
+			jfs_ip->atlhead = jfs_ip->atltail = 0;
+			TXN_LOCK();
+			list_del_init(&jfs_ip->anon_inode_list);
+			TXN_UNLOCK();
+		}
+
+		/*
+		 * acquire transaction lock on on-disk inode page
+		 * (become first tlock of the tblk's tlock list)
+		 */
+		if (((rc = diWrite(tid, ip))))
+			goto out;
+	}
+
+	/*
+	 *      write log records from transaction locks
+	 *
+	 * txUpdateMap() resets XAD_NEW in XAD.
+	 */
+	if ((rc = txLog(log, tblk, &cd)))
+		goto TheEnd;
+
+	/*
+	 * Ensure that inode isn't reused before
+	 * lazy commit thread finishes processing
+	 */
+	if (tblk->xflag & (COMMIT_CREATE | COMMIT_DELETE))
+		atomic_inc(&tblk->ip->i_count);
+	if (tblk->xflag & COMMIT_DELETE) {
+		ip = tblk->ip;
+		assert((ip->i_nlink == 0) && !test_cflag(COMMIT_Nolink, ip));
+		set_cflag(COMMIT_Nolink, ip);
+	}
+
+	/*
+	 *      write COMMIT log record
+	 */
+	lrd->type = cpu_to_le16(LOG_COMMIT);
+	lrd->length = 0;
+	lsn = lmLog(log, tblk, lrd, NULL);
+
+	lmGroupCommit(log, tblk);
+
+	/*
+	 *      - transaction is now committed -
+	 */
+
+	/*
+	 * force pages in careful update
+	 * (imap addressing structure update)
+	 */
+	if (flag & COMMIT_FORCE)
+		txForce(tblk);
+
+	/*
+	 *      update allocation map.
+	 *
+	 * update inode allocation map and inode:
+	 * free pager lock on memory object of inode if any.
+	 * update  block allocation map.
+	 *
+	 * txUpdateMap() resets XAD_NEW in XAD.
+	 */
+	if (tblk->xflag & COMMIT_FORCE)
+		txUpdateMap(tblk);
+
+	/*
+	 *      free transaction locks and pageout/free pages
+	 */
+	txRelease(tblk);
+
+	if ((tblk->flag & tblkGC_LAZY) == 0)
+		txUnlock(tblk, flag);
+
+
+	/*
+	 *      reset in-memory object state
+	 */
+	for (k = 0; k < cd.nip; k++) {
+		ip = cd.iplist[k];
+		jfs_ip = JFS_IP(ip);
+
+		/*
+		 * reset in-memory inode state
+		 */
+		jfs_ip->bxflag = 0;
+		jfs_ip->blid = 0;
+	}
+
+      out:
+	if (rc != 0)
+		txAbortCommit(&cd, rc);
+	else
+		rc = rc1;
+
+      TheEnd:
+	jFYI(1, ("txCommit: tid = %d, returning %d\n", tid, rc));
+	return rc;
+}
+
+
+/*
+ * NAME:        txLog()
+ *
+ * FUNCTION:    Writes AFTER log records for all lines modified
+ *              by tid for segments specified by inodes in comdata.
+ *              Code assumes only WRITELOCKS are recorded in lockwords.
+ *
+ * PARAMETERS:
+ *
+ * RETURN :
+ */
+static int txLog(log_t * log, tblock_t * tblk, commit_t * cd)
+{
+	int rc = 0;
+	struct inode *ip;
+	lid_t lid;
+	tlock_t *tlck;
+	lrd_t *lrd = &cd->lrd;
+
+	/*
+	 * write log record(s) for each tlock of transaction,
+	 */
+	for (lid = tblk->next; lid; lid = tlck->next) {
+		tlck = lid_to_tlock(lid);
+
+		tlck->flag |= tlckLOG;
+
+		/* initialize lrd common */
+		ip = tlck->ip;
+		lrd->aggregate = cpu_to_le32(kdev_t_to_nr(ip->i_dev));
+		lrd->log.redopage.fileset = cpu_to_le32(JFS_IP(ip)->fileset);
+		lrd->log.redopage.inode = cpu_to_le32(ip->i_ino);
+
+		if (tlck->mp)
+			hold_metapage(tlck->mp, 0);
+
+		/* write log record of page from the tlock */
+		switch (tlck->type & tlckTYPE) {
+		case tlckXTREE:
+			xtLog(log, tblk, lrd, tlck);
+			break;
+
+		case tlckDTREE:
+			dtLog(log, tblk, lrd, tlck);
+			break;
+
+		case tlckINODE:
+			diLog(log, tblk, lrd, tlck, cd);
+			break;
+
+		case tlckMAP:
+			mapLog(log, tblk, lrd, tlck);
+			break;
+
+		case tlckDATA:
+			dataLog(log, tblk, lrd, tlck);
+			break;
+
+		default:
+			jERROR(1, ("UFO tlock:0x%p\n", tlck));
+		}
+		if (tlck->mp)
+			release_metapage(tlck->mp);
+	}
+
+	return rc;
+}
+
+
+/*
+ *      diLog()
+ *
+ * function:    log inode tlock and format maplock to update bmap;
+ */
+int diLog(log_t * log,
+	  tblock_t * tblk, lrd_t * lrd, tlock_t * tlck, commit_t * cd)
+{
+	int rc = 0;
+	metapage_t *mp;
+	pxd_t *pxd;
+	pxdlock_t *pxdlock;
+
+	mp = tlck->mp;
+
+	/* initialize as REDOPAGE record format */
+	lrd->log.redopage.type = cpu_to_le16(LOG_INODE);
+	lrd->log.redopage.l2linesize = cpu_to_le16(L2INODESLOTSIZE);
+
+	pxd = &lrd->log.redopage.pxd;
+
+	/*
+	 *      inode after image
+	 */
+	if (tlck->type & tlckENTRY) {
+		/* log after-image for logredo(): */
+		lrd->type = cpu_to_le16(LOG_REDOPAGE);
+//              *pxd = mp->cm_pxd;
+		PXDaddress(pxd, mp->index);
+		PXDlength(pxd,
+			  mp->logical_size >> tblk->sb->s_blocksize_bits);
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+
+		/* mark page as homeward bound */
+		tlck->flag |= tlckWRITEPAGE;
+	} else if (tlck->type & tlckFREE) {
+		/*
+		 *      free inode extent
+		 *
+		 * (pages of the freed inode extent have been invalidated and
+		 * a maplock for free of the extent has been formatted at
+		 * txLock() time);
+		 *
+		 * the tlock had been acquired on the inode allocation map page
+		 * (iag) that specifies the freed extent, even though the map
+		 * page is not itself logged, to prevent pageout of the map
+		 * page before the log;
+		 */
+		assert(tlck->type & tlckFREE);
+
+		/* log LOG_NOREDOINOEXT of the freed inode extent for
+		 * logredo() to start NoRedoPage filters, and to update
+		 * imap and bmap for free of the extent;
+		 */
+		lrd->type = cpu_to_le16(LOG_NOREDOINOEXT);
+		/*
+		 * For the LOG_NOREDOINOEXT record, we need
+		 * to pass the IAG number and inode extent
+		 * index (within that IAG) from which the
+		 * the extent being released.  These have been
+		 * passed to us in the iplist[1] and iplist[2].
+		 */
+		lrd->log.noredoinoext.iagnum =
+		    cpu_to_le32((u32) (size_t) cd->iplist[1]);
+		lrd->log.noredoinoext.inoext_idx =
+		    cpu_to_le32((u32) (size_t) cd->iplist[2]);
+
+		pxdlock = (pxdlock_t *) & tlck->lock;
+		*pxd = pxdlock->pxd;
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+
+		/* update bmap */
+		tlck->flag |= tlckUPDATEMAP;
+
+		/* mark page as homeward bound */
+		tlck->flag |= tlckWRITEPAGE;
+	} else {
+		jERROR(2, ("diLog: UFO type tlck:0x%p\n", tlck));
+	}
+#ifdef  _JFS_WIP
+	/*
+	 *      alloc/free external EA extent
+	 *
+	 * a maplock for txUpdateMap() to update bPWMAP for alloc/free
+	 * of the extent has been formatted at txLock() time;
+	 */
+	else {
+		assert(tlck->type & tlckEA);
+
+		/* log LOG_UPDATEMAP for logredo() to update bmap for
+		 * alloc of new (and free of old) external EA extent;
+		 */
+		lrd->type = cpu_to_le16(LOG_UPDATEMAP);
+		pxdlock = (pxdlock_t *) & tlck->lock;
+		nlock = pxdlock->index;
+		for (i = 0; i < nlock; i++, pxdlock++) {
+			if (pxdlock->flag & mlckALLOCPXD)
+				lrd->log.updatemap.type =
+				    cpu_to_le16(LOG_ALLOCPXD);
+			else
+				lrd->log.updatemap.type =
+				    cpu_to_le16(LOG_FREEPXD);
+			lrd->log.updatemap.nxd = cpu_to_le16(1);
+			lrd->log.updatemap.pxd = pxdlock->pxd;
+			lrd->backchain =
+			    cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+		}
+
+		/* update bmap */
+		tlck->flag |= tlckUPDATEMAP;
+	}
+#endif				/* _JFS_WIP */
+
+	return rc;
+}
+
+
+/*
+ *      dataLog()
+ *
+ * function:    log data tlock
+ */
+int dataLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck)
+{
+	metapage_t *mp;
+	pxd_t *pxd;
+	int rc;
+	s64 xaddr;
+	int xflag;
+	s32 xlen;
+
+	mp = tlck->mp;
+
+	/* initialize as REDOPAGE record format */
+	lrd->log.redopage.type = cpu_to_le16(LOG_DATA);
+	lrd->log.redopage.l2linesize = cpu_to_le16(L2DATASLOTSIZE);
+
+	pxd = &lrd->log.redopage.pxd;
+
+	/* log after-image for logredo(): */
+	lrd->type = cpu_to_le16(LOG_REDOPAGE);
+
+	if (JFS_IP(tlck->ip)->next_index < MAX_INLINE_DIRTABLE_ENTRY) {
+		/*
+		 * The table has been truncated, we've must have deleted
+		 * the last entry, so don't bother logging this
+		 */
+		mp->lid = 0;
+		atomic_dec(&mp->nohomeok);
+		discard_metapage(mp);
+		tlck->mp = 0;
+		return 0;
+	}
+
+	rc = xtLookup(tlck->ip, mp->index, 1, &xflag, &xaddr, &xlen, 1);
+	if (rc || (xlen == 0)) {
+		jERROR(1, ("dataLog: can't find physical address\n"));
+		return 0;
+	}
+
+	PXDaddress(pxd, xaddr);
+	PXDlength(pxd, mp->logical_size >> tblk->sb->s_blocksize_bits);
+
+	lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+
+	/* mark page as homeward bound */
+	tlck->flag |= tlckWRITEPAGE;
+
+	return 0;
+}
+
+
+/*
+ *      dtLog()
+ *
+ * function:    log dtree tlock and format maplock to update bmap;
+ */
+void dtLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck)
+{
+	struct inode *ip;
+	metapage_t *mp;
+	pxdlock_t *pxdlock;
+	pxd_t *pxd;
+
+	ip = tlck->ip;
+	mp = tlck->mp;
+
+	/* initialize as REDOPAGE/NOREDOPAGE record format */
+	lrd->log.redopage.type = cpu_to_le16(LOG_DTREE);
+	lrd->log.redopage.l2linesize = cpu_to_le16(L2DTSLOTSIZE);
+
+	pxd = &lrd->log.redopage.pxd;
+
+	if (tlck->type & tlckBTROOT)
+		lrd->log.redopage.type |= cpu_to_le16(LOG_BTROOT);
+
+	/*
+	 *      page extension via relocation: entry insertion;
+	 *      page extension in-place: entry insertion;
+	 *      new right page from page split, reinitialized in-line
+	 *      root from root page split: entry insertion;
+	 */
+	if (tlck->type & (tlckNEW | tlckEXTEND)) {
+		/* log after-image of the new page for logredo():
+		 * mark log (LOG_NEW) for logredo() to initialize
+		 * freelist and update bmap for alloc of the new page;
+		 */
+		lrd->type = cpu_to_le16(LOG_REDOPAGE);
+		if (tlck->type & tlckEXTEND)
+			lrd->log.redopage.type |= cpu_to_le16(LOG_EXTEND);
+		else
+			lrd->log.redopage.type |= cpu_to_le16(LOG_NEW);
+//              *pxd = mp->cm_pxd;
+		PXDaddress(pxd, mp->index);
+		PXDlength(pxd,
+			  mp->logical_size >> tblk->sb->s_blocksize_bits);
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+
+		/* format a maplock for txUpdateMap() to update bPMAP for
+		 * alloc of the new page;
+		 */
+		if (tlck->type & tlckBTROOT)
+			return;
+		tlck->flag |= tlckUPDATEMAP;
+		pxdlock = (pxdlock_t *) & tlck->lock;
+		pxdlock->flag = mlckALLOCPXD;
+		pxdlock->pxd = *pxd;
+
+		pxdlock->index = 1;
+
+		/* mark page as homeward bound */
+		tlck->flag |= tlckWRITEPAGE;
+		return;
+	}
+
+	/*
+	 *      entry insertion/deletion,
+	 *      sibling page link update (old right page before split);
+	 */
+	if (tlck->type & (tlckENTRY | tlckRELINK)) {
+		/* log after-image for logredo(): */
+		lrd->type = cpu_to_le16(LOG_REDOPAGE);
+		PXDaddress(pxd, mp->index);
+		PXDlength(pxd,
+			  mp->logical_size >> tblk->sb->s_blocksize_bits);
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+
+		/* mark page as homeward bound */
+		tlck->flag |= tlckWRITEPAGE;
+		return;
+	}
+
+	/*
+	 *      page deletion: page has been invalidated
+	 *      page relocation: source extent
+	 *
+	 *      a maplock for free of the page has been formatted
+	 *      at txLock() time);
+	 */
+	if (tlck->type & (tlckFREE | tlckRELOCATE)) {
+		/* log LOG_NOREDOPAGE of the deleted page for logredo()
+		 * to start NoRedoPage filter and to update bmap for free
+		 * of the deletd page
+		 */
+		lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
+		pxdlock = (pxdlock_t *) & tlck->lock;
+		*pxd = pxdlock->pxd;
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+
+		/* a maplock for txUpdateMap() for free of the page
+		 * has been formatted at txLock() time;
+		 */
+		tlck->flag |= tlckUPDATEMAP;
+	}
+	return;
+}
+
+
+/*
+ *      xtLog()
+ *
+ * function:    log xtree tlock and format maplock to update bmap;
+ */
+void xtLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck)
+{
+	struct inode *ip;
+	metapage_t *mp;
+	xtpage_t *p;
+	xtlock_t *xtlck;
+	maplock_t *maplock;
+	xdlistlock_t *xadlock;
+	pxdlock_t *pxdlock;
+	pxd_t *pxd;
+	int next, lwm, hwm;
+
+	ip = tlck->ip;
+	mp = tlck->mp;
+
+	/* initialize as REDOPAGE/NOREDOPAGE record format */
+	lrd->log.redopage.type = cpu_to_le16(LOG_XTREE);
+	lrd->log.redopage.l2linesize = cpu_to_le16(L2XTSLOTSIZE);
+
+	pxd = &lrd->log.redopage.pxd;
+
+	if (tlck->type & tlckBTROOT) {
+		lrd->log.redopage.type |= cpu_to_le16(LOG_BTROOT);
+		p = &JFS_IP(ip)->i_xtroot;
+		if (S_ISDIR(ip->i_mode))
+			lrd->log.redopage.type |=
+			    cpu_to_le16(LOG_DIR_XTREE);
+	} else
+		p = (xtpage_t *) mp->data;
+	next = le16_to_cpu(p->header.nextindex);
+
+	xtlck = (xtlock_t *) & tlck->lock;
+
+	maplock = (maplock_t *) & tlck->lock;
+	xadlock = (xdlistlock_t *) maplock;
+
+	/*
+	 *      entry insertion/extension;
+	 *      sibling page link update (old right page before split);
+	 */
+	if (tlck->type & (tlckNEW | tlckGROW | tlckRELINK)) {
+		/* log after-image for logredo():
+		 * logredo() will update bmap for alloc of new/extended
+		 * extents (XAD_NEW|XAD_EXTEND) of XAD[lwm:next) from
+		 * after-image of XADlist;
+		 * logredo() resets (XAD_NEW|XAD_EXTEND) flag when
+		 * applying the after-image to the meta-data page.
+		 */
+		lrd->type = cpu_to_le16(LOG_REDOPAGE);
+//              *pxd = mp->cm_pxd;
+		PXDaddress(pxd, mp->index);
+		PXDlength(pxd,
+			  mp->logical_size >> tblk->sb->s_blocksize_bits);
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+
+		/* format a maplock for txUpdateMap() to update bPMAP
+		 * for alloc of new/extended extents of XAD[lwm:next)
+		 * from the page itself;
+		 * txUpdateMap() resets (XAD_NEW|XAD_EXTEND) flag.
+		 */
+		lwm = xtlck->lwm.offset;
+		if (lwm == 0)
+			lwm = XTPAGEMAXSLOT;
+
+		if (lwm == next)
+			goto out;
+		assert(lwm < next);
+		tlck->flag |= tlckUPDATEMAP;
+		xadlock->flag = mlckALLOCXADLIST;
+		xadlock->count = next - lwm;
+		if ((xadlock->count <= 2) && (tblk->xflag & COMMIT_LAZY)) {
+			int i;
+			/*
+			 * Lazy commit may allow xtree to be modified before
+			 * txUpdateMap runs.  Copy xad into linelock to
+			 * preserve correct data.
+			 */
+			xadlock->xdlist = &xtlck->pxdlock;
+			memcpy(xadlock->xdlist, &p->xad[lwm],
+			       sizeof(xad_t) * xadlock->count);
+
+			for (i = 0; i < xadlock->count; i++)
+				p->xad[lwm + i].flag &=
+				    ~(XAD_NEW | XAD_EXTENDED);
+		} else {
+			/*
+			 * xdlist will point to into inode's xtree, ensure
+			 * that transaction is not committed lazily.
+			 */
+			xadlock->xdlist = &p->xad[lwm];
+			tblk->xflag &= ~COMMIT_LAZY;
+		}
+		jFYI(1,
+		     ("xtLog: alloc ip:0x%p mp:0x%p tlck:0x%p lwm:%d count:%d\n",
+		      tlck->ip, mp, tlck, lwm, xadlock->count));
+
+		maplock->index = 1;
+
+	      out:
+		/* mark page as homeward bound */
+		tlck->flag |= tlckWRITEPAGE;
+
+		return;
+	}
+
+	/*
+	 *      page deletion: file deletion/truncation (ref. xtTruncate())
+	 *
+	 * (page will be invalidated after log is written and bmap
+	 * is updated from the page);
+	 */
+	if (tlck->type & tlckFREE) {
+		/* LOG_NOREDOPAGE log for NoRedoPage filter:
+		 * if page free from file delete, NoRedoFile filter from
+		 * inode image of zero link count will subsume NoRedoPage
+		 * filters for each page;
+		 * if page free from file truncattion, write NoRedoPage
+		 * filter;
+		 *
+		 * upadte of block allocation map for the page itself:
+		 * if page free from deletion and truncation, LOG_UPDATEMAP
+		 * log for the page itself is generated from processing
+		 * its parent page xad entries;
+		 */
+		/* if page free from file truncation, log LOG_NOREDOPAGE
+		 * of the deleted page for logredo() to start NoRedoPage
+		 * filter for the page;
+		 */
+		if (tblk->xflag & COMMIT_TRUNCATE) {
+			/* write NOREDOPAGE for the page */
+			lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
+			PXDaddress(pxd, mp->index);
+			PXDlength(pxd,
+				  mp->logical_size >> tblk->sb->
+				  s_blocksize_bits);
+			lrd->backchain =
+			    cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+
+			if (tlck->type & tlckBTROOT) {
+				/* Empty xtree must be logged */
+				lrd->type = cpu_to_le16(LOG_REDOPAGE);
+				lrd->backchain =
+				    cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+			}
+		}
+
+		/* init LOG_UPDATEMAP of the freed extents
+		 * XAD[XTENTRYSTART:hwm) from the deleted page itself
+		 * for logredo() to update bmap;
+		 */
+		lrd->type = cpu_to_le16(LOG_UPDATEMAP);
+		lrd->log.updatemap.type = cpu_to_le16(LOG_FREEXADLIST);
+		xtlck = (xtlock_t *) & tlck->lock;
+		hwm = xtlck->hwm.offset;
+		lrd->log.updatemap.nxd =
+		    cpu_to_le16(hwm - XTENTRYSTART + 1);
+		/* reformat linelock for lmLog() */
+		xtlck->header.offset = XTENTRYSTART;
+		xtlck->header.length = hwm - XTENTRYSTART + 1;
+		xtlck->index = 1;
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+
+		/* format a maplock for txUpdateMap() to update bmap
+		 * to free extents of XAD[XTENTRYSTART:hwm) from the
+		 * deleted page itself;
+		 */
+		tlck->flag |= tlckUPDATEMAP;
+		xadlock->flag = mlckFREEXADLIST;
+		xadlock->count = hwm - XTENTRYSTART + 1;
+		if ((xadlock->count <= 2) && (tblk->xflag & COMMIT_LAZY)) {
+			/*
+			 * Lazy commit may allow xtree to be modified before
+			 * txUpdateMap runs.  Copy xad into linelock to
+			 * preserve correct data.
+			 */
+			xadlock->xdlist = &xtlck->pxdlock;
+			memcpy(xadlock->xdlist, &p->xad[XTENTRYSTART],
+			       sizeof(xad_t) * xadlock->count);
+		} else {
+			/*
+			 * xdlist will point to into inode's xtree, ensure
+			 * that transaction is not committed lazily unless
+			 * we're deleting the inode (unlink).  In that case
+			 * we have special logic for the inode to be
+			 * unlocked by the lazy commit thread.
+			 */
+			xadlock->xdlist = &p->xad[XTENTRYSTART];
+			if ((tblk->xflag & COMMIT_LAZY) &&
+			    (tblk->xflag & COMMIT_DELETE) &&
+			    (tblk->ip == ip))
+				set_cflag(COMMIT_Holdlock, ip);
+			else
+				tblk->xflag &= ~COMMIT_LAZY;
+		}
+		jFYI(1,
+		     ("xtLog: free ip:0x%p mp:0x%p count:%d lwm:2\n",
+		      tlck->ip, mp, xadlock->count));
+
+		maplock->index = 1;
+
+		/* mark page as invalid */
+		if (((tblk->xflag & COMMIT_PWMAP) || S_ISDIR(ip->i_mode))
+		    && !(tlck->type & tlckBTROOT))
+			tlck->flag |= tlckFREEPAGE;
+		/*
+		   else (tblk->xflag & COMMIT_PMAP)
+		   ? release the page;
+		 */
+		return;
+	}
+
+	/*
+	 *      page/entry truncation: file truncation (ref. xtTruncate())
+	 *
+	 *     |----------+------+------+---------------|
+	 *                |      |      |
+	 *                |      |     hwm - hwm before truncation
+	 *                |     next - truncation point
+	 *               lwm - lwm before truncation
+	 * header ?
+	 */
+	if (tlck->type & tlckTRUNCATE) {
+		pxd_t tpxd;	/* truncated extent of xad */
+
+		/*
+		 * For truncation the entire linelock may be used, so it would
+		 * be difficult to store xad list in linelock itself.
+		 * Therefore, we'll just force transaction to be committed
+		 * synchronously, so that xtree pages won't be changed before
+		 * txUpdateMap runs.
+		 */
+		tblk->xflag &= ~COMMIT_LAZY;
+		lwm = xtlck->lwm.offset;
+		if (lwm == 0)
+			lwm = XTPAGEMAXSLOT;
+		hwm = xtlck->hwm.offset;
+
+		/*
+		 *      write log records
+		 */
+		/*
+		 * allocate entries XAD[lwm:next]:
+		 */
+		if (lwm < next) {
+			/* log after-image for logredo():
+			 * logredo() will update bmap for alloc of new/extended
+			 * extents (XAD_NEW|XAD_EXTEND) of XAD[lwm:next) from
+			 * after-image of XADlist;
+			 * logredo() resets (XAD_NEW|XAD_EXTEND) flag when
+			 * applying the after-image to the meta-data page.
+			 */
+			lrd->type = cpu_to_le16(LOG_REDOPAGE);
+			PXDaddress(pxd, mp->index);
+			PXDlength(pxd,
+				  mp->logical_size >> tblk->sb->
+				  s_blocksize_bits);
+			lrd->backchain =
+			    cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+		}
+
+		/*
+		 * truncate entry XAD[hwm == next - 1]:
+		 */
+		if (hwm == next - 1) {
+			/* init LOG_UPDATEMAP for logredo() to update bmap for
+			 * free of truncated delta extent of the truncated
+			 * entry XAD[next - 1]:
+			 * (xtlck->pxdlock = truncated delta extent);
+			 */
+			pxdlock = (pxdlock_t *) & xtlck->pxdlock;
+			/* assert(pxdlock->type & tlckTRUNCATE); */
+			lrd->type = cpu_to_le16(LOG_UPDATEMAP);
+			lrd->log.updatemap.type = cpu_to_le16(LOG_FREEPXD);
+			lrd->log.updatemap.nxd = cpu_to_le16(1);
+			lrd->log.updatemap.pxd = pxdlock->pxd;
+			tpxd = pxdlock->pxd;	/* save to format maplock */
+			lrd->backchain =
+			    cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+		}
+
+		/*
+		 * free entries XAD[next:hwm]:
+		 */
+		if (hwm >= next) {
+			/* init LOG_UPDATEMAP of the freed extents
+			 * XAD[next:hwm] from the deleted page itself
+			 * for logredo() to update bmap;
+			 */
+			lrd->type = cpu_to_le16(LOG_UPDATEMAP);
+			lrd->log.updatemap.type =
+			    cpu_to_le16(LOG_FREEXADLIST);
+			xtlck = (xtlock_t *) & tlck->lock;
+			hwm = xtlck->hwm.offset;
+			lrd->log.updatemap.nxd =
+			    cpu_to_le16(hwm - next + 1);
+			/* reformat linelock for lmLog() */
+			xtlck->header.offset = next;
+			xtlck->header.length = hwm - next + 1;
+			xtlck->index = 1;
+			lrd->backchain =
+			    cpu_to_le32(lmLog(log, tblk, lrd, tlck));
+		}
+
+		/*
+		 *      format maplock(s) for txUpdateMap() to update bmap
+		 */
+		maplock->index = 0;
+
+		/*
+		 * allocate entries XAD[lwm:next):
+		 */
+		if (lwm < next) {
+			/* format a maplock for txUpdateMap() to update bPMAP
+			 * for alloc of new/extended extents of XAD[lwm:next)
+			 * from the page itself;
+			 * txUpdateMap() resets (XAD_NEW|XAD_EXTEND) flag.
+			 */
+			tlck->flag |= tlckUPDATEMAP;
+			xadlock->flag = mlckALLOCXADLIST;
+			xadlock->count = next - lwm;
+			xadlock->xdlist = &p->xad[lwm];
+
+			jFYI(1,
+			     ("xtLog: alloc ip:0x%p mp:0x%p count:%d lwm:%d next:%d\n",
+			      tlck->ip, mp, xadlock->count, lwm, next));
+			maplock->index++;
+			xadlock++;
+		}
+
+		/*
+		 * truncate entry XAD[hwm == next - 1]:
+		 */
+		if (hwm == next - 1) {
+			pxdlock_t *pxdlock;
+
+			/* format a maplock for txUpdateMap() to update bmap
+			 * to free truncated delta extent of the truncated
+			 * entry XAD[next - 1];
+			 * (xtlck->pxdlock = truncated delta extent);
+			 */
+			tlck->flag |= tlckUPDATEMAP;
+			pxdlock = (pxdlock_t *) xadlock;
+			pxdlock->flag = mlckFREEPXD;
+			pxdlock->count = 1;
+			pxdlock->pxd = tpxd;
+
+			jFYI(1,
+			     ("xtLog: truncate ip:0x%p mp:0x%p count:%d hwm:%d\n",
+			      ip, mp, pxdlock->count, hwm));
+			maplock->index++;
+			xadlock++;
+		}
+
+		/*
+		 * free entries XAD[next:hwm]:
+		 */
+		if (hwm >= next) {
+			/* format a maplock for txUpdateMap() to update bmap
+			 * to free extents of XAD[next:hwm] from thedeleted
+			 * page itself;
+			 */
+			tlck->flag |= tlckUPDATEMAP;
+			xadlock->flag = mlckFREEXADLIST;
+			xadlock->count = hwm - next + 1;
+			xadlock->xdlist = &p->xad[next];
+
+			jFYI(1,
+			     ("xtLog: free ip:0x%p mp:0x%p count:%d next:%d hwm:%d\n",
+			      tlck->ip, mp, xadlock->count, next, hwm));
+			maplock->index++;
+		}
+
+		/* mark page as homeward bound */
+		tlck->flag |= tlckWRITEPAGE;
+	}
+	return;
+}
+
+
+/*
+ *      mapLog()
+ *
+ * function:    log from maplock of freed data extents;
+ */
+void mapLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck)
+{
+	pxdlock_t *pxdlock;
+	int i, nlock;
+	pxd_t *pxd;
+
+	/*
+	 *      page relocation: free the source page extent
+	 *
+	 * a maplock for txUpdateMap() for free of the page
+	 * has been formatted at txLock() time saving the src
+	 * relocated page address;
+	 */
+	if (tlck->type & tlckRELOCATE) {
+		/* log LOG_NOREDOPAGE of the old relocated page
+		 * for logredo() to start NoRedoPage filter;
+		 */
+		lrd->type = cpu_to_le16(LOG_NOREDOPAGE);
+		pxdlock = (pxdlock_t *) & tlck->lock;
+		pxd = &lrd->log.redopage.pxd;
+		*pxd = pxdlock->pxd;
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+
+		/* (N.B. currently, logredo() does NOT update bmap
+		 * for free of the page itself for (LOG_XTREE|LOG_NOREDOPAGE);
+		 * if page free from relocation, LOG_UPDATEMAP log is
+		 * specifically generated now for logredo()
+		 * to update bmap for free of src relocated page;
+		 * (new flag LOG_RELOCATE may be introduced which will
+		 * inform logredo() to start NORedoPage filter and also
+		 * update block allocation map at the same time, thus
+		 * avoiding an extra log write);
+		 */
+		lrd->type = cpu_to_le16(LOG_UPDATEMAP);
+		lrd->log.updatemap.type = cpu_to_le16(LOG_FREEPXD);
+		lrd->log.updatemap.nxd = cpu_to_le16(1);
+		lrd->log.updatemap.pxd = pxdlock->pxd;
+		lrd->backchain = cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+
+		/* a maplock for txUpdateMap() for free of the page
+		 * has been formatted at txLock() time;
+		 */
+		tlck->flag |= tlckUPDATEMAP;
+		return;
+	}
+	/*
+
+	 * Otherwise it's not a relocate request
+	 *
+	 */
+	else {
+		/* log LOG_UPDATEMAP for logredo() to update bmap for
+		 * free of truncated/relocated delta extent of the data;
+		 * e.g.: external EA extent, relocated/truncated extent
+		 * from xtTailgate();
+		 */
+		lrd->type = cpu_to_le16(LOG_UPDATEMAP);
+		pxdlock = (pxdlock_t *) & tlck->lock;
+		nlock = pxdlock->index;
+		for (i = 0; i < nlock; i++, pxdlock++) {
+			if (pxdlock->flag & mlckALLOCPXD)
+				lrd->log.updatemap.type =
+				    cpu_to_le16(LOG_ALLOCPXD);
+			else
+				lrd->log.updatemap.type =
+				    cpu_to_le16(LOG_FREEPXD);
+			lrd->log.updatemap.nxd = cpu_to_le16(1);
+			lrd->log.updatemap.pxd = pxdlock->pxd;
+			lrd->backchain =
+			    cpu_to_le32(lmLog(log, tblk, lrd, NULL));
+			jFYI(1, ("mapLog: xaddr:0x%lx xlen:0x%x\n",
+				 (ulong) addressPXD(&pxdlock->pxd),
+				 lengthPXD(&pxdlock->pxd)));
+		}
+
+		/* update bmap */
+		tlck->flag |= tlckUPDATEMAP;
+	}
+}
+
+
+/*
+ *      txEA()
+ *
+ * function:    acquire maplock for EA/ACL extents or
+ *              set COMMIT_INLINE flag;
+ */
+void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea)
+{
+	tlock_t *tlck = NULL;
+	pxdlock_t *maplock = NULL, *pxdlock = NULL;
+
+	/*
+	 * format maplock for alloc of new EA extent
+	 */
+	if (newea) {
+		/* Since the newea could be a completely zeroed entry we need to
+		 * check for the two flags which indicate we should actually
+		 * commit new EA data
+		 */
+		if (newea->flag & DXD_EXTENT) {
+			tlck = txMaplock(tid, ip, tlckMAP);
+			maplock = (pxdlock_t *) & tlck->lock;
+			pxdlock = (pxdlock_t *) maplock;
+			pxdlock->flag = mlckALLOCPXD;
+			PXDaddress(&pxdlock->pxd, addressDXD(newea));
+			PXDlength(&pxdlock->pxd, lengthDXD(newea));
+			pxdlock++;
+			maplock->index = 1;
+		} else if (newea->flag & DXD_INLINE) {
+			tlck = NULL;
+
+			set_cflag(COMMIT_Inlineea, ip);
+		}
+	}
+
+	/*
+	 * format maplock for free of old EA extent
+	 */
+	if (!test_cflag(COMMIT_Nolink, ip) && oldea->flag & DXD_EXTENT) {
+		if (tlck == NULL) {
+			tlck = txMaplock(tid, ip, tlckMAP);
+			maplock = (pxdlock_t *) & tlck->lock;
+			pxdlock = (pxdlock_t *) maplock;
+			maplock->index = 0;
+		}
+		pxdlock->flag = mlckFREEPXD;
+		PXDaddress(&pxdlock->pxd, addressDXD(oldea));
+		PXDlength(&pxdlock->pxd, lengthDXD(oldea));
+		maplock->index++;
+	}
+}
+
+
+/*
+ *      txForce()
+ *
+ * function: synchronously write pages locked by transaction
+ *              after txLog() but before txUpdateMap();
+ */
+void txForce(tblock_t * tblk)
+{
+	tlock_t *tlck;
+	lid_t lid, next;
+	metapage_t *mp;
+
+	/*
+	 * reverse the order of transaction tlocks in
+	 * careful update order of address index pages
+	 * (right to left, bottom up)
+	 */
+	tlck = lid_to_tlock(tblk->next);
+	lid = tlck->next;
+	tlck->next = 0;
+	while (lid) {
+		tlck = lid_to_tlock(lid);
+		next = tlck->next;
+		tlck->next = tblk->next;
+		tblk->next = lid;
+		lid = next;
+	}
+
+	/*
+	 * synchronously write the page, and
+	 * hold the page for txUpdateMap();
+	 */
+	for (lid = tblk->next; lid; lid = next) {
+		tlck = lid_to_tlock(lid);
+		next = tlck->next;
+
+		if ((mp = tlck->mp) != NULL &&
+		    (tlck->type & tlckBTROOT) == 0) {
+			assert(mp->xflag & COMMIT_PAGE);
+
+			if (tlck->flag & tlckWRITEPAGE) {
+				tlck->flag &= ~tlckWRITEPAGE;
+
+				/* do not release page to freelist */
+				assert(atomic_read(&mp->nohomeok));
+				hold_metapage(mp, 0);
+				write_metapage(mp);
+			}
+		}
+	}
+}
+
+
+/*
+ *      txUpdateMap()
+ *
+ * function:    update persistent allocation map (and working map
+ *              if appropriate);
+ *
+ * parameter:
+ */
+static void txUpdateMap(tblock_t * tblk)
+{
+	struct inode *ip;
+	struct inode *ipimap;
+	lid_t lid;
+	tlock_t *tlck;
+	maplock_t *maplock;
+	pxdlock_t pxdlock;
+	int maptype;
+	int k, nlock;
+	metapage_t *mp = 0;
+
+	ipimap = JFS_SBI(tblk->sb)->ipimap;
+
+	maptype = (tblk->xflag & COMMIT_PMAP) ? COMMIT_PMAP : COMMIT_PWMAP;
+
+
+	/*
+	 *      update block allocation map
+	 *
+	 * update allocation state in pmap (and wmap) and
+	 * update lsn of the pmap page;
+	 */
+	/*
+	 * scan each tlock/page of transaction for block allocation/free:
+	 *
+	 * for each tlock/page of transaction, update map.
+	 *  ? are there tlock for pmap and pwmap at the same time ?
+	 */
+	for (lid = tblk->next; lid; lid = tlck->next) {
+		tlck = lid_to_tlock(lid);
+
+		if ((tlck->flag & tlckUPDATEMAP) == 0)
+			continue;
+
+		if (tlck->flag & tlckFREEPAGE) {
+			/*
+			 * Another thread may attempt to reuse freed space
+			 * immediately, so we want to get rid of the metapage
+			 * before anyone else has a chance to get it.
+			 * Lock metapage, update maps, then invalidate
+			 * the metapage.
+			 */
+			mp = tlck->mp;
+			ASSERT(mp->xflag & COMMIT_PAGE);
+			hold_metapage(mp, 0);
+		}
+
+		/*
+		 * extent list:
+		 * . in-line PXD list:
+		 * . out-of-line XAD list:
+		 */
+		maplock = (maplock_t *) & tlck->lock;
+		nlock = maplock->index;
+
+		for (k = 0; k < nlock; k++, maplock++) {
+			/*
+			 * allocate blocks in persistent map:
+			 *
+			 * blocks have been allocated from wmap at alloc time;
+			 */
+			if (maplock->flag & mlckALLOC) {
+				txAllocPMap(ipimap, maplock, tblk);
+			}
+			/*
+			 * free blocks in persistent and working map:
+			 * blocks will be freed in pmap and then in wmap;
+			 *
+			 * ? tblock specifies the PMAP/PWMAP based upon
+			 * transaction
+			 *
+			 * free blocks in persistent map:
+			 * blocks will be freed from wmap at last reference
+			 * release of the object for regular files;
+			 *
+			 * Alway free blocks from both persistent & working
+			 * maps for directories
+			 */
+			else {	/* (maplock->flag & mlckFREE) */
+
+				if (S_ISDIR(tlck->ip->i_mode))
+					txFreeMap(ipimap, maplock,
+						  tblk, COMMIT_PWMAP);
+				else
+					txFreeMap(ipimap, maplock,
+						  tblk, maptype);
+			}
+		}
+		if (tlck->flag & tlckFREEPAGE) {
+			if (!(tblk->flag & tblkGC_LAZY)) {
+				/* This is equivalent to txRelease */
+				ASSERT(mp->lid == lid);
+				tlck->mp->lid = 0;
+			}
+			assert(atomic_read(&mp->nohomeok) == 1);
+			atomic_dec(&mp->nohomeok);
+			discard_metapage(mp);
+			tlck->mp = 0;
+		}
+	}
+	/*
+	 *      update inode allocation map
+	 *
+	 * update allocation state in pmap and
+	 * update lsn of the pmap page;
+	 * update in-memory inode flag/state
+	 *
+	 * unlock mapper/write lock
+	 */
+	if (tblk->xflag & COMMIT_CREATE) {
+		ip = tblk->ip;
+
+		ASSERT(test_cflag(COMMIT_New, ip));
+		clear_cflag(COMMIT_New, ip);
+
+		diUpdatePMap(ipimap, ip->i_ino, FALSE, tblk);
+		ipimap->i_state |= I_DIRTY;
+		/* update persistent block allocation map
+		 * for the allocation of inode extent;
+		 */
+		pxdlock.flag = mlckALLOCPXD;
+		pxdlock.pxd = JFS_IP(ip)->ixpxd;
+		pxdlock.index = 1;
+		txAllocPMap(ip, (maplock_t *) & pxdlock, tblk);
+		iput(ip);
+	} else if (tblk->xflag & COMMIT_DELETE) {
+		ip = tblk->ip;
+		diUpdatePMap(ipimap, ip->i_ino, TRUE, tblk);
+		ipimap->i_state |= I_DIRTY;
+		if (test_and_clear_cflag(COMMIT_Holdlock, ip)) {
+			if (tblk->flag & tblkGC_LAZY)
+				IWRITE_UNLOCK(ip);
+		}
+		iput(ip);
+	}
+}
+
+
+/*
+ *      txAllocPMap()
+ *
+ * function: allocate from persistent map;
+ *
+ * parameter:
+ *      ipbmap  -
+ *      malock -
+ *              xad list:
+ *              pxd:
+ *
+ *      maptype -
+ *              allocate from persistent map;
+ *              free from persistent map;
+ *              (e.g., tmp file - free from working map at releae
+ *               of last reference);
+ *              free from persistent and working map;
+ *
+ *      lsn     - log sequence number;
+ */
+static void txAllocPMap(struct inode *ip, maplock_t * maplock,
+			tblock_t * tblk)
+{
+	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+	xdlistlock_t *xadlistlock;
+	xad_t *xad;
+	s64 xaddr;
+	int xlen;
+	pxdlock_t *pxdlock;
+	xdlistlock_t *pxdlistlock;
+	pxd_t *pxd;
+	int n;
+
+	/*
+	 * allocate from persistent map;
+	 */
+	if (maplock->flag & mlckALLOCXADLIST) {
+		xadlistlock = (xdlistlock_t *) maplock;
+		xad = xadlistlock->xdlist;
+		for (n = 0; n < xadlistlock->count; n++, xad++) {
+			if (xad->flag & (XAD_NEW | XAD_EXTENDED)) {
+				xaddr = addressXAD(xad);
+				xlen = lengthXAD(xad);
+				dbUpdatePMap(ipbmap, FALSE, xaddr,
+					     (s64) xlen, tblk);
+				xad->flag &= ~(XAD_NEW | XAD_EXTENDED);
+				jFYI(1,
+				     ("allocPMap: xaddr:0x%lx xlen:%d\n",
+				      (ulong) xaddr, xlen));
+			}
+		}
+	} else if (maplock->flag & mlckALLOCPXD) {
+		pxdlock = (pxdlock_t *) maplock;
+		xaddr = addressPXD(&pxdlock->pxd);
+		xlen = lengthPXD(&pxdlock->pxd);
+		dbUpdatePMap(ipbmap, FALSE, xaddr, (s64) xlen, tblk);
+		jFYI(1,
+		     ("allocPMap: xaddr:0x%lx xlen:%d\n", (ulong) xaddr,
+		      xlen));
+	} else {		/* (maplock->flag & mlckALLOCPXDLIST) */
+
+		pxdlistlock = (xdlistlock_t *) maplock;
+		pxd = pxdlistlock->xdlist;
+		for (n = 0; n < pxdlistlock->count; n++, pxd++) {
+			xaddr = addressPXD(pxd);
+			xlen = lengthPXD(pxd);
+			dbUpdatePMap(ipbmap, FALSE, xaddr, (s64) xlen,
+				     tblk);
+			jFYI(1,
+			     ("allocPMap: xaddr:0x%lx xlen:%d\n",
+			      (ulong) xaddr, xlen));
+		}
+	}
+}
+
+
+/*
+ *      txFreeMap()
+ *
+ * function:    free from persistent and/or working map;
+ *
+ * todo: optimization
+ */
+void txFreeMap(struct inode *ip,
+	       maplock_t * maplock, tblock_t * tblk, int maptype)
+{
+	struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
+	xdlistlock_t *xadlistlock;
+	xad_t *xad;
+	s64 xaddr;
+	int xlen;
+	pxdlock_t *pxdlock;
+	xdlistlock_t *pxdlistlock;
+	pxd_t *pxd;
+	int n;
+
+	jFYI(1,
+	     ("txFreeMap: tblk:0x%p maplock:0x%p maptype:0x%x\n",
+	      tblk, maplock, maptype));
+
+	/*
+	 * free from persistent map;
+	 */
+	if (maptype == COMMIT_PMAP || maptype == COMMIT_PWMAP) {
+		if (maplock->flag & mlckFREEXADLIST) {
+			xadlistlock = (xdlistlock_t *) maplock;
+			xad = xadlistlock->xdlist;
+			for (n = 0; n < xadlistlock->count; n++, xad++) {
+				if (!(xad->flag & XAD_NEW)) {
+					xaddr = addressXAD(xad);
+					xlen = lengthXAD(xad);
+					dbUpdatePMap(ipbmap, TRUE, xaddr,
+						     (s64) xlen, tblk);
+					jFYI(1,
+					     ("freePMap: xaddr:0x%lx xlen:%d\n",
+					      (ulong) xaddr, xlen));
+				}
+			}
+		} else if (maplock->flag & mlckFREEPXD) {
+			pxdlock = (pxdlock_t *) maplock;
+			xaddr = addressPXD(&pxdlock->pxd);
+			xlen = lengthPXD(&pxdlock->pxd);
+			dbUpdatePMap(ipbmap, TRUE, xaddr, (s64) xlen,
+				     tblk);
+			jFYI(1,
+			     ("freePMap: xaddr:0x%lx xlen:%d\n",
+			      (ulong) xaddr, xlen));
+		} else {	/* (maplock->flag & mlckALLOCPXDLIST) */
+
+			pxdlistlock = (xdlistlock_t *) maplock;
+			pxd = pxdlistlock->xdlist;
+			for (n = 0; n < pxdlistlock->count; n++, pxd++) {
+				xaddr = addressPXD(pxd);
+				xlen = lengthPXD(pxd);
+				dbUpdatePMap(ipbmap, TRUE, xaddr,
+					     (s64) xlen, tblk);
+				jFYI(1,
+				     ("freePMap: xaddr:0x%lx xlen:%d\n",
+				      (ulong) xaddr, xlen));
+			}
+		}
+	}
+
+	/*
+	 * free from working map;
+	 */
+	if (maptype == COMMIT_PWMAP || maptype == COMMIT_WMAP) {
+		if (maplock->flag & mlckFREEXADLIST) {
+			xadlistlock = (xdlistlock_t *) maplock;
+			xad = xadlistlock->xdlist;
+			for (n = 0; n < xadlistlock->count; n++, xad++) {
+				xaddr = addressXAD(xad);
+				xlen = lengthXAD(xad);
+				dbFree(ip, xaddr, (s64) xlen);
+				xad->flag = 0;
+				jFYI(1,
+				     ("freeWMap: xaddr:0x%lx xlen:%d\n",
+				      (ulong) xaddr, xlen));
+			}
+		} else if (maplock->flag & mlckFREEPXD) {
+			pxdlock = (pxdlock_t *) maplock;
+			xaddr = addressPXD(&pxdlock->pxd);
+			xlen = lengthPXD(&pxdlock->pxd);
+			dbFree(ip, xaddr, (s64) xlen);
+			jFYI(1,
+			     ("freeWMap: xaddr:0x%lx xlen:%d\n",
+			      (ulong) xaddr, xlen));
+		} else {	/* (maplock->flag & mlckFREEPXDLIST) */
+
+			pxdlistlock = (xdlistlock_t *) maplock;
+			pxd = pxdlistlock->xdlist;
+			for (n = 0; n < pxdlistlock->count; n++, pxd++) {
+				xaddr = addressPXD(pxd);
+				xlen = lengthPXD(pxd);
+				dbFree(ip, xaddr, (s64) xlen);
+				jFYI(1,
+				     ("freeWMap: xaddr:0x%lx xlen:%d\n",
+				      (ulong) xaddr, xlen));
+			}
+		}
+	}
+}
+
+
+/*
+ *      txFreelock()
+ *
+ * function:    remove tlock from inode anonymous locklist
+ */
+void txFreelock(struct inode *ip)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	tlock_t *xtlck, *tlck;
+	lid_t xlid = 0, lid;
+
+	if (!jfs_ip->atlhead)
+		return;
+
+	xtlck = (tlock_t *) &jfs_ip->atlhead;
+
+	while ((lid = xtlck->next)) {
+		tlck = lid_to_tlock(lid);
+		if (tlck->flag & tlckFREELOCK) {
+			xtlck->next = tlck->next;
+			txLockFree(lid);
+		} else {
+			xtlck = tlck;
+			xlid = lid;
+		}
+	}
+
+	if (jfs_ip->atlhead)
+		jfs_ip->atltail = xlid;
+	else {
+		jfs_ip->atltail = 0;
+		/*
+		 * If inode was on anon_list, remove it
+		 */
+		TXN_LOCK();
+		list_del_init(&jfs_ip->anon_inode_list);
+		TXN_UNLOCK();
+	}
+}
+
+
+/*
+ *      txAbort()
+ *
+ * function: abort tx before commit;
+ *
+ * frees line-locks and segment locks for all
+ * segments in comdata structure.
+ * Optionally sets state of file-system to FM_DIRTY in super-block.
+ * log age of page-frames in memory for which caller has
+ * are reset to 0 (to avoid logwarap).
+ */
+void txAbort(tid_t tid, int dirty)
+{
+	lid_t lid, next;
+	metapage_t *mp;
+	tblock_t *tblk = tid_to_tblock(tid);
+
+	jEVENT(1, ("txAbort: tid:%d dirty:0x%x\n", tid, dirty));
+
+	/*
+	 * free tlocks of the transaction
+	 */
+	for (lid = tblk->next; lid; lid = next) {
+		next = lid_to_tlock(lid)->next;
+
+		mp = lid_to_tlock(lid)->mp;
+
+		if (mp) {
+			mp->lid = 0;
+
+			/*
+			 * reset lsn of page to avoid logwarap:
+			 *
+			 * (page may have been previously committed by another
+			 * transaction(s) but has not been paged, i.e.,
+			 * it may be on logsync list even though it has not
+			 * been logged for the current tx.)
+			 */
+			if (mp->xflag & COMMIT_PAGE && mp->lsn)
+				LogSyncRelease(mp);
+		}
+		/* insert tlock at head of freelist */
+		TXN_LOCK();
+		txLockFree(lid);
+		TXN_UNLOCK();
+	}
+
+	/* caller will free the transaction block */
+
+	tblk->next = tblk->last = 0;
+
+	/*
+	 * mark filesystem dirty
+	 */
+	if (dirty)
+		updateSuper(tblk->sb, FM_DIRTY);
+
+	return;
+}
+
+
+/*
+ *      txAbortCommit()
+ *
+ * function: abort commit.
+ *
+ * frees tlocks of transaction; line-locks and segment locks for all
+ * segments in comdata structure. frees malloc storage
+ * sets state of file-system to FM_MDIRTY in super-block.
+ * log age of page-frames in memory for which caller has
+ * are reset to 0 (to avoid logwarap).
+ */
+void txAbortCommit(commit_t * cd, int exval)
+{
+	tblock_t *tblk;
+	tid_t tid;
+	lid_t lid, next;
+	metapage_t *mp;
+
+	assert(exval == EIO || exval == ENOMEM);
+	jEVENT(1, ("txAbortCommit: cd:0x%p\n", cd));
+
+	/*
+	 * free tlocks of the transaction
+	 */
+	tid = cd->tid;
+	tblk = tid_to_tblock(tid);
+	for (lid = tblk->next; lid; lid = next) {
+		next = lid_to_tlock(lid)->next;
+
+		mp = lid_to_tlock(lid)->mp;
+		if (mp) {
+			mp->lid = 0;
+
+			/*
+			 * reset lsn of page to avoid logwarap;
+			 */
+			if (mp->xflag & COMMIT_PAGE)
+				LogSyncRelease(mp);
+		}
+
+		/* insert tlock at head of freelist */
+		TXN_LOCK();
+		txLockFree(lid);
+		TXN_UNLOCK();
+	}
+
+	tblk->next = tblk->last = 0;
+
+	/* free the transaction block */
+	txEnd(tid);
+
+	/*
+	 * mark filesystem dirty
+	 */
+	updateSuper(cd->sb, FM_DIRTY);
+}
+
+
+/*
+ *      txLazyCommit(void)
+ *
+ *	All transactions except those changing ipimap (COMMIT_FORCE) are
+ *	processed by this routine.  This insures that the inode and block
+ *	allocation maps are updated in order.  For synchronous transactions,
+ *	let the user thread finish processing after txUpdateMap() is called.
+ */
+void txLazyCommit(tblock_t * tblk)
+{
+	log_t *log;
+
+	while (((tblk->flag & tblkGC_READY) == 0) &&
+	       ((tblk->flag & tblkGC_UNLOCKED) == 0)) {
+		/* We must have gotten ahead of the user thread
+		 */
+		jFYI(1,
+		     ("jfs_lazycommit: tblk 0x%p not unlocked\n", tblk));
+		schedule();
+	}
+
+	jFYI(1, ("txLazyCommit: processing tblk 0x%p\n", tblk));
+
+	txUpdateMap(tblk);
+
+	log = (log_t *) JFS_SBI(tblk->sb)->log;
+
+	spin_lock_irq(&log->gclock);	// LOGGC_LOCK
+
+	tblk->flag |= tblkGC_COMMITTED;
+
+	if ((tblk->flag & tblkGC_READY) || (tblk->flag & tblkGC_LAZY))
+		log->gcrtc--;
+
+	if (tblk->flag & tblkGC_READY)
+		wake_up(&tblk->gcwait);	// LOGGC_WAKEUP
+
+	spin_unlock_irq(&log->gclock);	// LOGGC_UNLOCK
+
+	if (tblk->flag & tblkGC_LAZY) {
+		txUnlock(tblk, 0);
+		tblk->flag &= ~tblkGC_LAZY;
+		txEnd(tblk - TxBlock);	/* Convert back to tid */
+	}
+
+	jFYI(1, ("txLazyCommit: done: tblk = 0x%p\n", tblk));
+}
+
+/*
+ *      jfs_lazycommit(void)
+ *
+ *	To be run as a kernel daemon.  If lbmIODone is called in an interrupt
+ *	context, or where blocking is not wanted, this routine will process
+ *	committed transactions from the unlock queue.
+ */
+int jfs_lazycommit(void)
+{
+	int WorkDone;
+	tblock_t *tblk;
+	unsigned long flags;
+
+	lock_kernel();
+
+	daemonize();
+	current->tty = NULL;
+	strcpy(current->comm, "jfsCommit");
+
+	unlock_kernel();
+
+	jfsCommitTask = current;
+
+	spin_lock_irq(&current->sigmask_lock);
+	siginitsetinv(&current->blocked,
+		      sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP)
+		      | sigmask(SIGCONT));
+	spin_unlock_irq(&current->sigmask_lock);
+
+	LAZY_LOCK_INIT();
+	TxAnchor.unlock_queue = TxAnchor.unlock_tail = 0;
+
+	complete(&jfsIOwait);
+
+	do {
+restart:
+		WorkDone = 0;
+		while ((tblk = TxAnchor.unlock_queue)) {
+			/*
+			 * We can't get ahead of user thread.  Spinning is
+			 * simpler than blocking/waking.  We shouldn't spin
+			 * very long, since user thread shouldn't be blocking
+			 * between lmGroupCommit & txEnd.
+			 */
+			WorkDone = 1;
+
+			LAZY_LOCK(flags);
+			/*
+			 * Remove first transaction from queue
+			 */
+			TxAnchor.unlock_queue = tblk->cqnext;
+			tblk->cqnext = 0;
+			if (TxAnchor.unlock_tail == tblk)
+				TxAnchor.unlock_tail = 0;
+
+			LAZY_UNLOCK(flags);
+			txLazyCommit(tblk);
+
+			/*
+			 * We can be running indefinately if other processors
+			 * are adding transactions to this list
+			 */
+			if (need_resched()) {
+				current->state = TASK_RUNNING;
+				schedule();
+			}
+		}
+
+		if (WorkDone)
+			goto restart;
+		
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule();
+	} while (!jfs_thread_stopped());
+
+	if (TxAnchor.unlock_queue)
+		jERROR(1, ("jfs_lazycommit being killed with pending transactions!\n"));
+	else
+		jFYI(1, ("jfs_lazycommit being killed\n"));
+	complete(&jfsIOwait);
+	return 0;
+}
+
+void txLazyUnlock(tblock_t * tblk)
+{
+	unsigned long flags;
+
+	LAZY_LOCK(flags);
+
+	if (TxAnchor.unlock_tail)
+		TxAnchor.unlock_tail->cqnext = tblk;
+	else
+		TxAnchor.unlock_queue = tblk;
+	TxAnchor.unlock_tail = tblk;
+	tblk->cqnext = 0;
+	LAZY_UNLOCK(flags);
+	wake_up_process(jfsCommitTask);
+}
+
+static void LogSyncRelease(metapage_t * mp)
+{
+	log_t *log = mp->log;
+
+	assert(atomic_read(&mp->nohomeok));
+	assert(log);
+	atomic_dec(&mp->nohomeok);
+
+	if (atomic_read(&mp->nohomeok))
+		return;
+
+	hold_metapage(mp, 0);
+
+	LOGSYNC_LOCK(log);
+	mp->log = NULL;
+	mp->lsn = 0;
+	mp->clsn = 0;
+	log->count--;
+	list_del_init(&mp->synclist);
+	LOGSYNC_UNLOCK(log);
+
+	release_metapage(mp);
+}
+
+/*
+ *      jfs_sync(void)
+ *
+ *	To be run as a kernel daemon.  This is awakened when tlocks run low.
+ *	We write any inodes that have anonymous tlocks so they will become
+ *	available.
+ */
+int jfs_sync(void)
+{
+	struct inode *ip;
+	struct jfs_inode_info *jfs_ip;
+
+	lock_kernel();
+
+	daemonize();
+	current->tty = NULL;
+	strcpy(current->comm, "jfsSync");
+
+	unlock_kernel();
+
+	jfsSyncTask = current;
+
+	spin_lock_irq(&current->sigmask_lock);
+	siginitsetinv(&current->blocked,
+		      sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP)
+		      | sigmask(SIGCONT));
+	spin_unlock_irq(&current->sigmask_lock);
+
+	complete(&jfsIOwait);
+
+	do {
+		/*
+		 * write each inode on the anonymous inode list
+		 */
+		TXN_LOCK();
+		while (TlocksLow && !list_empty(&TxAnchor.anon_list)) {
+			jfs_ip = list_entry(TxAnchor.anon_list.next,
+					    struct jfs_inode_info,
+					    anon_inode_list);
+			ip = &jfs_ip->vfs_inode;
+
+			/*
+			 * We must release the TXN_LOCK since our
+			 * IWRITE_TRYLOCK implementation may still block
+			 */
+			TXN_UNLOCK();
+			if (IWRITE_TRYLOCK(ip)) {
+				/*
+				 * inode will be removed from anonymous list
+				 * when it is committed
+				 */
+				jfs_commit_inode(ip, 0);
+				IWRITE_UNLOCK(ip);
+				/*
+				 * Just to be safe.  I don't know how
+				 * long we can run without blocking
+				 */
+				if (need_resched()) {
+					current->state = TASK_RUNNING;
+					schedule();
+				}
+				TXN_LOCK();
+			} else {
+				/* We can't get the write lock.  It may
+				 * be held by a thread waiting for tlock's
+				 * so let's not block here.  Save it to
+				 * put back on the anon_list.
+				 */
+
+				/*
+				 * We released TXN_LOCK, let's make sure
+				 * this inode is still there
+				 */
+				TXN_LOCK();
+				if (TxAnchor.anon_list.next !=
+				    &jfs_ip->anon_inode_list)
+					continue;
+
+				/* Take off anon_list */
+				list_del(&jfs_ip->anon_inode_list);
+
+				/* Put on anon_list2 */
+				list_add(&jfs_ip->anon_inode_list,
+					 &TxAnchor.anon_list2);
+			}
+		}
+		/* Add anon_list2 back to anon_list */
+		if (!list_empty(&TxAnchor.anon_list2)) {
+			list_splice(&TxAnchor.anon_list2, &TxAnchor.anon_list);
+			INIT_LIST_HEAD(&TxAnchor.anon_list2);
+		}
+		TXN_UNLOCK();
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule();
+	} while (!jfs_thread_stopped());
+
+	jFYI(1, ("jfs_sync being killed\n"));
+	complete(&jfsIOwait);
+	return 0;
+}
+
+#if CONFIG_PROC_FS
+int jfs_txanchor_read(char *buffer, char **start, off_t offset, int length,
+		      int *eof, void *data)
+{
+	int len = 0;
+	off_t begin;
+	char *freewait;
+	char *freelockwait;
+	char *lowlockwait;
+
+	freewait =
+	    waitqueue_active(&TxAnchor.freewait) ? "active" : "empty";
+	freelockwait =
+	    waitqueue_active(&TxAnchor.freelockwait) ? "active" : "empty";
+	lowlockwait =
+	    waitqueue_active(&TxAnchor.lowlockwait) ? "active" : "empty";
+
+	len += sprintf(buffer,
+		       "JFS TxAnchor\n"
+		       "============\n"
+		       "freetid = %d\n"
+		       "freewait = %s\n"
+		       "freelock = %d\n"
+		       "freelockwait = %s\n"
+		       "lowlockwait = %s\n"
+		       "tlocksInUse = %d\n"
+		       "unlock_queue = 0x%p\n"
+		       "unlock_tail = 0x%p\n",
+		       TxAnchor.freetid,
+		       freewait,
+		       TxAnchor.freelock,
+		       freelockwait,
+		       lowlockwait,
+		       TxAnchor.tlocksInUse,
+		       TxAnchor.unlock_queue,
+		       TxAnchor.unlock_tail);
+
+	begin = offset;
+	*start = buffer + begin;
+	len -= begin;
+
+	if (len > length)
+		len = length;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+#endif
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_txnmgr.h linux-2.5.6-pre2/fs/jfs/jfs_txnmgr.h
--- linux-2.5.6-pre1/fs/jfs/jfs_txnmgr.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_txnmgr.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,315 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Change History :
+ *
+ */
+
+#ifndef _H_JFS_TXNMGR
+#define _H_JFS_TXNMGR
+/*
+ *	jfs_txnmgr.h: transaction manager
+ */
+
+#include "jfs_logmgr.h"
+
+/*
+ * Hide implementation of TxBlock and TxLock
+ */
+#define tid_to_tblock(tid) (&TxBlock[tid])
+
+#define lid_to_tlock(lid) (&TxLock[lid])
+
+/*
+ *	transaction block
+ */
+typedef struct tblock {
+	/*
+	 * tblock_t and jbuf_t common area: struct logsyncblk
+	 *
+	 * the following 5 fields are the same as struct logsyncblk
+	 * which is common to tblock and jbuf to form logsynclist
+	 */
+	u16 xflag;		/* tx commit type */
+	u16 flag;		/* tx commit state */
+	lid_t dummy;		/* Must keep structures common */
+	s32 lsn;		/* recovery lsn */
+	struct list_head synclist;	/* logsynclist link */
+
+	/* lock management */
+	struct super_block *sb;	/* 4: super block */
+	lid_t next;		/* 2: index of first tlock of tid */
+	lid_t last;		/* 2: index of last tlock of tid */
+	wait_queue_head_t waitor;	/* 4: tids waiting on this tid */
+
+	/* log management */
+	u32 logtid;		/* 4: log transaction id */
+				/* (32) */
+
+	/* commit management */
+	struct tblock *cqnext;	/* 4: commit queue link */
+	s32 clsn;		/* 4: commit lsn */
+	struct lbuf *bp;	/* 4: */
+	s32 pn;			/* 4: commit record log page number */
+	s32 eor;		/* 4: commit record eor */
+	wait_queue_head_t gcwait;	/* 4: group commit event list:
+					 *    ready transactions wait on this
+					 *    event for group commit completion.
+					 */
+	struct inode *ip;	/* 4: inode being created or deleted */
+	s32 rsrvd;		/* 4: */
+} tblock_t;			/* (64) */
+
+extern struct tblock *TxBlock;	/* transaction block table */
+
+/* commit flags: tblk->xflag */
+#define	COMMIT_SYNC	0x0001	/* synchronous commit */
+#define	COMMIT_FORCE	0x0002	/* force pageout at end of commit */
+#define	COMMIT_FLUSH	0x0004	/* init flush at end of commit */
+#define COMMIT_MAP	0x00f0
+#define	COMMIT_PMAP	0x0010	/* update pmap */
+#define	COMMIT_WMAP	0x0020	/* update wmap */
+#define	COMMIT_PWMAP	0x0040	/* update pwmap */
+#define	COMMIT_FREE	0x0f00
+#define	COMMIT_DELETE	0x0100	/* inode delete */
+#define	COMMIT_TRUNCATE	0x0200	/* file truncation */
+#define	COMMIT_CREATE	0x0400	/* inode create */
+#define	COMMIT_LAZY	0x0800	/* lazy commit */
+#define COMMIT_PAGE	0x1000	/* Identifies element as metapage */
+#define COMMIT_INODE	0x2000	/* Identifies element as inode */
+
+/* group commit flags tblk->flag: see jfs_logmgr.h */
+
+/*
+ *	transaction lock
+ */
+typedef struct tlock {
+	lid_t next;		/* index next lockword on tid locklist
+				 *          next lockword on freelist
+				 */
+	tid_t tid;		/* transaction id holding lock */
+
+	u16 flag;		/* 2: lock control */
+	u16 type;		/* 2: log type */
+
+	struct metapage *mp;	/* 4: object page buffer locked */
+	struct inode *ip;	/* 4: object */
+	/* (16) */
+
+	s16 lock[24];		/* 48: overlay area */
+} tlock_t;			/* (64) */
+
+extern struct tlock *TxLock;	/* transaction lock table */
+
+/*
+ * tlock flag
+ */
+/* txLock state */
+#define tlckPAGELOCK		0x8000
+#define tlckINODELOCK		0x4000
+#define tlckLINELOCK		0x2000
+#define tlckINLINELOCK		0x1000
+/* lmLog state */
+#define tlckLOG			0x0800
+/* updateMap state */
+#define	tlckUPDATEMAP		0x0080
+/* freeLock state */
+#define tlckFREELOCK		0x0008
+#define tlckWRITEPAGE		0x0004
+#define tlckFREEPAGE		0x0002
+
+/*
+ * tlock type
+ */
+#define	tlckTYPE		0xfe00
+#define	tlckINODE		0x8000
+#define	tlckXTREE		0x4000
+#define	tlckDTREE		0x2000
+#define	tlckMAP			0x1000
+#define	tlckEA			0x0800
+#define	tlckACL			0x0400
+#define	tlckDATA		0x0200
+#define	tlckBTROOT		0x0100
+
+#define	tlckOPERATION		0x00ff
+#define tlckGROW		0x0001	/* file grow */
+#define tlckREMOVE		0x0002	/* file delete */
+#define tlckTRUNCATE		0x0004	/* file truncate */
+#define tlckRELOCATE		0x0008	/* file/directory relocate */
+#define tlckENTRY		0x0001	/* directory insert/delete */
+#define tlckEXTEND		0x0002	/* directory extend in-line */
+#define tlckSPLIT		0x0010	/* splited page */
+#define tlckNEW			0x0020	/* new page from split */
+#define tlckFREE		0x0040	/* free page */
+#define tlckRELINK		0x0080	/* update sibling pointer */
+
+/*
+ *	linelock for lmLog()
+ *
+ * note: linelock_t and its variations are overlaid
+ * at tlock.lock: watch for alignment;
+ */
+typedef struct {
+	u8 offset;		/* 1: */
+	u8 length;		/* 1: */
+} lv_t;				/* (2) */
+
+#define	TLOCKSHORT	20
+#define	TLOCKLONG	28
+
+typedef struct {
+	u16 next;		/* 2: next linelock */
+
+	s8 maxcnt;		/* 1: */
+	s8 index;		/* 1: */
+
+	u16 flag;		/* 2: */
+	u8 type;		/* 1: */
+	u8 l2linesize;		/* 1: log2 of linesize */
+	/* (8) */
+
+	lv_t lv[20];		/* 40: */
+} linelock_t;			/* (48) */
+
+#define dtlock_t	linelock_t
+#define itlock_t	linelock_t
+
+typedef struct {
+	u16 next;		/* 2: */
+
+	s8 maxcnt;		/* 1: */
+	s8 index;		/* 1: */
+
+	u16 flag;		/* 2: */
+	u8 type;		/* 1: */
+	u8 l2linesize;		/* 1: log2 of linesize */
+				/* (8) */
+
+	lv_t header;		/* 2: */
+	lv_t lwm;		/* 2: low water mark */
+	lv_t hwm;		/* 2: high water mark */
+	lv_t twm;		/* 2: */
+				/* (16) */
+
+	s32 pxdlock[8];		/* 32: */
+} xtlock_t;			/* (48) */
+
+
+/*
+ *	maplock for txUpdateMap()
+ *
+ * note: maplock_t and its variations are overlaid
+ * at tlock.lock/linelock: watch for alignment;
+ * N.B. next field may be set by linelock, and should not
+ * be modified by maplock;
+ * N.B. index of the first pxdlock specifies index of next 
+ * free maplock (i.e., number of maplock) in the tlock; 
+ */
+typedef struct {
+	u16 next;		/* 2: */
+
+	u8 maxcnt;		/* 2: */
+	u8 index;		/* 2: next free maplock index */
+
+	u16 flag;		/* 2: */
+	u8 type;		/* 1: */
+	u8 count;		/* 1: number of pxd/xad */
+				/* (8) */
+
+	pxd_t pxd;		/* 8: */
+} maplock_t;			/* (16): */
+
+/* maplock flag */
+#define	mlckALLOC		0x00f0
+#define	mlckALLOCXADLIST	0x0080
+#define	mlckALLOCPXDLIST	0x0040
+#define	mlckALLOCXAD		0x0020
+#define	mlckALLOCPXD		0x0010
+#define	mlckFREE		0x000f
+#define	mlckFREEXADLIST		0x0008
+#define	mlckFREEPXDLIST		0x0004
+#define	mlckFREEXAD		0x0002
+#define	mlckFREEPXD		0x0001
+
+#define	pxdlock_t	maplock_t
+
+typedef struct {
+	u16 next;		/* 2: */
+
+	u8 maxcnt;		/* 2: */
+	u8 index;		/* 2: */
+
+	u16 flag;		/* 2: */
+	u8 type;		/* 1: */
+	u8 count;		/* 1: number of pxd/xad */
+				/* (8) */
+
+	void *xdlist;		/* 4: pxd/xad list */
+	s32 rsrvd;		/* 4: */
+} xdlistlock_t;			/* (16): */
+
+
+/*
+ *	commit
+ *
+ * parameter to the commit manager routines
+ */
+typedef struct commit {
+	tid_t tid;		/* 4: tid = index of tblock */
+	int flag;		/* 4: flags */
+	log_t *log;		/* 4: log */
+	struct super_block *sb;	/* 4: superblock */
+
+	int nip;		/* 4: number of entries in iplist */
+	struct inode **iplist;	/* 4: list of pointers to inodes */
+				/* (32) */
+
+	/* log record descriptor on 64-bit boundary */
+	lrd_t lrd;		/* : log record descriptor */
+} commit_t;
+
+/*
+ * external declarations
+ */
+extern tlock_t *txLock(tid_t tid, struct inode *ip, struct metapage *mp, int flag);
+
+extern tlock_t *txMaplock(tid_t tid, struct inode *ip, int flag);
+
+extern int txCommit(tid_t tid, int nip, struct inode **iplist, int flag);
+
+extern tid_t txBegin(struct super_block *sb, int flag);
+
+extern void txBeginAnon(struct super_block *sb);
+
+extern void txEnd(tid_t tid);
+
+extern void txAbort(tid_t tid, int dirty);
+
+extern linelock_t *txLinelock(linelock_t * tlock);
+
+extern void txFreeMap(struct inode *ip,
+		      maplock_t * maplock, tblock_t * tblk, int maptype);
+
+extern void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea);
+
+extern void txFreelock(struct inode *ip);
+
+extern int lmLog(log_t * log, tblock_t * tblk, lrd_t * lrd, tlock_t * tlck);
+
+#endif				/* _H_JFS_TXNMGR */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_types.h linux-2.5.6-pre2/fs/jfs/jfs_types.h
--- linux-2.5.6-pre1/fs/jfs/jfs_types.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_types.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,187 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _H_JFS_TYPES
+#define	_H_JFS_TYPES
+
+/*
+ *	jfs_types.h:
+ *
+ * basic type/utility  definitions
+ *
+ * note: this header file must be the 1st include file
+ * of JFS include list in all JFS .c file.
+ */
+
+#include <linux/types.h>
+#include <linux/nls.h>
+
+#include "endian24.h"
+
+/*
+ * transaction and lock id's
+ */
+typedef uint tid_t;
+typedef uint lid_t;
+
+/*
+ * Almost identical to Linux's timespec, but not quite
+ */
+struct timestruc_t {
+	u32 tv_sec;
+	u32 tv_nsec;
+};
+
+/*
+ *	handy
+ */
+
+#define LEFTMOSTONE	0x80000000
+#define	HIGHORDER	0x80000000u	/* high order bit on            */
+#define	ONES		0xffffffffu	/* all bit on                   */
+
+typedef int boolean_t;
+#define TRUE 1
+#define FALSE 0
+
+/*
+ *	logical xd (lxd)
+ */
+typedef struct {
+	unsigned len:24;
+	unsigned off1:8;
+	u32 off2;
+} lxd_t;
+
+/* lxd_t field construction */
+#define	LXDlength(lxd, length32)	( (lxd)->len = length32 )
+#define	LXDoffset(lxd, offset64)\
+{\
+	(lxd)->off1 = ((s64)offset64) >> 32;\
+	(lxd)->off2 = (offset64) & 0xffffffff;\
+}
+
+/* lxd_t field extraction */
+#define	lengthLXD(lxd)	( (lxd)->len )
+#define	offsetLXD(lxd)\
+	( ((s64)((lxd)->off1)) << 32 | (lxd)->off2 )
+
+/* lxd list */
+typedef struct {
+	s16 maxnlxd;
+	s16 nlxd;
+	lxd_t *lxd;
+} lxdlist_t;
+
+/*
+ *	physical xd (pxd)
+ */
+typedef struct {
+	unsigned len:24;
+	unsigned addr1:8;
+	u32 addr2;
+} pxd_t;
+
+/* xd_t field construction */
+
+#define	PXDlength(pxd, length32)	((pxd)->len = __cpu_to_le24(length32))
+#define	PXDaddress(pxd, address64)\
+{\
+	(pxd)->addr1 = ((s64)address64) >> 32;\
+	(pxd)->addr2 = __cpu_to_le32((address64) & 0xffffffff);\
+}
+
+/* xd_t field extraction */
+#define	lengthPXD(pxd)	__le24_to_cpu((pxd)->len)
+#define	addressPXD(pxd)\
+	( ((s64)((pxd)->addr1)) << 32 | __le32_to_cpu((pxd)->addr2))
+
+/* pxd list */
+typedef struct {
+	s16 maxnpxd;
+	s16 npxd;
+	pxd_t pxd[8];
+} pxdlist_t;
+
+
+/*
+ *	data extent descriptor (dxd)
+ */
+typedef struct {
+	unsigned flag:8;	/* 1: flags */
+	unsigned rsrvd:24;	/* 3: */
+	u32 size;		/* 4: size in byte */
+	unsigned len:24;	/* 3: length in unit of fsblksize */
+	unsigned addr1:8;	/* 1: address in unit of fsblksize */
+	u32 addr2;		/* 4: address in unit of fsblksize */
+} dxd_t;			/* - 16 - */
+
+/* dxd_t flags */
+#define	DXD_INDEX	0x80	/* B+-tree index */
+#define	DXD_INLINE	0x40	/* in-line data extent */
+#define	DXD_EXTENT	0x20	/* out-of-line single extent */
+#define	DXD_FILE	0x10	/* out-of-line file (inode) */
+#define DXD_CORRUPT	0x08	/* Inconsistency detected */
+
+/* dxd_t field construction
+ *	Conveniently, the PXD macros work for DXD
+ */
+#define	DXDlength	PXDlength
+#define	DXDaddress	PXDaddress
+#define	lengthDXD	lengthPXD
+#define	addressDXD	addressPXD
+
+/*
+ *      directory entry argument
+ */
+typedef struct component_name {
+	int namlen;
+	wchar_t *name;
+} component_t;
+
+
+/*
+ *	DASD limit information - stored in directory inode
+ */
+typedef struct dasd {
+	u8 thresh;		/* Alert Threshold (in percent) */
+	u8 delta;		/* Alert Threshold delta (in percent)   */
+	u8 rsrvd1;
+	u8 limit_hi;		/* DASD limit (in logical blocks)       */
+	u32 limit_lo;		/* DASD limit (in logical blocks)       */
+	u8 rsrvd2[3];
+	u8 used_hi;		/* DASD usage (in logical blocks)       */
+	u32 used_lo;		/* DASD usage (in logical blocks)       */
+} dasd_t;
+
+#define DASDLIMIT(dasdp) \
+	(((u64)((dasdp)->limit_hi) << 32) + __le32_to_cpu((dasdp)->limit_lo))
+#define setDASDLIMIT(dasdp, limit)\
+{\
+	(dasdp)->limit_hi = ((u64)limit) >> 32;\
+	(dasdp)->limit_lo = __cpu_to_le32(limit);\
+}
+#define DASDUSED(dasdp) \
+	(((u64)((dasdp)->used_hi) << 32) + __le32_to_cpu((dasdp)->used_lo))
+#define setDASDUSED(dasdp, used)\
+{\
+	(dasdp)->used_hi = ((u64)used) >> 32;\
+	(dasdp)->used_lo = __cpu_to_le32(used);\
+}
+
+#endif				/* !_H_JFS_TYPES */
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_umount.c linux-2.5.6-pre2/fs/jfs/jfs_umount.c
--- linux-2.5.6-pre1/fs/jfs/jfs_umount.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_umount.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,158 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Change History :
+ */
+
+/*
+ *	jfs_umount.c
+ *
+ * note: file system in transition to aggregate/fileset:
+ * (ref. jfs_mount.c)
+ *
+ * file system unmount is interpreted as mount of the single/only 
+ * fileset in the aggregate and, if unmount of the last fileset, 
+ * as unmount of the aggerate;
+ */
+
+#include <linux/fs.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_superblock.h"
+#include "jfs_dmap.h"
+#include "jfs_imap.h"
+#include "jfs_metapage.h"
+#include "jfs_debug.h"
+
+/*
+ * NAME:	jfs_umount(vfsp, flags, crp)
+ *
+ * FUNCTION:	vfs_umount()
+ *
+ * PARAMETERS:	vfsp	- virtual file system pointer
+ *		flags	- unmount for shutdown
+ *		crp	- credential
+ *
+ * RETURN :	EBUSY	- device has open files
+ */
+int jfs_umount(struct super_block *sb)
+{
+	int rc = 0;
+	log_t *log;
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	struct inode *ipbmap = sbi->ipbmap;
+	struct inode *ipimap = sbi->ipimap;
+	struct inode *ipaimap = sbi->ipaimap;
+	struct inode *ipaimap2 = sbi->ipaimap2;
+
+	jFYI(1, ("\n	UnMount JFS: sb:0x%p\n", sb));
+
+	/*
+	 *      update superblock and close log 
+	 *
+	 * if mounted read-write and log based recovery was enabled
+	 */
+	if ((log = sbi->log)) {
+		/*
+		 * close log: 
+		 *
+		 * remove file system from log active file system list.
+		 */
+		log = sbi->log;
+		rc = lmLogClose(sb, log);
+	}
+
+	/*
+	 * close fileset inode allocation map (aka fileset inode)
+	 */
+	jEVENT(0, ("jfs_umount: close ipimap:0x%p\n", ipimap));
+	diUnmount(ipimap, 0);
+
+	diFreeSpecial(ipimap);
+	sbi->ipimap = NULL;
+
+	/*
+	 * close secondary aggregate inode allocation map
+	 */
+	ipaimap2 = sbi->ipaimap2;
+	if (ipaimap2) {
+		jEVENT(0, ("jfs_umount: close ipaimap2:0x%p\n", ipaimap2));
+		diUnmount(ipaimap2, 0);
+		diFreeSpecial(ipaimap2);
+		sbi->ipaimap2 = NULL;
+	}
+
+	/*
+	 * close aggregate inode allocation map
+	 */
+	ipaimap = sbi->ipaimap;
+	jEVENT(0, ("jfs_umount: close ipaimap:0x%p\n", ipaimap));
+	diUnmount(ipaimap, 0);
+	diFreeSpecial(ipaimap);
+	sbi->ipaimap = NULL;
+
+	/*
+	 * close aggregate block allocation map
+	 */
+	jEVENT(0, ("jfs_umount: close ipbmap:%p\n", ipbmap));
+	dbUnmount(ipbmap, 0);
+
+	diFreeSpecial(ipbmap);
+	sbi->ipimap = NULL;
+
+	/*
+	 * ensure all file system file pages are propagated to their
+	 * home blocks on disk (and their in-memory buffer pages are 
+	 * invalidated) BEFORE updating file system superblock state
+	 * (to signify file system is unmounted cleanly, and thus in 
+	 * consistent state) and log superblock active file system 
+	 * list (to signify skip logredo()).
+	 */
+	if (log)		/* log = NULL if read-only mount */
+		rc = updateSuper(sb, FM_CLEAN);
+
+
+	jFYI(0, ("	UnMount JFS Complete: %d\n", rc));
+	return rc;
+}
+
+
+int jfs_umount_rw(struct super_block *sb)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+
+	if (!sbi->log)
+		return 0;
+
+	/*
+	 * close log: 
+	 *
+	 * remove file system from log active file system list.
+	 */
+	lmLogClose(sb, sbi->log);
+
+	dbSync(sbi->ipbmap);
+	diSync(sbi->ipimap);
+
+	sbi->log = 0;
+
+	return updateSuper(sb, FM_CLEAN);
+       
+}
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_unicode.c linux-2.5.6-pre2/fs/jfs/jfs_unicode.c
--- linux-2.5.6-pre1/fs/jfs/jfs_unicode.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_unicode.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,110 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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/fs.h>
+#include <linux/slab.h>
+#include "jfs_types.h"
+#include "jfs_filsys.h"
+#include "jfs_unicode.h"
+#include "jfs_debug.h"
+
+/*
+ * NAME:	jfs_strfromUCS()
+ *
+ * FUNCTION:	Convert little-endian unicode string to character string
+ *
+ */
+int jfs_strfromUCS_le(char *to, const wchar_t * from,	/* LITTLE ENDIAN */
+		      int len, struct nls_table *codepage)
+{
+	int i;
+	int outlen = 0;
+
+	for (i = 0; (i < len) && from[i]; i++) {
+		int charlen;
+		charlen =
+		    codepage->uni2char(le16_to_cpu(from[i]), &to[outlen],
+				       NLS_MAX_CHARSET_SIZE);
+		if (charlen > 0) {
+			outlen += charlen;
+		} else {
+			to[outlen++] = '?';
+		}
+	}
+	to[outlen] = 0;
+	jEVENT(0, ("jfs_strfromUCS returning %d - '%s'\n", outlen, to));
+	return outlen;
+}
+
+/*
+ * NAME:	jfs_strtoUCS()
+ *
+ * FUNCTION:	Convert character string to unicode string
+ *
+ */
+int jfs_strtoUCS(wchar_t * to,
+		 const char *from, int len, struct nls_table *codepage)
+{
+	int charlen;
+	int i;
+
+	jEVENT(0, ("jfs_strtoUCS - '%s'\n", from));
+
+	for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
+		charlen = codepage->char2uni(from, len, &to[i]);
+		if (charlen < 1) {
+			jERROR(1, ("jfs_strtoUCS: char2uni returned %d.\n",
+				   charlen));
+			jERROR(1, ("charset = %s, char = 0x%x\n",
+				   codepage->charset, (unsigned char) *from));
+			to[i] = 0x003f;	/* a question mark */
+			charlen = 1;
+		}
+	}
+
+	jEVENT(0, (" returning %d\n", i));
+
+	to[i] = 0;
+	return i;
+}
+
+/*
+ * NAME:	get_UCSname()
+ *
+ * FUNCTION:	Allocate and translate to unicode string
+ *
+ */
+int get_UCSname(component_t * uniName, struct dentry *dentry,
+		struct nls_table *nls_tab)
+{
+	int length = dentry->d_name.len;
+
+	if (length > JFS_NAME_MAX)
+		return ENAMETOOLONG;
+
+	uniName->name =
+	    kmalloc((length + 1) * sizeof(wchar_t), GFP_NOFS);
+
+	if (uniName->name == NULL)
+		return ENOSPC;
+
+	uniName->namlen = jfs_strtoUCS(uniName->name, dentry->d_name.name,
+				       length, nls_tab);
+
+	return 0;
+}
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_unicode.h linux-2.5.6-pre2/fs/jfs/jfs_unicode.h
--- linux-2.5.6-pre1/fs/jfs/jfs_unicode.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_unicode.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,143 @@
+/*
+ * unistrk:  Unicode kernel case support
+ *
+ * Function:
+ *     Convert a unicode character to upper or lower case using
+ *     compressed tables.
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ */
+
+#include <asm/byteorder.h>
+#include "jfs_types.h"
+
+typedef struct {
+	wchar_t start;
+	wchar_t end;
+	signed char *table;
+} UNICASERANGE;
+
+extern signed char UniUpperTable[512];
+extern UNICASERANGE UniUpperRange[];
+extern int get_UCSname(component_t *, struct dentry *, struct nls_table *);
+extern int jfs_strfromUCS_le(char *, const wchar_t *, int, struct nls_table *);
+
+#define free_UCSname(COMP) kfree((COMP)->name)
+
+/*
+ * UniStrcpy:  Copy a string
+ */
+static inline wchar_t *UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2)
+{
+	wchar_t *anchor = ucs1;	/* save the start of result string */
+
+	while ((*ucs1++ = *ucs2++));
+	return anchor;
+}
+
+
+
+/*
+ * UniStrncpy:  Copy length limited string with pad
+ */
+static inline wchar_t *UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2,
+				  size_t n)
+{
+	wchar_t *anchor = ucs1;
+
+	while (n-- && *ucs2)	/* Copy the strings */
+		*ucs1++ = *ucs2++;
+
+	n++;
+	while (n--)		/* Pad with nulls */
+		*ucs1++ = 0;
+	return anchor;
+}
+
+/*
+ * UniStrncmp_le:  Compare length limited string - native to little-endian
+ */
+static inline int UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2,
+				size_t n)
+{
+	if (!n)
+		return 0;	/* Null strings are equal */
+	while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
+		ucs1++;
+		ucs2++;
+	}
+	return (int) *ucs1 - (int) __le16_to_cpu(*ucs2);
+}
+
+/*
+ * UniStrncpy_le:  Copy length limited string with pad to little-endian
+ */
+static inline wchar_t *UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2,
+				     size_t n)
+{
+	wchar_t *anchor = ucs1;
+
+	while (n-- && *ucs2)	/* Copy the strings */
+		*ucs1++ = __le16_to_cpu(*ucs2++);
+
+	n++;
+	while (n--)		/* Pad with nulls */
+		*ucs1++ = 0;
+	return anchor;
+}
+
+
+/*
+ * UniToupper:  Convert a unicode character to upper case
+ */
+static inline wchar_t UniToupper(register wchar_t uc)
+{
+	register UNICASERANGE *rp;
+
+	if (uc < sizeof(UniUpperTable)) {	/* Latin characters */
+		return uc + UniUpperTable[uc];	/* Use base tables */
+	} else {
+		rp = UniUpperRange;	/* Use range tables */
+		while (rp->start) {
+			if (uc < rp->start)	/* Before start of range */
+				return uc;	/* Uppercase = input */
+			if (uc <= rp->end)	/* In range */
+				return uc + rp->table[uc - rp->start];
+			rp++;	/* Try next range */
+		}
+	}
+	return uc;		/* Past last range */
+}
+
+
+/*
+ * UniStrupr:  Upper case a unicode string
+ */
+static inline wchar_t *UniStrupr(register wchar_t * upin)
+{
+	register wchar_t *up;
+
+	up = upin;
+	while (*up) {		/* For all characters */
+		*up = UniToupper(*up);
+		up++;
+	}
+	return upin;		/* Return input pointer */
+}
+
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_uniupr.c linux-2.5.6-pre2/fs/jfs/jfs_uniupr.c
--- linux-2.5.6-pre1/fs/jfs/jfs_uniupr.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_uniupr.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,137 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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
+ *
+ * jfs_uniupr.c - Unicode compressed case ranges
+ *
+*/
+
+#include <linux/fs.h>
+#include "jfs_unicode.h"
+
+/*
+ * Latin upper case
+ */
+signed char UniUpperTable[512] = {
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 000-00f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 010-01f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 020-02f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 030-03f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 040-04f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 050-05f */
+   0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 060-06f */
+ -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,  0,  0,  0,  0,  0, /* 070-07f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 080-08f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 090-09f */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 0a0-0af */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 0b0-0bf */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 0c0-0cf */
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 0d0-0df */
+ -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 0e0-0ef */
+ -32,-32,-32,-32,-32,-32,-32,  0,-32,-32,-32,-32,-32,-32,-32,121, /* 0f0-0ff */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 100-10f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 110-11f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 120-12f */
+   0,  0,  0, -1,  0, -1,  0, -1,  0,  0, -1,  0, -1,  0, -1,  0, /* 130-13f */
+  -1,  0, -1,  0, -1,  0, -1,  0, -1,  0,  0, -1,  0, -1,  0, -1, /* 140-14f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 150-15f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 160-16f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0,  0, -1,  0, -1,  0, -1,  0, /* 170-17f */
+   0,  0,  0, -1,  0, -1,  0,  0, -1,  0,  0,  0, -1,  0,  0,  0, /* 180-18f */
+   0,  0, -1,  0,  0,  0,  0,  0,  0, -1,  0,  0,  0,  0,  0,  0, /* 190-19f */
+   0, -1,  0, -1,  0, -1,  0,  0, -1,  0,  0,  0,  0, -1,  0,  0, /* 1a0-1af */
+  -1,  0,  0,  0, -1,  0, -1,  0,  0, -1,  0,  0,  0, -1,  0,  0, /* 1b0-1bf */
+   0,  0,  0,  0,  0, -1, -2,  0, -1, -2,  0, -1, -2,  0, -1,  0, /* 1c0-1cf */
+  -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,-79,  0, -1, /* 1d0-1df */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e0-1ef */
+   0,  0, -1, -2,  0, -1,  0,  0,  0, -1,  0, -1,  0, -1,  0, -1, /* 1f0-1ff */
+};
+
+/* Upper case range - Greek */
+static signed char UniCaseRangeU03a0[47] = {
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,-38,-37,-37,-37, /* 3a0-3af */
+   0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 3b0-3bf */
+ -32,-32,-31,-32,-32,-32,-32,-32,-32,-32,-32,-32,-64,-63,-63,
+};
+
+/* Upper case range - Cyrillic */
+static signed char UniCaseRangeU0430[48] = {
+ -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 430-43f */
+ -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* 440-44f */
+   0,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,-80,  0,-80,-80, /* 450-45f */
+};
+
+/* Upper case range - Extended cyrillic */
+static signed char UniCaseRangeU0490[61] = {
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 490-49f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 4a0-4af */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 4b0-4bf */
+   0,  0, -1,  0, -1,  0,  0,  0, -1,  0,  0,  0, -1,
+};
+
+/* Upper case range - Extended latin and greek */
+static signed char UniCaseRangeU1e00[509] = {
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e00-1e0f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e10-1e1f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e20-1e2f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e30-1e3f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e40-1e4f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e50-1e5f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e60-1e6f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e70-1e7f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1e80-1e8f */
+   0, -1,  0, -1,  0, -1,  0,  0,  0,  0,  0,-59,  0, -1,  0, -1, /* 1e90-1e9f */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1ea0-1eaf */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1eb0-1ebf */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1ec0-1ecf */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1ed0-1edf */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0, -1, /* 1ee0-1eef */
+   0, -1,  0, -1,  0, -1,  0, -1,  0, -1,  0,  0,  0,  0,  0,  0, /* 1ef0-1eff */
+   8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f00-1f0f */
+   8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f10-1f1f */
+   8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f20-1f2f */
+   8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f30-1f3f */
+   8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f40-1f4f */
+   0,  8,  0,  8,  0,  8,  0,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f50-1f5f */
+   8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f60-1f6f */
+  74, 74, 86, 86, 86, 86,100,100,  0,  0,112,112,126,126,  0,  0, /* 1f70-1f7f */
+   8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f80-1f8f */
+   8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1f90-1f9f */
+   8,  8,  8,  8,  8,  8,  8,  8,  0,  0,  0,  0,  0,  0,  0,  0, /* 1fa0-1faf */
+   8,  8,  0,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 1fb0-1fbf */
+   0,  0,  0,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 1fc0-1fcf */
+   8,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 1fd0-1fdf */
+   8,  8,  0,  0,  0,  7,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, /* 1fe0-1fef */
+   0,  0,  0,  9,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+/* Upper case range - Wide latin */
+static signed char UniCaseRangeUff40[27] = {
+   0,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32, /* ff40-ff4f */
+ -32,-32,-32,-32,-32,-32,-32,-32,-32,-32,-32,
+};
+
+/*
+ * Upper Case Range
+ */
+UNICASERANGE UniUpperRange[] = {
+    { 0x03a0,  0x03ce,  UniCaseRangeU03a0 },
+    { 0x0430,  0x045f,  UniCaseRangeU0430 },
+    { 0x0490,  0x04cc,  UniCaseRangeU0490 },
+    { 0x1e00,  0x1ffc,  UniCaseRangeU1e00 },
+    { 0xff40,  0xff5a,  UniCaseRangeUff40 },
+    { 0, 0, 0 }
+};
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_xtree.c linux-2.5.6-pre2/fs/jfs/jfs_xtree.c
--- linux-2.5.6-pre1/fs/jfs/jfs_xtree.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_xtree.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,4444 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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
+ */
+/*
+ *      jfs_xtree.c: extent allocation descriptor B+-tree manager
+ */
+
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_metapage.h"
+#include "jfs_dmap.h"
+#include "jfs_dinode.h"
+#include "jfs_superblock.h"
+#include "jfs_debug.h"
+
+/*
+ * xtree local flag
+ */
+#define XT_INSERT       0x00000001
+
+/*
+ *       xtree key/entry comparison: extent offset
+ *
+ * return:
+ *      -1: k < start of extent
+ *       0: start_of_extent <= k <= end_of_extent
+ *       1: k > end_of_extent
+ */
+#define XT_CMP(CMP, K, X, OFFSET64)\
+{\
+        OFFSET64 = offsetXAD(X);\
+        (CMP) = ((K) >= OFFSET64 + lengthXAD(X)) ? 1 :\
+              ((K) < OFFSET64) ? -1 : 0;\
+}
+
+/* write a xad entry */
+#define XT_PUTENTRY(XAD, FLAG, OFF, LEN, ADDR)\
+{\
+        (XAD)->flag = (FLAG);\
+        XADoffset((XAD), (OFF));\
+        XADlength((XAD), (LEN));\
+        XADaddress((XAD), (ADDR));\
+}
+
+#define XT_PAGE(IP, MP) BT_PAGE(IP, MP, xtpage_t, i_xtroot)
+
+/* get page buffer for specified block address */
+#define XT_GETPAGE(IP, BN, MP, SIZE, P, RC)\
+{\
+        BT_GETPAGE(IP, BN, MP, xtpage_t, SIZE, P, RC, i_xtroot)\
+        if (!(RC))\
+        {\
+                if ((le16_to_cpu((P)->header.nextindex) < XTENTRYSTART) ||\
+                    (le16_to_cpu((P)->header.nextindex) > le16_to_cpu((P)->header.maxentry)) ||\
+                    (le16_to_cpu((P)->header.maxentry) > (((BN)==0)?XTROOTMAXSLOT:PSIZE>>L2XTSLOTSIZE)))\
+                {\
+                        jERROR(1,("XT_GETPAGE: xtree page corrupt\n"));\
+			BT_PUTPAGE(MP);\
+			updateSuper((IP)->i_sb, FM_DIRTY);\
+			MP = NULL;\
+                        RC = EIO;\
+                }\
+        }\
+}
+
+/* for consistency */
+#define XT_PUTPAGE(MP) BT_PUTPAGE(MP)
+
+#define XT_GETSEARCH(IP, LEAF, BN, MP,  P, INDEX) \
+	BT_GETSEARCH(IP, LEAF, BN, MP, xtpage_t, P, INDEX, i_xtroot)
+/* xtree entry parameter descriptor */
+typedef struct {
+	metapage_t *mp;
+	s16 index;
+	u8 flag;
+	s64 off;
+	s64 addr;
+	int len;
+	pxdlist_t *pxdlist;
+} xtsplit_t;
+
+
+/*
+ *      statistics
+ */
+#ifdef CONFIG_JFS_STATISTICS
+static struct {
+	uint search;
+	uint fastSearch;
+	uint split;
+} xtStat;
+#endif
+
+
+/*
+ * forward references
+ */
+static int xtSearch(struct inode *ip,
+		    s64 xoff, int *cmpp, btstack_t * btstack, int flag);
+
+static int xtSplitUp(tid_t tid,
+		     struct inode *ip,
+		     xtsplit_t * split, btstack_t * btstack);
+
+static int xtSplitPage(tid_t tid,
+		       struct inode *ip,
+		       xtsplit_t * split, metapage_t ** rmpp, s64 * rbnp);
+
+static int xtSplitRoot(tid_t tid,
+		       struct inode *ip,
+		       xtsplit_t * split, metapage_t ** rmpp);
+
+#ifdef _STILL_TO_PORT
+static int xtDeleteUp(tid_t tid,
+		      struct inode *ip,
+		      metapage_t * fmp,
+		      xtpage_t * fp, btstack_t * btstack);
+
+static int xtSearchNode(struct inode *ip,
+			xad_t * xad,
+			int *cmpp, btstack_t * btstack, int flag);
+
+static int xtRelink(tid_t tid, struct inode *ip, xtpage_t * fp);
+#endif				/*  _STILL_TO_PORT */
+
+/* External references */
+
+/*
+ *      debug control
+ */
+/*      #define _JFS_DEBUG_XTREE        1 */
+
+
+/*
+ *      xtLookup()
+ *
+ * function: map a single page into a physical extent;
+ */
+int xtLookup(struct inode *ip, s64 lstart,
+	     s64 llen, int *pflag, s64 * paddr, s32 * plen, int no_check)
+{
+	int rc = 0;
+	btstack_t btstack;
+	int cmp;
+	s64 bn;
+	metapage_t *mp;
+	xtpage_t *p;
+	int index;
+	xad_t *xad;
+	s64 size, xoff, xend;
+	int xlen;
+	s64 xaddr;
+
+	*plen = 0;
+
+	if (!no_check) {
+		/* is lookup offset beyond eof ? */
+		size = ((u64) ip->i_size + (JFS_SBI(ip->i_sb)->bsize - 1)) >>
+		    JFS_SBI(ip->i_sb)->l2bsize;
+		if (lstart >= size) {
+			jERROR(1,
+			       ("xtLookup: lstart (0x%lx) >= size (0x%lx)\n",
+				(ulong) lstart, (ulong) size));
+			return 0;
+		}
+	}
+
+	/*
+	 * search for the xad entry covering the logical extent
+	 */
+//search:
+	if ((rc = xtSearch(ip, lstart, &cmp, &btstack, 0))) {
+		jERROR(1, ("xtLookup: xtSearch returned %d\n", rc));
+		return rc;
+	}
+
+	/*
+	 *      compute the physical extent covering logical extent
+	 *
+	 * N.B. search may have failed (e.g., hole in sparse file),
+	 * and returned the index of the next entry.
+	 */
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	/* is xad found covering start of logical extent ?
+	 * lstart is a page start address,
+	 * i.e., lstart cannot start in a hole;
+	 */
+	if (cmp) {
+		jFYI(1, ("xtLookup: cmp = %d\n", cmp));
+		goto out;
+	}
+
+	/*
+	 * lxd covered by xad
+	 */
+	xad = &p->xad[index];
+	xoff = offsetXAD(xad);
+	xlen = lengthXAD(xad);
+	xend = xoff + xlen;
+	xaddr = addressXAD(xad);
+
+	jEVENT(0,
+	       ("index = %d, xoff = 0x%lx, xlen = 0x%x, xaddr = 0x%lx\n",
+		index, (ulong) xoff, xlen, (ulong) xaddr));
+
+	/* initialize new pxd */
+	*pflag = xad->flag;
+	*paddr = xaddr + (lstart - xoff);
+	/* a page must be fully covered by an xad */
+	*plen = min(xend - lstart, llen);
+
+      out:
+	XT_PUTPAGE(mp);
+
+	return rc;
+}
+
+
+/*
+ *      xtLookupList()
+ *
+ * function: map a single logical extent into a list of physical extent;
+ *
+ * parameter:
+ *      struct inode    *ip,
+ *      lxdlist_t       *lxdlist,       lxd list (in)
+ *      xadlist_t       *xadlist,       xad list (in/out)
+ *      int		flag)
+ *
+ * coverage of lxd by xad under assumption of
+ * . lxd's are ordered and disjoint.
+ * . xad's are ordered and disjoint.
+ *
+ * return:
+ *      0:      success
+ *
+ * note: a page being written (even a single byte) is backed fully,
+ *      except the last page which is only backed with blocks
+ *      required to cover the last byte;
+ *      the extent backing a page is fully contained within an xad;
+ */
+int xtLookupList(struct inode *ip, lxdlist_t * lxdlist,	/* lxd list (in) */
+		 xadlist_t * xadlist,	/* xad list (in/out) */
+		 int flag)
+{
+	int rc = 0;
+	btstack_t btstack;
+	int cmp;
+	s64 bn;
+	metapage_t *mp;
+	xtpage_t *p;
+	int index;
+	lxd_t *lxd;
+	xad_t *xad, *pxd;
+	s64 size, lstart, lend, xstart, xend, pstart;
+	s64 llen, xlen, plen;
+	s64 xaddr, paddr;
+	int nlxd, npxd, maxnpxd;
+
+	npxd = xadlist->nxad = 0;
+	maxnpxd = xadlist->maxnxad;
+	pxd = xadlist->xad;
+
+	nlxd = lxdlist->nlxd;
+	lxd = lxdlist->lxd;
+
+	lstart = offsetLXD(lxd);
+	llen = lengthLXD(lxd);
+	lend = lstart + llen;
+
+	size = (ip->i_size + (JFS_SBI(ip->i_sb)->bsize - 1)) >>
+	    JFS_SBI(ip->i_sb)->l2bsize;
+
+	/*
+	 * search for the xad entry covering the logical extent
+	 */
+      search:
+	if (lstart >= size)
+		return 0;
+
+	if ((rc = xtSearch(ip, lstart, &cmp, &btstack, 0)))
+		return rc;
+
+	/*
+	 *      compute the physical extent covering logical extent
+	 *
+	 * N.B. search may have failed (e.g., hole in sparse file),
+	 * and returned the index of the next entry.
+	 */
+//map:
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	/* is xad on the next sibling page ? */
+	if (index == le16_to_cpu(p->header.nextindex)) {
+		if (p->header.flag & BT_ROOT)
+			goto mapend;
+
+		if ((bn = le64_to_cpu(p->header.next)) == 0)
+			goto mapend;
+
+		XT_PUTPAGE(mp);
+
+		/* get next sibling page */
+		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		index = XTENTRYSTART;
+	}
+
+	xad = &p->xad[index];
+
+	/*
+	 * is lxd covered by xad ?
+	 */
+      compare:
+	xstart = offsetXAD(xad);
+	xlen = lengthXAD(xad);
+	xend = xstart + xlen;
+	xaddr = addressXAD(xad);
+
+      compare1:
+	if (xstart < lstart)
+		goto compare2;
+
+	/* (lstart <= xstart) */
+
+	/* lxd is NOT covered by xad */
+	if (lend <= xstart) {
+		/*
+		 * get next lxd
+		 */
+		if (--nlxd == 0)
+			goto mapend;
+		lxd++;
+
+		lstart = offsetLXD(lxd);
+		llen = lengthLXD(lxd);
+		lend = lstart + llen;
+		if (lstart >= size)
+			goto mapend;
+
+		/* compare with the current xad  */
+		goto compare1;
+	}
+	/* lxd is covered by xad */
+	else {			/* (xstart < lend) */
+
+		/* initialize new pxd */
+		pstart = xstart;
+		plen = min(lend - xstart, xlen);
+		paddr = xaddr;
+
+		goto cover;
+	}
+
+	/* (xstart < lstart) */
+      compare2:
+	/* lxd is covered by xad */
+	if (lstart < xend) {
+		/* initialize new pxd */
+		pstart = lstart;
+		plen = min(xend - lstart, llen);
+		paddr = xaddr + (lstart - xstart);
+
+		goto cover;
+	}
+	/* lxd is NOT covered by xad */
+	else {			/* (xend <= lstart) */
+
+		/*
+		 * get next xad
+		 *
+		 * linear search next xad covering lxd on
+		 * the current xad page, and then tree search
+		 */
+		if (index == le16_to_cpu(p->header.nextindex) - 1) {
+			if (p->header.flag & BT_ROOT)
+				goto mapend;
+
+			XT_PUTPAGE(mp);
+			goto search;
+		} else {
+			index++;
+			xad++;
+
+			/* compare with new xad */
+			goto compare;
+		}
+	}
+
+	/*
+	 * lxd is covered by xad and a new pxd has been initialized
+	 * (lstart <= xstart < lend) or (xstart < lstart < xend)
+	 */
+      cover:
+	/* finalize pxd corresponding to current xad */
+	XT_PUTENTRY(pxd, xad->flag, pstart, plen, paddr);
+
+	if (++npxd >= maxnpxd)
+		goto mapend;
+	pxd++;
+
+	/*
+	 * lxd is fully covered by xad
+	 */
+	if (lend <= xend) {
+		/*
+		 * get next lxd
+		 */
+		if (--nlxd == 0)
+			goto mapend;
+		lxd++;
+
+		lstart = offsetLXD(lxd);
+		llen = lengthLXD(lxd);
+		lend = lstart + llen;
+		if (lstart >= size)
+			goto mapend;
+
+		/*
+		 * test for old xad covering new lxd
+		 * (old xstart < new lstart)
+		 */
+		goto compare2;
+	}
+	/*
+	 * lxd is partially covered by xad
+	 */
+	else {			/* (xend < lend)  */
+
+		/*
+		 * get next xad
+		 *
+		 * linear search next xad covering lxd on
+		 * the current xad page, and then next xad page search
+		 */
+		if (index == le16_to_cpu(p->header.nextindex) - 1) {
+			if (p->header.flag & BT_ROOT)
+				goto mapend;
+
+			if ((bn = le64_to_cpu(p->header.next)) == 0)
+				goto mapend;
+
+			XT_PUTPAGE(mp);
+
+			/* get next sibling page */
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+			if (rc)
+				return rc;
+
+			index = XTENTRYSTART;
+			xad = &p->xad[index];
+		} else {
+			index++;
+			xad++;
+		}
+
+		/*
+		 * test for new xad covering old lxd
+		 * (old lstart < new xstart)
+		 */
+		goto compare;
+	}
+
+      mapend:
+	xadlist->nxad = npxd;
+
+//out:
+	XT_PUTPAGE(mp);
+
+	return rc;
+}
+
+
+/*
+ *      xtSearch()
+ *
+ * function:    search for the xad entry covering specified offset.
+ *
+ * parameters:
+ *      ip      - file object;
+ *      xoff    - extent offset;
+ *      cmpp    - comparison result:
+ *      btstack - traverse stack;
+ *      flag    - search process flag (XT_INSERT);
+ *
+ * returns:
+ *      btstack contains (bn, index) of search path traversed to the entry.
+ *      *cmpp is set to result of comparison with the entry returned.
+ *      the page containing the entry is pinned at exit.
+ */
+static int xtSearch(struct inode *ip, s64 xoff,	/* offset of extent */
+		    int *cmpp, btstack_t * btstack, int flag)
+{
+	struct jfs_inode_info *jfs_ip = JFS_IP(ip);
+	int rc = 0;
+	int cmp = 1;		/* init for empty page */
+	s64 bn;			/* block number */
+	metapage_t *mp;		/* page buffer */
+	xtpage_t *p;		/* page */
+	xad_t *xad;
+	int base, index, lim, btindex;
+	btframe_t *btsp;
+	int nsplit = 0;		/* number of pages to split */
+	s64 t64;
+
+	INCREMENT(xtStat.search);
+
+	BT_CLR(btstack);
+
+	btstack->nsplit = 0;
+
+	/*
+	 *      search down tree from root:
+	 *
+	 * between two consecutive entries of <Ki, Pi> and <Kj, Pj> of
+	 * internal page, child page Pi contains entry with k, Ki <= K < Kj.
+	 *
+	 * if entry with search key K is not found
+	 * internal page search find the entry with largest key Ki
+	 * less than K which point to the child page to search;
+	 * leaf page search find the entry with smallest key Kj
+	 * greater than K so that the returned index is the position of
+	 * the entry to be shifted right for insertion of new entry.
+	 * for empty tree, search key is greater than any key of the tree.
+	 *
+	 * by convention, root bn = 0.
+	 */
+	for (bn = 0;;) {
+		/* get/pin the page to search */
+		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		/* try sequential access heuristics with the previous
+		 * access entry in target leaf page:
+		 * once search narrowed down into the target leaf,
+		 * key must either match an entry in the leaf or
+		 * key entry does not exist in the tree;
+		 */
+//fastSearch:
+		if ((jfs_ip->btorder & BT_SEQUENTIAL) &&
+		    (p->header.flag & BT_LEAF) &&
+		    (index = jfs_ip->btindex) <
+		    le16_to_cpu(p->header.nextindex)) {
+			xad = &p->xad[index];
+			t64 = offsetXAD(xad);
+			if (xoff < t64 + lengthXAD(xad)) {
+				if (xoff >= t64) {
+					*cmpp = 0;
+					goto out;
+				}
+
+				/* stop sequential access heuristics */
+				goto binarySearch;
+			} else {	/* (t64 + lengthXAD(xad)) <= xoff */
+
+				/* try next sequential entry */
+				index++;
+				if (index <
+				    le16_to_cpu(p->header.nextindex)) {
+					xad++;
+					t64 = offsetXAD(xad);
+					if (xoff < t64 + lengthXAD(xad)) {
+						if (xoff >= t64) {
+							*cmpp = 0;
+							goto out;
+						}
+
+						/* miss: key falls between
+						 * previous and this entry
+						 */
+						*cmpp = 1;
+						goto out;
+					}
+
+					/* (xoff >= t64 + lengthXAD(xad));
+					 * matching entry may be further out:
+					 * stop heuristic search
+					 */
+					/* stop sequential access heuristics */
+					goto binarySearch;
+				}
+
+				/* (index == p->header.nextindex);
+				 * miss: key entry does not exist in
+				 * the target leaf/tree
+				 */
+				*cmpp = 1;
+				goto out;
+			}
+
+			/*
+			 * if hit, return index of the entry found, and
+			 * if miss, where new entry with search key is
+			 * to be inserted;
+			 */
+		      out:
+			/* compute number of pages to split */
+			if (flag & XT_INSERT) {
+				if (p->header.nextindex ==	/* little-endian */
+				    p->header.maxentry)
+					nsplit++;
+				else
+					nsplit = 0;
+				btstack->nsplit = nsplit;
+			}
+
+			/* save search result */
+			btsp = btstack->top;
+			btsp->bn = bn;
+			btsp->index = index;
+			btsp->mp = mp;
+
+			/* update sequential access heuristics */
+			jfs_ip->btindex = index;
+
+			INCREMENT(xtStat.fastSearch);
+			return 0;
+		}
+
+		/* well, ... full search now */
+	      binarySearch:
+		lim = le16_to_cpu(p->header.nextindex) - XTENTRYSTART;
+
+		/*
+		 * binary search with search key K on the current page
+		 */
+		for (base = XTENTRYSTART; lim; lim >>= 1) {
+			index = base + (lim >> 1);
+
+			XT_CMP(cmp, xoff, &p->xad[index], t64);
+			if (cmp == 0) {
+				/*
+				 *      search hit
+				 */
+				/* search hit - leaf page:
+				 * return the entry found
+				 */
+				if (p->header.flag & BT_LEAF) {
+					*cmpp = cmp;
+
+					/* compute number of pages to split */
+					if (flag & XT_INSERT) {
+						if (p->header.nextindex ==
+						    p->header.maxentry)
+							nsplit++;
+						else
+							nsplit = 0;
+						btstack->nsplit = nsplit;
+					}
+
+					/* save search result */
+					btsp = btstack->top;
+					btsp->bn = bn;
+					btsp->index = index;
+					btsp->mp = mp;
+
+					/* init sequential access heuristics */
+					btindex = jfs_ip->btindex;
+					if (index == btindex ||
+					    index == btindex + 1)
+						jfs_ip->btorder = BT_SEQUENTIAL;
+					else
+						jfs_ip->btorder = BT_RANDOM;
+					jfs_ip->btindex = index;
+
+					return 0;
+				}
+
+				/* search hit - internal page:
+				 * descend/search its child page
+				 */
+				goto next;
+			}
+
+			if (cmp > 0) {
+				base = index + 1;
+				--lim;
+			}
+		}
+
+		/*
+		 *      search miss
+		 *
+		 * base is the smallest index with key (Kj) greater than
+		 * search key (K) and may be zero or maxentry index.
+		 */
+		/*
+		 * search miss - leaf page:
+		 *
+		 * return location of entry (base) where new entry with
+		 * search key K is to be inserted.
+		 */
+		if (p->header.flag & BT_LEAF) {
+			*cmpp = cmp;
+
+			/* compute number of pages to split */
+			if (flag & XT_INSERT) {
+				if (p->header.nextindex ==
+				    p->header.maxentry)
+					nsplit++;
+				else
+					nsplit = 0;
+				btstack->nsplit = nsplit;
+			}
+
+			/* save search result */
+			btsp = btstack->top;
+			btsp->bn = bn;
+			btsp->index = base;
+			btsp->mp = mp;
+
+			/* init sequential access heuristics */
+			btindex = jfs_ip->btindex;
+			if (base == btindex || base == btindex + 1)
+				jfs_ip->btorder = BT_SEQUENTIAL;
+			else
+				jfs_ip->btorder = BT_RANDOM;
+			jfs_ip->btindex = base;
+
+			return 0;
+		}
+
+		/*
+		 * search miss - non-leaf page:
+		 *
+		 * if base is non-zero, decrement base by one to get the parent
+		 * entry of the child page to search.
+		 */
+		index = base ? base - 1 : base;
+
+		/*
+		 * go down to child page
+		 */
+	      next:
+		/* update number of pages to split */
+		if (p->header.nextindex == p->header.maxentry)
+			nsplit++;
+		else
+			nsplit = 0;
+
+		/* push (bn, index) of the parent page/entry */
+		BT_PUSH(btstack, bn, index);
+
+		/* get the child page block number */
+		bn = addressXAD(&p->xad[index]);
+
+		/* unpin the parent page */
+		XT_PUTPAGE(mp);
+	}
+}
+
+/*
+ *      xtInsert()
+ *
+ * function:
+ *
+ * parameter:
+ *      tid     - transaction id;
+ *      ip      - file object;
+ *      xflag   - extent flag (XAD_NOTRECORDED):
+ *      xoff    - extent offset;
+ *      xlen    - extent length;
+ *      xaddrp  - extent address pointer (in/out):
+ *              if (*xaddrp)
+ *                      caller allocated data extent at *xaddrp;
+ *              else
+ *                      allocate data extent and return its xaddr;
+ *      flag    -
+ *
+ * return:
+ */
+int xtInsert(tid_t tid,		/* transaction id */
+	     struct inode *ip, int xflag, s64 xoff, s32 xlen, s64 * xaddrp,
+	     int flag)
+{
+	int rc = 0;
+	s64 xaddr, hint;
+	metapage_t *mp;		/* meta-page buffer */
+	xtpage_t *p;		/* base B+-tree index page */
+	s64 bn;
+	int index, nextindex;
+	btstack_t btstack;	/* traverse stack */
+	xtsplit_t split;	/* split information */
+	xad_t *xad;
+	int cmp;
+	tlock_t *tlck;
+	xtlock_t *xtlck;
+
+	jFYI(1,
+	     ("xtInsert: nxoff:0x%lx nxlen:0x%x\n", (ulong) xoff, xlen));
+
+	/*
+	 *      search for the entry location at which to insert:
+	 *
+	 * xtFastSearch() and xtSearch() both returns (leaf page
+	 * pinned, index at which to insert).
+	 * n.b. xtSearch() may return index of maxentry of
+	 * the full page.
+	 */
+	if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT)))
+		return rc;
+
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	/* This test must follow XT_GETSEARCH since mp must be valid if
+	 * we branch to out: */
+	if (cmp == 0) {
+		rc = EEXIST;
+		goto out;
+	}
+
+	/*
+	 * allocate data extent requested
+	 *
+	 * allocation hint: last xad
+	 */
+	if ((xaddr = *xaddrp) == 0) {
+		if (index > XTENTRYSTART) {
+			xad = &p->xad[index - 1];
+			hint = addressXAD(xad) + lengthXAD(xad) - 1;
+		} else
+			hint = 0;
+		if ((rc = dbAlloc(ip, hint, (s64) xlen, &xaddr)))
+			goto out;
+	}
+
+	/*
+	 *      insert entry for new extent
+	 */
+	xflag |= XAD_NEW;
+
+	/*
+	 *      if the leaf page is full, split the page and
+	 *      propagate up the router entry for the new page from split
+	 *
+	 * The xtSplitUp() will insert the entry and unpin the leaf page.
+	 */
+	nextindex = le16_to_cpu(p->header.nextindex);
+	if (nextindex == le16_to_cpu(p->header.maxentry)) {
+		split.mp = mp;
+		split.index = index;
+		split.flag = xflag;
+		split.off = xoff;
+		split.len = xlen;
+		split.addr = xaddr;
+		split.pxdlist = NULL;
+		if ((rc = xtSplitUp(tid, ip, &split, &btstack))) {
+			/* undo data extent allocation */
+			if (*xaddrp == 0)
+				dbFree(ip, xaddr, (s64) xlen);
+			return rc;
+		}
+
+		*xaddrp = xaddr;
+		return 0;
+	}
+
+	/*
+	 *      insert the new entry into the leaf page
+	 */
+	/*
+	 * acquire a transaction lock on the leaf page;
+	 *
+	 * action: xad insertion/extension;
+	 */
+	BT_MARK_DIRTY(mp, ip);
+
+	/* if insert into middle, shift right remaining entries. */
+	if (index < nextindex)
+		memmove(&p->xad[index + 1], &p->xad[index],
+			(nextindex - index) * sizeof(xad_t));
+
+	/* insert the new entry: mark the entry NEW */
+	xad = &p->xad[index];
+	XT_PUTENTRY(xad, xflag, xoff, xlen, xaddr);
+
+	/* advance next available entry index */
+	p->header.nextindex =
+	    cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+
+	/* Don't log it if there are no links to the file */
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+		xtlck = (xtlock_t *) & tlck->lock;
+		xtlck->lwm.offset =
+		    (xtlck->lwm.offset) ? min(index,
+					      (int)xtlck->lwm.offset) : index;
+		xtlck->lwm.length =
+		    le16_to_cpu(p->header.nextindex) - xtlck->lwm.offset;
+	}
+
+	*xaddrp = xaddr;
+
+      out:
+	/* unpin the leaf page */
+	XT_PUTPAGE(mp);
+
+	return rc;
+}
+
+
+/*
+ *      xtSplitUp()
+ *
+ * function:
+ *      split full pages as propagating insertion up the tree
+ *
+ * parameter:
+ *      tid     - transaction id;
+ *      ip      - file object;
+ *      split   - entry parameter descriptor;
+ *      btstack - traverse stack from xtSearch()
+ *
+ * return:
+ */
+static int
+xtSplitUp(tid_t tid,
+	  struct inode *ip, xtsplit_t * split, btstack_t * btstack)
+{
+	int rc = 0;
+	metapage_t *smp;
+	xtpage_t *sp;		/* split page */
+	metapage_t *rmp;
+	s64 rbn;		/* new right page block number */
+	metapage_t *rcmp;
+	xtpage_t *rcp;		/* right child page */
+	s64 rcbn;		/* right child page block number */
+	int skip;		/* index of entry of insertion */
+	int nextindex;		/* next available entry index of p */
+	btframe_t *parent;	/* parent page entry on traverse stack */
+	xad_t *xad;
+	s64 xaddr;
+	int xlen;
+	int nsplit;		/* number of pages split */
+	pxdlist_t pxdlist;
+	pxd_t *pxd;
+	tlock_t *tlck;
+	xtlock_t *xtlck;
+
+	smp = split->mp;
+	sp = XT_PAGE(ip, smp);
+
+	/* is inode xtree root extension/inline EA area free ? */
+	if ((sp->header.flag & BT_ROOT) && (!S_ISDIR(ip->i_mode)) &&
+	    (sp->header.maxentry < cpu_to_le16(XTROOTMAXSLOT)) &&
+	    (JFS_IP(ip)->mode2 & INLINEEA)) {
+		sp->header.maxentry = cpu_to_le16(XTROOTMAXSLOT);
+		JFS_IP(ip)->mode2 &= ~INLINEEA;
+
+		BT_MARK_DIRTY(smp, ip);
+		/*
+		 * acquire a transaction lock on the leaf page;
+		 *
+		 * action: xad insertion/extension;
+		 */
+
+		/* if insert into middle, shift right remaining entries. */
+		skip = split->index;
+		nextindex = le16_to_cpu(sp->header.nextindex);
+		if (skip < nextindex)
+			memmove(&sp->xad[skip + 1], &sp->xad[skip],
+				(nextindex - skip) * sizeof(xad_t));
+
+		/* insert the new entry: mark the entry NEW */
+		xad = &sp->xad[skip];
+		XT_PUTENTRY(xad, split->flag, split->off, split->len,
+			    split->addr);
+
+		/* advance next available entry index */
+		sp->header.nextindex =
+		    cpu_to_le16(le16_to_cpu(sp->header.nextindex) + 1);
+
+		/* Don't log it if there are no links to the file */
+		if (!test_cflag(COMMIT_Nolink, ip)) {
+			tlck = txLock(tid, ip, smp, tlckXTREE | tlckGROW);
+			xtlck = (xtlock_t *) & tlck->lock;
+			xtlck->lwm.offset = (xtlck->lwm.offset) ?
+			    min(skip, (int)xtlck->lwm.offset) : skip;
+			xtlck->lwm.length =
+			    le16_to_cpu(sp->header.nextindex) -
+			    xtlck->lwm.offset;
+		}
+
+		return 0;
+	}
+
+	/*
+	 * allocate new index blocks to cover index page split(s)
+	 *
+	 * allocation hint: ?
+	 */
+	if (split->pxdlist == NULL) {
+		nsplit = btstack->nsplit;
+		split->pxdlist = &pxdlist;
+		pxdlist.maxnpxd = pxdlist.npxd = 0;
+		pxd = &pxdlist.pxd[0];
+		xlen = JFS_SBI(ip->i_sb)->nbperpage;
+		for (; nsplit > 0; nsplit--, pxd++) {
+			if ((rc = dbAlloc(ip, (s64) 0, (s64) xlen, &xaddr))
+			    == 0) {
+				PXDaddress(pxd, xaddr);
+				PXDlength(pxd, xlen);
+
+				pxdlist.maxnpxd++;
+
+				continue;
+			}
+
+			/* undo allocation */
+
+			XT_PUTPAGE(smp);
+			return rc;
+		}
+	}
+
+	/*
+	 * Split leaf page <sp> into <sp> and a new right page <rp>.
+	 *
+	 * The split routines insert the new entry into the leaf page,
+	 * and acquire txLock as appropriate.
+	 * return <rp> pinned and its block number <rpbn>.
+	 */
+	rc = (sp->header.flag & BT_ROOT) ?
+	    xtSplitRoot(tid, ip, split, &rmp) :
+	    xtSplitPage(tid, ip, split, &rmp, &rbn);
+	if (rc)
+		return EIO;
+
+	XT_PUTPAGE(smp);
+
+	/*
+	 * propagate up the router entry for the leaf page just split
+	 *
+	 * insert a router entry for the new page into the parent page,
+	 * propagate the insert/split up the tree by walking back the stack
+	 * of (bn of parent page, index of child page entry in parent page)
+	 * that were traversed during the search for the page that split.
+	 *
+	 * the propagation of insert/split up the tree stops if the root
+	 * splits or the page inserted into doesn't have to split to hold
+	 * the new entry.
+	 *
+	 * the parent entry for the split page remains the same, and
+	 * a new entry is inserted at its right with the first key and
+	 * block number of the new right page.
+	 *
+	 * There are a maximum of 3 pages pinned at any time:
+	 * right child, left parent and right parent (when the parent splits)
+	 * to keep the child page pinned while working on the parent.
+	 * make sure that all pins are released at exit.
+	 */
+	while ((parent = BT_POP(btstack)) != NULL) {
+		/* parent page specified by stack frame <parent> */
+
+		/* keep current child pages <rcp> pinned */
+		rcmp = rmp;
+		rcbn = rbn;
+		rcp = XT_PAGE(ip, rcmp);
+
+		/*
+		 * insert router entry in parent for new right child page <rp>
+		 */
+		/* get/pin the parent page <sp> */
+		XT_GETPAGE(ip, parent->bn, smp, PSIZE, sp, rc);
+		if (rc)
+			goto errout2;
+
+		/*
+		 * The new key entry goes ONE AFTER the index of parent entry,
+		 * because the split was to the right.
+		 */
+		skip = parent->index + 1;
+
+		/*
+		 * split or shift right remaining entries of the parent page
+		 */
+		nextindex = le16_to_cpu(sp->header.nextindex);
+		/*
+		 * parent page is full - split the parent page
+		 */
+		if (nextindex == le16_to_cpu(sp->header.maxentry)) {
+			/* init for parent page split */
+			split->mp = smp;
+			split->index = skip;	/* index at insert */
+			split->flag = XAD_NEW;
+			split->off = offsetXAD(&rcp->xad[XTENTRYSTART]);
+			split->len = JFS_SBI(ip->i_sb)->nbperpage;
+			split->addr = rcbn;
+
+			/* unpin previous right child page */
+			XT_PUTPAGE(rcmp);
+
+			/* The split routines insert the new entry,
+			 * and acquire txLock as appropriate.
+			 * return <rp> pinned and its block number <rpbn>.
+			 */
+			rc = (sp->header.flag & BT_ROOT) ?
+			    xtSplitRoot(tid, ip, split, &rmp) :
+			    xtSplitPage(tid, ip, split, &rmp, &rbn);
+			if (rc)
+				goto errout1;
+
+			XT_PUTPAGE(smp);
+			/* keep new child page <rp> pinned */
+		}
+		/*
+		 * parent page is not full - insert in parent page
+		 */
+		else {
+			/*
+			 * insert router entry in parent for the right child
+			 * page from the first entry of the right child page:
+			 */
+			/*
+			 * acquire a transaction lock on the parent page;
+			 *
+			 * action: router xad insertion;
+			 */
+			BT_MARK_DIRTY(smp, ip);
+
+			/*
+			 * if insert into middle, shift right remaining entries
+			 */
+			if (skip < nextindex)
+				memmove(&sp->xad[skip + 1], &sp->xad[skip],
+					(nextindex -
+					 skip) << L2XTSLOTSIZE);
+
+			/* insert the router entry */
+			xad = &sp->xad[skip];
+			XT_PUTENTRY(xad, XAD_NEW,
+				    offsetXAD(&rcp->xad[XTENTRYSTART]),
+				    JFS_SBI(ip->i_sb)->nbperpage, rcbn);
+
+			/* advance next available entry index. */
+			sp->header.nextindex =
+			    cpu_to_le16(le16_to_cpu(sp->header.nextindex) +
+					1);
+
+			/* Don't log it if there are no links to the file */
+			if (!test_cflag(COMMIT_Nolink, ip)) {
+				tlck = txLock(tid, ip, smp,
+					      tlckXTREE | tlckGROW);
+				xtlck = (xtlock_t *) & tlck->lock;
+				xtlck->lwm.offset = (xtlck->lwm.offset) ?
+				    min(skip, (int)xtlck->lwm.offset) : skip;
+				xtlck->lwm.length =
+				    le16_to_cpu(sp->header.nextindex) -
+				    xtlck->lwm.offset;
+			}
+
+			/* unpin parent page */
+			XT_PUTPAGE(smp);
+
+			/* exit propagate up */
+			break;
+		}
+	}
+
+	/* unpin current right page */
+	XT_PUTPAGE(rmp);
+
+	return 0;
+
+	/*
+	 * If something fails in the above loop we were already walking back
+	 * up the tree and the tree is now inconsistent.
+	 * release all pages we're holding.
+	 */
+      errout1:
+	XT_PUTPAGE(smp);
+
+      errout2:
+	XT_PUTPAGE(rcmp);
+
+	return rc;
+}
+
+
+/*
+ *      xtSplitPage()
+ *
+ * function:
+ *      split a full non-root page into
+ *      original/split/left page and new right page
+ *      i.e., the original/split page remains as left page.
+ *
+ * parameter:
+ *      int		tid,
+ *      struct inode    *ip,
+ *      xtsplit_t       *split,
+ *      metapage_t	**rmpp,
+ *      u64		*rbnp,
+ *
+ * return:
+ *      Pointer to page in which to insert or NULL on error.
+ */
+static int
+xtSplitPage(tid_t tid, struct inode *ip,
+	    xtsplit_t * split, metapage_t ** rmpp, s64 * rbnp)
+{
+	int rc = 0;
+	metapage_t *smp;
+	xtpage_t *sp;
+	metapage_t *rmp;
+	xtpage_t *rp;		/* new right page allocated */
+	s64 rbn;		/* new right page block number */
+	metapage_t *mp;
+	xtpage_t *p;
+	s64 nextbn;
+	int skip, maxentry, middle, righthalf, n;
+	xad_t *xad;
+	pxdlist_t *pxdlist;
+	pxd_t *pxd;
+	tlock_t *tlck;
+	xtlock_t *sxtlck = 0, *rxtlck = 0;
+
+	smp = split->mp;
+	sp = XT_PAGE(ip, smp);
+
+	INCREMENT(xtStat.split);
+
+	/*
+	 * allocate the new right page for the split
+	 */
+	pxdlist = split->pxdlist;
+	pxd = &pxdlist->pxd[pxdlist->npxd];
+	pxdlist->npxd++;
+	rbn = addressPXD(pxd);
+	rmp = get_metapage(ip, rbn, PSIZE, 1);
+	if (rmp == NULL)
+		return EIO;
+
+	jEVENT(0,
+	       ("xtSplitPage: ip:0x%p smp:0x%p rmp:0x%p\n", ip, smp, rmp));
+
+	BT_MARK_DIRTY(rmp, ip);
+	/*
+	 * action: new page;
+	 */
+
+	rp = (xtpage_t *) rmp->data;
+	rp->header.self = *pxd;
+	rp->header.flag = sp->header.flag & BT_TYPE;
+	rp->header.maxentry = sp->header.maxentry;	/* little-endian */
+	rp->header.nextindex = cpu_to_le16(XTENTRYSTART);
+
+	BT_MARK_DIRTY(smp, ip);
+	/* Don't log it if there are no links to the file */
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		/*
+		 * acquire a transaction lock on the new right page;
+		 */
+		tlck = txLock(tid, ip, rmp, tlckXTREE | tlckNEW);
+		rxtlck = (xtlock_t *) & tlck->lock;
+		rxtlck->lwm.offset = XTENTRYSTART;
+		/*
+		 * acquire a transaction lock on the split page
+		 */
+		tlck = txLock(tid, ip, smp, tlckXTREE | tlckGROW);
+		sxtlck = (xtlock_t *) & tlck->lock;
+	}
+
+	/*
+	 * initialize/update sibling pointers of <sp> and <rp>
+	 */
+	nextbn = le64_to_cpu(sp->header.next);
+	rp->header.next = cpu_to_le64(nextbn);
+	rp->header.prev = cpu_to_le64(addressPXD(&sp->header.self));
+	sp->header.next = cpu_to_le64(rbn);
+
+	skip = split->index;
+
+	/*
+	 *      sequential append at tail (after last entry of last page)
+	 *
+	 * if splitting the last page on a level because of appending
+	 * a entry to it (skip is maxentry), it's likely that the access is
+	 * sequential. adding an empty page on the side of the level is less
+	 * work and can push the fill factor much higher than normal.
+	 * if we're wrong it's no big deal -  we will do the split the right
+	 * way next time.
+	 * (it may look like it's equally easy to do a similar hack for
+	 * reverse sorted data, that is, split the tree left, but it's not.
+	 * Be my guest.)
+	 */
+	if (nextbn == 0 && skip == le16_to_cpu(sp->header.maxentry)) {
+		/*
+		 * acquire a transaction lock on the new/right page;
+		 *
+		 * action: xad insertion;
+		 */
+		/* insert entry at the first entry of the new right page */
+		xad = &rp->xad[XTENTRYSTART];
+		XT_PUTENTRY(xad, split->flag, split->off, split->len,
+			    split->addr);
+
+		rp->header.nextindex = cpu_to_le16(XTENTRYSTART + 1);
+
+		if (!test_cflag(COMMIT_Nolink, ip)) {
+			/* rxtlck->lwm.offset = XTENTRYSTART; */
+			rxtlck->lwm.length = 1;
+		}
+
+		*rmpp = rmp;
+		*rbnp = rbn;
+
+		ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd));
+
+		jEVENT(0, ("xtSplitPage: sp:0x%p rp:0x%p\n", sp, rp));
+		return 0;
+	}
+
+	/*
+	 *      non-sequential insert (at possibly middle page)
+	 */
+
+	/*
+	 * update previous pointer of old next/right page of <sp>
+	 */
+	if (nextbn != 0) {
+		XT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc);
+		if (rc) {
+			XT_PUTPAGE(rmp);
+			return rc;
+		}
+
+		BT_MARK_DIRTY(mp, ip);
+		/*
+		 * acquire a transaction lock on the next page;
+		 *
+		 * action:sibling pointer update;
+		 */
+		if (!test_cflag(COMMIT_Nolink, ip))
+			tlck = txLock(tid, ip, mp, tlckXTREE | tlckRELINK);
+
+		p->header.prev = cpu_to_le64(rbn);
+
+		/* sibling page may have been updated previously, or
+		 * it may be updated later;
+		 */
+
+		XT_PUTPAGE(mp);
+	}
+
+	/*
+	 * split the data between the split and new/right pages
+	 */
+	maxentry = le16_to_cpu(sp->header.maxentry);
+	middle = maxentry >> 1;
+	righthalf = maxentry - middle;
+
+	/*
+	 * skip index in old split/left page - insert into left page:
+	 */
+	if (skip <= middle) {
+		/* move right half of split page to the new right page */
+		memmove(&rp->xad[XTENTRYSTART], &sp->xad[middle],
+			righthalf << L2XTSLOTSIZE);
+
+		/* shift right tail of left half to make room for new entry */
+		if (skip < middle)
+			memmove(&sp->xad[skip + 1], &sp->xad[skip],
+				(middle - skip) << L2XTSLOTSIZE);
+
+		/* insert new entry */
+		xad = &sp->xad[skip];
+		XT_PUTENTRY(xad, split->flag, split->off, split->len,
+			    split->addr);
+
+		/* update page header */
+		sp->header.nextindex = cpu_to_le16(middle + 1);
+		if (!test_cflag(COMMIT_Nolink, ip)) {
+			sxtlck->lwm.offset = (sxtlck->lwm.offset) ?
+			    min(skip, (int)sxtlck->lwm.offset) : skip;
+		}
+
+		rp->header.nextindex =
+		    cpu_to_le16(XTENTRYSTART + righthalf);
+	}
+	/*
+	 * skip index in new right page - insert into right page:
+	 */
+	else {
+		/* move left head of right half to right page */
+		n = skip - middle;
+		memmove(&rp->xad[XTENTRYSTART], &sp->xad[middle],
+			n << L2XTSLOTSIZE);
+
+		/* insert new entry */
+		n += XTENTRYSTART;
+		xad = &rp->xad[n];
+		XT_PUTENTRY(xad, split->flag, split->off, split->len,
+			    split->addr);
+
+		/* move right tail of right half to right page */
+		if (skip < maxentry)
+			memmove(&rp->xad[n + 1], &sp->xad[skip],
+				(maxentry - skip) << L2XTSLOTSIZE);
+
+		/* update page header */
+		sp->header.nextindex = cpu_to_le16(middle);
+		if (!test_cflag(COMMIT_Nolink, ip)) {
+			sxtlck->lwm.offset = (sxtlck->lwm.offset) ?
+			    min(middle, (int)sxtlck->lwm.offset) : middle;
+		}
+
+		rp->header.nextindex = cpu_to_le16(XTENTRYSTART +
+						   righthalf + 1);
+	}
+
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		sxtlck->lwm.length = le16_to_cpu(sp->header.nextindex) -
+		    sxtlck->lwm.offset;
+
+		/* rxtlck->lwm.offset = XTENTRYSTART; */
+		rxtlck->lwm.length = le16_to_cpu(rp->header.nextindex) -
+		    XTENTRYSTART;
+	}
+
+	*rmpp = rmp;
+	*rbnp = rbn;
+
+	ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd));
+
+	jEVENT(0, ("xtSplitPage: sp:0x%p rp:0x%p\n", sp, rp));
+	return rc;
+}
+
+
+/*
+ *      xtSplitRoot()
+ *
+ * function:
+ *      split the full root page into
+ *      original/root/split page and new right page
+ *      i.e., root remains fixed in tree anchor (inode) and
+ *      the root is copied to a single new right child page
+ *      since root page << non-root page, and
+ *      the split root page contains a single entry for the
+ *      new right child page.
+ *
+ * parameter:
+ *      int		tid,
+ *      struct inode    *ip,
+ *      xtsplit_t       *split,
+ *      metapage_t	**rmpp)
+ *
+ * return:
+ *      Pointer to page in which to insert or NULL on error.
+ */
+static int
+xtSplitRoot(tid_t tid,
+	    struct inode *ip, xtsplit_t * split, metapage_t ** rmpp)
+{
+	xtpage_t *sp;
+	metapage_t *rmp;
+	xtpage_t *rp;
+	s64 rbn;
+	int skip, nextindex;
+	xad_t *xad;
+	pxd_t *pxd;
+	pxdlist_t *pxdlist;
+	tlock_t *tlck;
+	xtlock_t *xtlck;
+
+	sp = &JFS_IP(ip)->i_xtroot;
+
+	INCREMENT(xtStat.split);
+
+	/*
+	 *      allocate a single (right) child page
+	 */
+	pxdlist = split->pxdlist;
+	pxd = &pxdlist->pxd[pxdlist->npxd];
+	pxdlist->npxd++;
+	rbn = addressPXD(pxd);
+	rmp = get_metapage(ip, rbn, PSIZE, 1);
+	if (rmp == NULL)
+		return EIO;
+
+	jEVENT(0, ("xtSplitRoot: ip:0x%p rmp:0x%p\n", ip, rmp));
+
+	/*
+	 * acquire a transaction lock on the new right page;
+	 *
+	 * action: new page;
+	 */
+	BT_MARK_DIRTY(rmp, ip);
+
+	rp = (xtpage_t *) rmp->data;
+	rp->header.flag =
+	    (sp->header.flag & BT_LEAF) ? BT_LEAF : BT_INTERNAL;
+	rp->header.self = *pxd;
+	rp->header.nextindex = cpu_to_le16(XTENTRYSTART);
+	rp->header.maxentry = cpu_to_le16(PSIZE >> L2XTSLOTSIZE);
+
+	/* initialize sibling pointers */
+	rp->header.next = 0;
+	rp->header.prev = 0;
+
+	/*
+	 * copy the in-line root page into new right page extent
+	 */
+	nextindex = le16_to_cpu(sp->header.maxentry);
+	memmove(&rp->xad[XTENTRYSTART], &sp->xad[XTENTRYSTART],
+		(nextindex - XTENTRYSTART) << L2XTSLOTSIZE);
+
+	/*
+	 * insert the new entry into the new right/child page
+	 * (skip index in the new right page will not change)
+	 */
+	skip = split->index;
+	/* if insert into middle, shift right remaining entries */
+	if (skip != nextindex)
+		memmove(&rp->xad[skip + 1], &rp->xad[skip],
+			(nextindex - skip) * sizeof(xad_t));
+
+	xad = &rp->xad[skip];
+	XT_PUTENTRY(xad, split->flag, split->off, split->len, split->addr);
+
+	/* update page header */
+	rp->header.nextindex = cpu_to_le16(nextindex + 1);
+
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		tlck = txLock(tid, ip, rmp, tlckXTREE | tlckNEW);
+		xtlck = (xtlock_t *) & tlck->lock;
+		xtlck->lwm.offset = XTENTRYSTART;
+		xtlck->lwm.length = le16_to_cpu(rp->header.nextindex) -
+		    XTENTRYSTART;
+	}
+
+	/*
+	 *      reset the root
+	 *
+	 * init root with the single entry for the new right page
+	 * set the 1st entry offset to 0, which force the left-most key
+	 * at any level of the tree to be less than any search key.
+	 */
+	/*
+	 * acquire a transaction lock on the root page (in-memory inode);
+	 *
+	 * action: root split;
+	 */
+	BT_MARK_DIRTY(split->mp, ip);
+
+	xad = &sp->xad[XTENTRYSTART];
+	XT_PUTENTRY(xad, XAD_NEW, 0, JFS_SBI(ip->i_sb)->nbperpage, rbn);
+
+	/* update page header of root */
+	sp->header.flag &= ~BT_LEAF;
+	sp->header.flag |= BT_INTERNAL;
+
+	sp->header.nextindex = cpu_to_le16(XTENTRYSTART + 1);
+
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		tlck = txLock(tid, ip, split->mp, tlckXTREE | tlckGROW);
+		xtlck = (xtlock_t *) & tlck->lock;
+		xtlck->lwm.offset = XTENTRYSTART;
+		xtlck->lwm.length = 1;
+	}
+
+	*rmpp = rmp;
+
+	ip->i_blocks += LBLK2PBLK(ip->i_sb, lengthPXD(pxd));
+
+	jEVENT(0, ("xtSplitRoot: sp:0x%p rp:0x%p\n", sp, rp));
+	return 0;
+}
+
+
+/*
+ *      xtExtend()
+ *
+ * function: extend in-place;
+ *
+ * note: existing extent may or may not have been committed.
+ * caller is responsible for pager buffer cache update, and
+ * working block allocation map update;
+ * update pmap: alloc whole extended extent;
+ */
+int xtExtend(tid_t tid,		/* transaction id */
+	     struct inode *ip, s64 xoff,	/* delta extent offset */
+	     s32 xlen,		/* delta extent length */
+	     int flag)
+{
+	int rc = 0;
+	int cmp;
+	metapage_t *mp;		/* meta-page buffer */
+	xtpage_t *p;		/* base B+-tree index page */
+	s64 bn;
+	int index, nextindex, len;
+	btstack_t btstack;	/* traverse stack */
+	xtsplit_t split;	/* split information */
+	xad_t *xad;
+	s64 xaddr;
+	tlock_t *tlck;
+	xtlock_t *xtlck = 0;
+	int rootsplit = 0;
+
+	jFYI(1,
+	     ("xtExtend: nxoff:0x%lx nxlen:0x%x\n", (ulong) xoff, xlen));
+
+	/* there must exist extent to be extended */
+	if ((rc = xtSearch(ip, xoff - 1, &cmp, &btstack, XT_INSERT)))
+		return rc;
+	assert(cmp == 0);
+
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	/* extension must be contiguous */
+	xad = &p->xad[index];
+	jFYI(0, ("xtExtend: xoff:0x%lx xlen:0x%x xaddr:0x%lx\n",
+		 (ulong) offsetXAD(xad), lengthXAD(xad),
+		 (ulong) addressXAD(xad)));
+	assert((offsetXAD(xad) + lengthXAD(xad)) == xoff);
+
+	/*
+	 * acquire a transaction lock on the leaf page;
+	 *
+	 * action: xad insertion/extension;
+	 */
+	BT_MARK_DIRTY(mp, ip);
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+		xtlck = (xtlock_t *) & tlck->lock;
+	}
+
+	/* extend will overflow extent ? */
+	xlen = lengthXAD(xad) + xlen;
+	if ((len = xlen - MAXXLEN) <= 0)
+		goto extendOld;
+
+	/*
+	 *      extent overflow: insert entry for new extent
+	 */
+//insertNew:
+	xoff = offsetXAD(xad) + MAXXLEN;
+	xaddr = addressXAD(xad) + MAXXLEN;
+	nextindex = le16_to_cpu(p->header.nextindex);
+
+	/*
+	 *      if the leaf page is full, insert the new entry and
+	 *      propagate up the router entry for the new page from split
+	 *
+	 * The xtSplitUp() will insert the entry and unpin the leaf page.
+	 */
+	if (nextindex == le16_to_cpu(p->header.maxentry)) {
+		rootsplit = p->header.flag & BT_ROOT;
+
+		/* xtSpliUp() unpins leaf pages */
+		split.mp = mp;
+		split.index = index + 1;
+		split.flag = XAD_NEW;
+		split.off = xoff;	/* split offset */
+		split.len = len;
+		split.addr = xaddr;
+		split.pxdlist = NULL;
+		if ((rc = xtSplitUp(tid, ip, &split, &btstack)))
+			return rc;
+
+		/*
+		 * if leaf root has been split, original root has been
+		 * copied to new child page, i.e., original entry now
+		 * resides on the new child page;
+		 */
+		if (rootsplit) {
+			if (p->header.nextindex ==
+			    cpu_to_le16(XTENTRYSTART + 1)) {
+				xad = &p->xad[XTENTRYSTART];
+				bn = addressXAD(xad);
+
+				/* get new child page */
+				XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+
+				BT_MARK_DIRTY(mp, ip);
+				if (!test_cflag(COMMIT_Nolink, ip)) {
+					tlck = txLock(tid, ip, mp,
+						      tlckXTREE |
+						      tlckGROW);
+					xtlck = (xtlock_t *) & tlck->lock;
+				}
+			}
+		} else
+			/* get back old page */
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	}
+	/*
+	 *      insert the new entry into the leaf page
+	 */
+	else {
+		/* insert the new entry: mark the entry NEW */
+		xad = &p->xad[index + 1];
+		XT_PUTENTRY(xad, XAD_NEW, xoff, len, xaddr);
+
+		/* advance next available entry index */
+		p->header.nextindex =
+		    cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+	}
+
+	/* get back old entry */
+	xad = &p->xad[index];
+	xlen = MAXXLEN;
+
+	/*
+	 * extend old extent
+	 */
+      extendOld:
+	XADlength(xad, xlen);
+	if (!(xad->flag & XAD_NEW))
+		xad->flag |= XAD_EXTENDED;
+
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		xtlck->lwm.offset =
+		    (xtlck->lwm.offset) ? min(index,
+					      (int)xtlck->lwm.offset) : index;
+		xtlck->lwm.length =
+		    le16_to_cpu(p->header.nextindex) - xtlck->lwm.offset;
+	}
+
+	/* unpin the leaf page */
+	XT_PUTPAGE(mp);
+
+	return rc;
+}
+
+
+/*
+ *      xtTailgate()
+ *
+ * function: split existing 'tail' extent
+ *      (split offset >= start offset of tail extent), and
+ *      relocate and extend the split tail half;
+ *
+ * note: existing extent may or may not have been committed.
+ * caller is responsible for pager buffer cache update, and
+ * working block allocation map update;
+ * update pmap: free old split tail extent, alloc new extent;
+ */
+int xtTailgate(tid_t tid,		/* transaction id */
+	       struct inode *ip, s64 xoff,	/* split/new extent offset */
+	       s32 xlen,	/* new extent length */
+	       s64 xaddr,	/* new extent address */
+	       int flag)
+{
+	int rc = 0;
+	int cmp;
+	metapage_t *mp;		/* meta-page buffer */
+	xtpage_t *p;		/* base B+-tree index page */
+	s64 bn;
+	int index, nextindex, llen, rlen;
+	btstack_t btstack;	/* traverse stack */
+	xtsplit_t split;	/* split information */
+	xad_t *xad;
+	tlock_t *tlck;
+	xtlock_t *xtlck = 0;
+	tlock_t *mtlck;
+	maplock_t *pxdlock;
+	int rootsplit = 0;
+
+/*
+printf("xtTailgate: nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n",
+        (ulong)xoff, xlen, (ulong)xaddr);
+*/
+
+	/* there must exist extent to be tailgated */
+	if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT)))
+		return rc;
+	assert(cmp == 0);
+
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	/* entry found must be last entry */
+	nextindex = le16_to_cpu(p->header.nextindex);
+	assert(index == nextindex - 1);
+
+	BT_MARK_DIRTY(mp, ip);
+	/*
+	 * acquire tlock of the leaf page containing original entry
+	 */
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+		xtlck = (xtlock_t *) & tlck->lock;
+	}
+
+	/* completely replace extent ? */
+	xad = &p->xad[index];
+/*
+printf("xtTailgate: xoff:0x%lx xlen:0x%x xaddr:0x%lx\n",
+        (ulong)offsetXAD(xad), lengthXAD(xad), (ulong)addressXAD(xad));
+*/
+	if ((llen = xoff - offsetXAD(xad)) == 0)
+		goto updateOld;
+
+	/*
+	 *      partially replace extent: insert entry for new extent
+	 */
+//insertNew:
+	/*
+	 *      if the leaf page is full, insert the new entry and
+	 *      propagate up the router entry for the new page from split
+	 *
+	 * The xtSplitUp() will insert the entry and unpin the leaf page.
+	 */
+	if (nextindex == le16_to_cpu(p->header.maxentry)) {
+		rootsplit = p->header.flag & BT_ROOT;
+
+		/* xtSpliUp() unpins leaf pages */
+		split.mp = mp;
+		split.index = index + 1;
+		split.flag = XAD_NEW;
+		split.off = xoff;	/* split offset */
+		split.len = xlen;
+		split.addr = xaddr;
+		split.pxdlist = NULL;
+		if ((rc = xtSplitUp(tid, ip, &split, &btstack)))
+			return rc;
+
+		/*
+		 * if leaf root has been split, original root has been
+		 * copied to new child page, i.e., original entry now
+		 * resides on the new child page;
+		 */
+		if (rootsplit) {
+			if (p->header.nextindex ==
+			    cpu_to_le16(XTENTRYSTART + 1)) {
+				xad = &p->xad[XTENTRYSTART];
+				bn = addressXAD(xad);
+
+				/* get new child page */
+				XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+
+				BT_MARK_DIRTY(mp, ip);
+				if (!test_cflag(COMMIT_Nolink, ip)) {
+					tlck = txLock(tid, ip, mp,
+						      tlckXTREE |
+						      tlckGROW);
+					xtlck = (xtlock_t *) & tlck->lock;
+				}
+			}
+		} else
+			/* get back old page */
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	}
+	/*
+	 *      insert the new entry into the leaf page
+	 */
+	else {
+		/* insert the new entry: mark the entry NEW */
+		xad = &p->xad[index + 1];
+		XT_PUTENTRY(xad, XAD_NEW, xoff, xlen, xaddr);
+
+		/* advance next available entry index */
+		p->header.nextindex =
+		    cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+	}
+
+	/* get back old XAD */
+	xad = &p->xad[index];
+
+	/*
+	 * truncate/relocate old extent at split offset
+	 */
+      updateOld:
+	/* update dmap for old/committed/truncated extent */
+	rlen = lengthXAD(xad) - llen;
+	if (!(xad->flag & XAD_NEW)) {
+		/* free from PWMAP at commit */
+		if (!test_cflag(COMMIT_Nolink, ip)) {
+			mtlck = txMaplock(tid, ip, tlckMAP);
+			pxdlock = (maplock_t *) & mtlck->lock;
+			pxdlock->flag = mlckFREEPXD;
+			PXDaddress(&pxdlock->pxd, addressXAD(xad) + llen);
+			PXDlength(&pxdlock->pxd, rlen);
+			pxdlock->index = 1;
+		}
+		jEVENT(0,
+		       ("xtTailgate: free extent xaddr:0x%lx xlen:0x%x\n",
+			(ulong) addressPXD(&pxdlock->pxd),
+			lengthPXD(&pxdlock->pxd)));
+	} else
+		/* free from WMAP */
+		dbFree(ip, addressXAD(xad) + llen, (s64) rlen);
+
+	if (llen)
+		/* truncate */
+		XADlength(xad, llen);
+	else
+		/* replace */
+		XT_PUTENTRY(xad, XAD_NEW, xoff, xlen, xaddr);
+
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		xtlck->lwm.offset = (xtlck->lwm.offset) ?
+		    min(index, (int)xtlck->lwm.offset) : index;
+		xtlck->lwm.length = le16_to_cpu(p->header.nextindex) -
+		    xtlck->lwm.offset;
+	}
+
+	/* unpin the leaf page */
+	XT_PUTPAGE(mp);
+
+	return rc;
+}
+
+
+/*
+ *      xtUpdate()
+ *
+ * function: update XAD;
+ *
+ *      update extent for allocated_but_not_recorded or
+ *      compressed extent;
+ *
+ * parameter:
+ *      nxad    - new XAD;
+ *                logical extent of the specified XAD must be completely
+ *                contained by an existing XAD;
+ */
+int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
+{				/* new XAD */
+	int rc = 0;
+	int cmp;
+	metapage_t *mp;		/* meta-page buffer */
+	xtpage_t *p;		/* base B+-tree index page */
+	s64 bn;
+	int index0, index, newindex, nextindex;
+	btstack_t btstack;	/* traverse stack */
+	xtsplit_t split;	/* split information */
+	xad_t *xad, *lxad, *rxad;
+	int xflag;
+	s64 nxoff, xoff;
+	int nxlen, xlen, lxlen, rxlen;
+	s64 nxaddr, xaddr;
+	tlock_t *tlck;
+	xtlock_t *xtlck = 0;
+	int rootsplit = 0, newpage = 0;
+
+	/* there must exist extent to be tailgated */
+	nxoff = offsetXAD(nxad);
+	nxlen = lengthXAD(nxad);
+	nxaddr = addressXAD(nxad);
+/*
+printf("xtUpdate: nxflag:0x%x nxoff:0x%lx nxlen:0x%x nxaddr:0x%lx\n",
+        nxad->flag, (ulong)nxoff, nxlen, (ulong)nxaddr);
+*/
+	if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT)))
+		return rc;
+	assert(cmp == 0);
+
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0);
+
+	BT_MARK_DIRTY(mp, ip);
+	/*
+	 * acquire tlock of the leaf page containing original entry
+	 */
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+		xtlck = (xtlock_t *) & tlck->lock;
+	}
+
+	xad = &p->xad[index0];
+	xflag = xad->flag;
+	xoff = offsetXAD(xad);
+	xlen = lengthXAD(xad);
+	xaddr = addressXAD(xad);
+/*
+printf("xtUpdate: xflag:0x%x xoff:0x%lx xlen:0x%x xaddr:0x%lx\n",
+        xflag, (ulong)xoff, xlen, (ulong)xaddr);
+*/
+
+	/* nXAD must be completely contained within XAD */
+	assert(xoff <= nxoff);
+	assert(nxoff + nxlen <= xoff + xlen);
+
+	index = index0;
+	newindex = index + 1;
+	nextindex = le16_to_cpu(p->header.nextindex);
+
+#ifdef  _JFS_WIP_NOCOALESCE
+	if (xoff < nxoff)
+		goto updateRight;
+
+	/*
+	 * replace XAD with nXAD
+	 */
+      replace:			/* (nxoff == xoff) */
+	if (nxlen == xlen) {
+		/* replace XAD with nXAD:recorded */
+		*xad = *nxad;
+		xad->flag = xflag & ~XAD_NOTRECORDED;
+
+		goto out;
+	} else			/* (nxlen < xlen) */
+		goto updateLeft;
+#endif				/* _JFS_WIP_NOCOALESCE */
+
+/* #ifdef _JFS_WIP_COALESCE */
+	if (xoff < nxoff)
+		goto coalesceRight;
+
+	/*
+	 * coalesce with left XAD
+	 */
+//coalesceLeft: /* (xoff == nxoff) */
+	/* is XAD first entry of page ? */
+	if (index == XTENTRYSTART)
+		goto replace;
+
+	/* is nXAD logically and physically contiguous with lXAD ? */
+	lxad = &p->xad[index - 1];
+	lxlen = lengthXAD(lxad);
+	if (!(lxad->flag & XAD_NOTRECORDED) &&
+	    (nxoff == offsetXAD(lxad) + lxlen) &&
+	    (nxaddr == addressXAD(lxad) + lxlen) &&
+	    (lxlen + nxlen < MAXXLEN)) {
+		/* extend right lXAD */
+		index0 = index - 1;
+		XADlength(lxad, lxlen + nxlen);
+
+		/* If we just merged two extents together, need to make sure the
+		 * right extent gets logged.  If the left one is marked XAD_NEW,
+		 * then we know it will be logged.  Otherwise, mark as
+		 * XAD_EXTENDED
+		 */
+		if (!(lxad->flag & XAD_NEW))
+			lxad->flag |= XAD_EXTENDED;
+
+		if (xlen > nxlen) {
+			/* truncate XAD */
+			XADoffset(xad, xoff + nxlen);
+			XADlength(xad, xlen - nxlen);
+			XADaddress(xad, xaddr + nxlen);
+			goto out;
+		} else {	/* (xlen == nxlen) */
+
+			/* remove XAD */
+			if (index < nextindex - 1)
+				memmove(&p->xad[index], &p->xad[index + 1],
+					(nextindex - index -
+					 1) << L2XTSLOTSIZE);
+
+			p->header.nextindex =
+			    cpu_to_le16(le16_to_cpu(p->header.nextindex) -
+					1);
+
+			index = index0;
+			newindex = index + 1;
+			nextindex = le16_to_cpu(p->header.nextindex);
+			xoff = nxoff = offsetXAD(lxad);
+			xlen = nxlen = lxlen + nxlen;
+			xaddr = nxaddr = addressXAD(lxad);
+			goto coalesceRight;
+		}
+	}
+
+	/*
+	 * replace XAD with nXAD
+	 */
+      replace:			/* (nxoff == xoff) */
+	if (nxlen == xlen) {
+		/* replace XAD with nXAD:recorded */
+		*xad = *nxad;
+		xad->flag = xflag & ~XAD_NOTRECORDED;
+
+		goto coalesceRight;
+	} else			/* (nxlen < xlen) */
+		goto updateLeft;
+
+	/*
+	 * coalesce with right XAD
+	 */
+      coalesceRight:		/* (xoff <= nxoff) */
+	/* is XAD last entry of page ? */
+	if (newindex == nextindex) {
+		if (xoff == nxoff)
+			goto out;
+		goto updateRight;
+	}
+
+	/* is nXAD logically and physically contiguous with rXAD ? */
+	rxad = &p->xad[index + 1];
+	rxlen = lengthXAD(rxad);
+	if (!(rxad->flag & XAD_NOTRECORDED) &&
+	    (nxoff + nxlen == offsetXAD(rxad)) &&
+	    (nxaddr + nxlen == addressXAD(rxad)) &&
+	    (rxlen + nxlen < MAXXLEN)) {
+		/* extend left rXAD */
+		XADoffset(rxad, nxoff);
+		XADlength(rxad, rxlen + nxlen);
+		XADaddress(rxad, nxaddr);
+
+		/* If we just merged two extents together, need to make sure
+		 * the left extent gets logged.  If the right one is marked
+		 * XAD_NEW, then we know it will be logged.  Otherwise, mark as
+		 * XAD_EXTENDED
+		 */
+		if (!(rxad->flag & XAD_NEW))
+			rxad->flag |= XAD_EXTENDED;
+
+		if (xlen > nxlen)
+			/* truncate XAD */
+			XADlength(xad, xlen - nxlen);
+		else {		/* (xlen == nxlen) */
+
+			/* remove XAD */
+			memmove(&p->xad[index], &p->xad[index + 1],
+				(nextindex - index - 1) << L2XTSLOTSIZE);
+
+			p->header.nextindex =
+			    cpu_to_le16(le16_to_cpu(p->header.nextindex) -
+					1);
+		}
+
+		goto out;
+	} else if (xoff == nxoff)
+		goto out;
+
+	assert(xoff < nxoff);
+/* #endif _JFS_WIP_COALESCE */
+
+	/*
+	 * split XAD into (lXAD, nXAD):
+	 *
+	 *          |---nXAD--->
+	 * --|----------XAD----------|--
+	 *   |-lXAD-|
+	 */
+      updateRight:		/* (xoff < nxoff) */
+	/* truncate old XAD as lXAD:not_recorded */
+	xad = &p->xad[index];
+	XADlength(xad, nxoff - xoff);
+
+	/* insert nXAD:recorded */
+	if (nextindex == le16_to_cpu(p->header.maxentry)) {
+/*
+printf("xtUpdate.updateRight.split p:0x%p\n", p);
+*/
+		rootsplit = p->header.flag & BT_ROOT;
+
+		/* xtSpliUp() unpins leaf pages */
+		split.mp = mp;
+		split.index = newindex;
+		split.flag = xflag & ~XAD_NOTRECORDED;
+		split.off = nxoff;
+		split.len = nxlen;
+		split.addr = nxaddr;
+		split.pxdlist = NULL;
+		if ((rc = xtSplitUp(tid, ip, &split, &btstack)))
+			return rc;
+
+		/*
+		 * if leaf root has been split, original root has been
+		 * copied to new child page, i.e., original entry now
+		 * resides on the new child page;
+		 */
+		if (rootsplit) {
+			if (p->header.nextindex ==
+			    cpu_to_le16(XTENTRYSTART + 1)) {
+				xad = &p->xad[XTENTRYSTART];
+				bn = addressXAD(xad);
+
+				/* get new child page */
+				XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+
+				BT_MARK_DIRTY(mp, ip);
+				if (!test_cflag(COMMIT_Nolink, ip)) {
+					tlck = txLock(tid, ip, mp,
+						      tlckXTREE |
+						      tlckGROW);
+					xtlck = (xtlock_t *) & tlck->lock;
+				}
+			}
+		} else {
+			/* get back old page */
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+
+			/* is nXAD on new page ? */
+			if (newindex >
+			    (le16_to_cpu(p->header.maxentry) >> 1)) {
+				newindex =
+				    newindex -
+				    le16_to_cpu(p->header.nextindex) +
+				    XTENTRYSTART;
+				newpage = 1;
+			}
+		}
+	} else {
+		/* if insert into middle, shift right remaining entries */
+		if (newindex < nextindex)
+			memmove(&p->xad[newindex + 1], &p->xad[newindex],
+				(nextindex - newindex) << L2XTSLOTSIZE);
+
+		/* insert the entry */
+		xad = &p->xad[newindex];
+		*xad = *nxad;
+		xad->flag = xflag & ~XAD_NOTRECORDED;
+
+		/* advance next available entry index. */
+		p->header.nextindex =
+		    cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+	}
+
+	/*
+	 * does nXAD force 3-way split ?
+	 *
+	 *          |---nXAD--->|
+	 * --|----------XAD-------------|--
+	 *   |-lXAD-|           |-rXAD -|
+	 */
+	if (nxoff + nxlen == xoff + xlen)
+		goto out;
+
+	/* reorient nXAD as XAD for further split XAD into (nXAD, rXAD) */
+	if (newpage) {
+		/* close out old page */
+		if (!test_cflag(COMMIT_Nolink, ip)) {
+			xtlck->lwm.offset = (xtlck->lwm.offset) ?
+			    min(index0, (int)xtlck->lwm.offset) : index0;
+			xtlck->lwm.length =
+			    le16_to_cpu(p->header.nextindex) -
+			    xtlck->lwm.offset;
+		}
+
+		bn = le64_to_cpu(p->header.next);
+		XT_PUTPAGE(mp);
+
+		/* get new right page */
+		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+
+		BT_MARK_DIRTY(mp, ip);
+		if (!test_cflag(COMMIT_Nolink, ip)) {
+			tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+			xtlck = (xtlock_t *) & tlck->lock;
+		}
+
+		index0 = index = newindex;
+	} else
+		index++;
+
+	newindex = index + 1;
+	nextindex = le16_to_cpu(p->header.nextindex);
+	xlen = xlen - (nxoff - xoff);
+	xoff = nxoff;
+	xaddr = nxaddr;
+
+	/* recompute split pages */
+	if (nextindex == le16_to_cpu(p->header.maxentry)) {
+/*
+printf("xtUpdate: updateRight+Left recompute split pages: p:0x%p\n", p);
+*/
+		XT_PUTPAGE(mp);
+
+		if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT)))
+			return rc;
+		assert(cmp == 0);
+
+		/* retrieve search result */
+		XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0);
+		assert(index0 == index);
+	}
+
+	/*
+	 * split XAD into (nXAD, rXAD)
+	 *
+	 *          ---nXAD---|
+	 * --|----------XAD----------|--
+	 *                    |-rXAD-|
+	 */
+      updateLeft:		/* (nxoff == xoff) && (nxlen < xlen) */
+	/* update old XAD with nXAD:recorded */
+	xad = &p->xad[index];
+	*xad = *nxad;
+	xad->flag = xflag & ~XAD_NOTRECORDED;
+
+	/* insert rXAD:not_recorded */
+	xoff = xoff + nxlen;
+	xlen = xlen - nxlen;
+	xaddr = xaddr + nxlen;
+	if (nextindex == le16_to_cpu(p->header.maxentry)) {
+		rootsplit = p->header.flag & BT_ROOT;
+
+/*
+printf("xtUpdate.updateLeft.split p:0x%p\n", p);
+*/
+		/* xtSpliUp() unpins leaf pages */
+		split.mp = mp;
+		split.index = newindex;
+		split.flag = xflag;
+		split.off = xoff;
+		split.len = xlen;
+		split.addr = xaddr;
+		split.pxdlist = NULL;
+		if ((rc = xtSplitUp(tid, ip, &split, &btstack)))
+			return rc;
+
+		/*
+		 * if leaf root has been split, original root has been
+		 * copied to new child page, i.e., original entry now
+		 * resides on the new child page;
+		 */
+		if (rootsplit) {
+			if (p->header.nextindex ==
+			    cpu_to_le16(XTENTRYSTART + 1)) {
+				xad = &p->xad[XTENTRYSTART];
+				bn = addressXAD(xad);
+
+				/* get new child page */
+				XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+
+				BT_MARK_DIRTY(mp, ip);
+				if (!test_cflag(COMMIT_Nolink, ip)) {
+					tlck = txLock(tid, ip, mp,
+						      tlckXTREE |
+						      tlckGROW);
+					xtlck = (xtlock_t *) & tlck->lock;
+				}
+			}
+		} else
+			/* get back old page */
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	} else {
+		/* if insert into middle, shift right remaining entries */
+		if (newindex < nextindex)
+			memmove(&p->xad[newindex + 1], &p->xad[newindex],
+				(nextindex - newindex) << L2XTSLOTSIZE);
+
+		/* insert the entry */
+		xad = &p->xad[newindex];
+		XT_PUTENTRY(xad, xflag, xoff, xlen, xaddr);
+
+		/* advance next available entry index. */
+		p->header.nextindex =
+		    cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+	}
+
+      out:
+	if (!test_cflag(COMMIT_Nolink, ip)) {
+		xtlck->lwm.offset = (xtlck->lwm.offset) ?
+		    min(index0, (int)xtlck->lwm.offset) : index0;
+		xtlck->lwm.length = le16_to_cpu(p->header.nextindex) -
+		    xtlck->lwm.offset;
+	}
+
+	/* unpin the leaf page */
+	XT_PUTPAGE(mp);
+
+	return rc;
+}
+
+
+#ifdef _STILL_TO_PORT
+/*
+ *      xtAppend()
+ *
+ * function: grow in append mode from contiguous region specified ;
+ *
+ * parameter:
+ *      tid             - transaction id;
+ *      ip              - file object;
+ *      xflag           - extent flag:
+ *      xoff            - extent offset;
+ *      maxblocks       - max extent length;
+ *      xlen            - extent length (in/out);
+ *      xaddrp          - extent address pointer (in/out):
+ *      flag            -
+ *
+ * return:
+ */
+int xtAppend(tid_t tid,		/* transaction id */
+	     struct inode *ip, int xflag, s64 xoff, s32 maxblocks,	/* @GD1 */
+	     s32 * xlenp,	/* (in/out) */
+	     s64 * xaddrp,	/* (in/out) */
+	     int flag)
+{
+	int rc = 0;
+	metapage_t *mp;		/* meta-page buffer */
+	xtpage_t *p;		/* base B+-tree index page */
+	s64 bn, xaddr;
+	int index, nextindex;
+	btstack_t btstack;	/* traverse stack */
+	xtsplit_t split;	/* split information */
+	xad_t *xad;
+	int cmp;
+	tlock_t *tlck;
+	xtlock_t *xtlck;
+	int nsplit, nblocks, xlen;
+	pxdlist_t pxdlist;
+	pxd_t *pxd;
+
+	xaddr = *xaddrp;
+	xlen = *xlenp;
+	jEVENT(0,
+	       ("xtAppend: xoff:0x%lx maxblocks:%d xlen:%d xaddr:0x%lx\n",
+		(ulong) xoff, maxblocks, xlen, (ulong) xaddr));
+
+	/*
+	 *      search for the entry location at which to insert:
+	 *
+	 * xtFastSearch() and xtSearch() both returns (leaf page
+	 * pinned, index at which to insert).
+	 * n.b. xtSearch() may return index of maxentry of
+	 * the full page.
+	 */
+	if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT)))
+		return rc;
+
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
+	if (cmp == 0) {
+		rc = EEXIST;
+		goto out;
+	}
+//insert:
+	/*
+	 *      insert entry for new extent
+	 */
+	xflag |= XAD_NEW;
+
+	/*
+	 *      if the leaf page is full, split the page and
+	 *      propagate up the router entry for the new page from split
+	 *
+	 * The xtSplitUp() will insert the entry and unpin the leaf page.
+	 */
+	nextindex = le16_to_cpu(p->header.nextindex);
+	if (nextindex < le16_to_cpu(p->header.maxentry))
+		goto insertLeaf;
+
+	/*
+	 * allocate new index blocks to cover index page split(s)
+	 */
+	nsplit = btstack.nsplit;
+	split.pxdlist = &pxdlist;
+	pxdlist.maxnpxd = pxdlist.npxd = 0;
+	pxd = &pxdlist.pxd[0];
+	nblocks = JFS_SBI(ip->i_sb)->nbperpage;
+	for (; nsplit > 0; nsplit--, pxd++, xaddr += nblocks, maxblocks -= nblocks) {	/* @GD1 */
+		if ((rc = dbAllocBottomUp(ip, xaddr, (s64) nblocks)) == 0) {
+			PXDaddress(pxd, xaddr);
+			PXDlength(pxd, nblocks);
+
+			pxdlist.maxnpxd++;
+
+			continue;
+		}
+
+		/* undo allocation */
+
+		goto out;
+	}
+
+	xlen = min(xlen, maxblocks);	/* @GD1 */
+
+	/*
+	 * allocate data extent requested
+	 */
+	if ((rc = dbAllocBottomUp(ip, xaddr, (s64) xlen)))
+		goto out;
+
+	split.mp = mp;
+	split.index = index;
+	split.flag = xflag;
+	split.off = xoff;
+	split.len = xlen;
+	split.addr = xaddr;
+	if ((rc = xtSplitUp(tid, ip, &split, &btstack))) {
+		/* undo data extent allocation */
+		dbFree(ip, *xaddrp, (s64) * xlenp);
+
+		return rc;
+	}
+
+	*xaddrp = xaddr;
+	*xlenp = xlen;
+	return 0;
+
+	/*
+	 *      insert the new entry into the leaf page
+	 */
+      insertLeaf:
+	/*
+	 * allocate data extent requested
+	 */
+	if ((rc = dbAllocBottomUp(ip, xaddr, (s64) xlen)))
+		goto out;
+
+	BT_MARK_DIRTY(mp, ip);
+	/*
+	 * acquire a transaction lock on the leaf page;
+	 *
+	 * action: xad insertion/extension;
+	 */
+	tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
+	xtlck = (xtlock_t *) & tlck->lock;
+
+	/* insert the new entry: mark the entry NEW */
+	xad = &p->xad[index];
+	XT_PUTENTRY(xad, xflag, xoff, xlen, xaddr);
+
+	/* advance next available entry index */
+	p->header.nextindex =
+	    cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
+
+	xtlck->lwm.offset =
+	    (xtlck->lwm.offset) ? min(index, xtlck->lwm.offset) : index;
+	xtlck->lwm.length = le16_to_cpu(p->header.nextindex) -
+	    xtlck->lwm.offset;
+
+	*xaddrp = xaddr;
+	*xlenp = xlen;
+
+      out:
+	/* unpin the leaf page */
+	XT_PUTPAGE(mp);
+
+	return rc;
+}
+
+
+/* - TBD for defragmentaion/reorganization -
+ *
+ *      xtDelete()
+ *
+ * function:
+ *      delete the entry with the specified key.
+ *
+ *      N.B.: whole extent of the entry is assumed to be deleted.
+ *
+ * parameter:
+ *
+ * return:
+ *       ENOENT: if the entry is not found.
+ *
+ * exception:
+ */
+int xtDelete(tid_t tid, struct inode *ip, s64 xoff, s32 xlen, int flag)
+{
+	int rc = 0;
+	btstack_t btstack;
+	int cmp;
+	s64 bn;
+	metapage_t *mp;
+	xtpage_t *p;
+	int index, nextindex;
+	tlock_t *tlck;
+	xtlock_t *xtlck;
+
+	/*
+	 * find the matching entry; xtSearch() pins the page
+	 */
+	if ((rc = xtSearch(ip, xoff, &cmp, &btstack, 0)))
+		return rc;
+
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+	if (cmp) {
+		/* unpin the leaf page */
+		XT_PUTPAGE(mp);
+		return ENOENT;
+	}
+
+	/*
+	 * delete the entry from the leaf page
+	 */
+	nextindex = le16_to_cpu(p->header.nextindex);
+	p->header.nextindex =
+	    cpu_to_le16(le16_to_cpu(p->header.nextindex) - 1);
+
+	/*
+	 * if the leaf page bocome empty, free the page
+	 */
+	if (p->header.nextindex == cpu_to_le16(XTENTRYSTART))
+		return (xtDeleteUp(tid, ip, mp, p, &btstack));
+
+	BT_MARK_DIRTY(mp, ip);
+	/*
+	 * acquire a transaction lock on the leaf page;
+	 *
+	 * action:xad deletion;
+	 */
+	tlck = txLock(tid, ip, mp, tlckXTREE);
+	xtlck = (xtlock_t *) & tlck->lock;
+	xtlck->lwm.offset =
+	    (xtlck->lwm.offset) ? min(index, xtlck->lwm.offset) : index;
+
+	/* if delete from middle, shift left/compact the remaining entries */
+	if (index < nextindex - 1)
+		memmove(&p->xad[index], &p->xad[index + 1],
+			(nextindex - index - 1) * sizeof(xad_t));
+
+	XT_PUTPAGE(mp);
+
+	return 0;
+}
+
+
+/* - TBD for defragmentaion/reorganization -
+ *
+ *      xtDeleteUp()
+ *
+ * function:
+ *      free empty pages as propagating deletion up the tree
+ *
+ * parameter:
+ *
+ * return:
+ */
+static int
+xtDeleteUp(tid_t tid,
+	   struct inode *ip,
+	   metapage_t * fmp, xtpage_t * fp, btstack_t * btstack)
+{
+	int rc = 0;
+	metapage_t *mp;
+	xtpage_t *p;
+	int index, nextindex;
+	s64 xaddr;
+	int xlen;
+	btframe_t *parent;
+	tlock_t *tlck;
+	xtlock_t *xtlck;
+
+	/*
+	 * keep root leaf page which has become empty
+	 */
+	if (fp->header.flag & BT_ROOT) {
+		/* keep the root page */
+		fp->header.flag &= ~BT_INTERNAL;
+		fp->header.flag |= BT_LEAF;
+		fp->header.nextindex = cpu_to_le16(XTENTRYSTART);
+
+		/* XT_PUTPAGE(fmp); */
+
+		return 0;
+	}
+
+	/*
+	 * free non-root leaf page
+	 */
+	if ((rc = xtRelink(tid, ip, fp)))
+		return rc;
+
+	xaddr = addressPXD(&fp->header.self);
+	xlen = lengthPXD(&fp->header.self);
+	/* free the page extent */
+	dbFree(ip, xaddr, (s64) xlen);
+
+	/* free the buffer page */
+	discard_metapage(fmp);
+
+	/*
+	 * propagate page deletion up the index tree
+	 *
+	 * If the delete from the parent page makes it empty,
+	 * continue all the way up the tree.
+	 * stop if the root page is reached (which is never deleted) or
+	 * if the entry deletion does not empty the page.
+	 */
+	while ((parent = BT_POP(btstack)) != NULL) {
+		/* get/pin the parent page <sp> */
+		XT_GETPAGE(ip, parent->bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		index = parent->index;
+
+		/* delete the entry for the freed child page from parent.
+		 */
+		nextindex = le16_to_cpu(p->header.nextindex);
+
+		/*
+		 * the parent has the single entry being deleted:
+		 * free the parent page which has become empty.
+		 */
+		if (nextindex == 1) {
+			if (p->header.flag & BT_ROOT) {
+				/* keep the root page */
+				p->header.flag &= ~BT_INTERNAL;
+				p->header.flag |= BT_LEAF;
+				p->header.nextindex =
+				    cpu_to_le16(XTENTRYSTART);
+
+				/* XT_PUTPAGE(fmp); */
+
+				break;
+			} else {
+				/* free the parent page */
+				if ((rc = xtRelink(tid, ip, p)))
+					return rc;
+
+				xaddr = addressPXD(&p->header.self);
+				/* free the page extent */
+				dbFree(ip, xaddr,
+				       (s64) JFS_SBI(ip->i_sb)->nbperpage);
+
+				/* unpin/free the buffer page */
+				discard_metapage(fmp);
+
+				/* propagate up */
+				continue;
+			}
+		}
+		/*
+		 * the parent has other entries remaining:
+		 * delete the router entry from the parent page.
+		 */
+		else {
+			BT_MARK_DIRTY(mp, ip);
+			/*
+			 * acquire a transaction lock on the leaf page;
+			 *
+			 * action:xad deletion;
+			 */
+			tlck = txLock(tid, ip, mp, tlckXTREE);
+			xtlck = (xtlock_t *) & tlck->lock;
+			xtlck->lwm.offset =
+			    (xtlck->lwm.offset) ? min(index,
+						      xtlck->lwm.
+						      offset) : index;
+
+			/* if delete from middle,
+			 * shift left/compact the remaining entries in the page
+			 */
+			if (index < nextindex - 1)
+				memmove(&p->xad[index], &p->xad[index + 1],
+					(nextindex - index -
+					 1) << L2XTSLOTSIZE);
+
+			p->header.nextindex =
+			    cpu_to_le16(le16_to_cpu(p->header.nextindex) -
+					1);
+			jEVENT(0,
+			       ("xtDeleteUp(entry): 0x%lx[%d]\n",
+				(ulong) parent->bn, index));
+		}
+
+		/* unpin the parent page */
+		XT_PUTPAGE(mp);
+
+		/* exit propagation up */
+		break;
+	}
+
+	return 0;
+}
+
+
+/*
+ * NAME:        xtRelocate()
+ *
+ * FUNCTION:    relocate xtpage or data extent of regular file;
+ *              This function is mainly used by defragfs utility.
+ *
+ * NOTE:        This routine does not have the logic to handle
+ *              uncommitted allocated extent. The caller should call
+ *              txCommit() to commit all the allocation before call
+ *              this routine.
+ */
+xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad,	/* old XAD */
+	   s64 nxaddr,		/* new xaddr */
+	   int xtype)
+{				/* extent type: XTPAGE or DATAEXT */
+	int rc = 0;
+	tblock_t *tblk;
+	tlock_t *tlck;
+	xtlock_t *xtlck;
+	metapage_t *mp, *pmp, *lmp, *rmp;	/* meta-page buffer */
+	xtpage_t *p, *pp, *rp, *lp;	/* base B+-tree index page */
+	xad_t *xad;
+	pxd_t *pxd;
+	s64 xoff, xsize;
+	int xlen;
+	s64 oxaddr, sxaddr, dxaddr, nextbn, prevbn;
+	cbuf_t *cp;
+	s64 offset, nbytes, nbrd, pno;
+	int nb, npages, nblks;
+	s64 bn;
+	int cmp;
+	int index;
+	pxdlock_t *pxdlock;
+	btstack_t btstack;	/* traverse stack */
+
+	xtype = xtype & EXTENT_TYPE;
+
+	xoff = offsetXAD(oxad);
+	oxaddr = addressXAD(oxad);
+	xlen = lengthXAD(oxad);
+
+	/* validate extent offset */
+	offset = xoff << JFS_SBI(ip->i_sb)->l2bsize;
+	if (offset >= ip->i_size)
+		return ESTALE;	/* stale extent */
+
+	jEVENT(0,
+	       ("xtRelocate: xtype:%d xoff:0x%lx xlen:0x%x xaddr:0x%lx:0x%lx\n",
+		xtype, (ulong) xoff, xlen, (ulong) oxaddr,
+		(ulong) nxaddr));
+
+	/*
+	 *      1. get and validate the parent xtpage/xad entry
+	 *      covering the source extent to be relocated;
+	 */
+	if (xtype == DATAEXT) {
+		/* search in leaf entry */
+		rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
+		if (rc)
+			return rc;
+		if (cmp) {
+			XT_PUTPAGE(pmp);
+			return ESTALE;
+		}
+
+		/* retrieve search result */
+		XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
+
+		/* validate for exact match with a single entry */
+		xad = &pp->xad[index];
+		if (addressXAD(xad) != oxaddr || lengthXAD(xad) != xlen) {
+			XT_PUTPAGE(pmp);
+			return ESTALE;
+		}
+	} else {		/* (xtype == XTPAGE) */
+
+		/* search in internal entry */
+		rc = xtSearchNode(ip, oxad, &cmp, &btstack, 0);
+		if (rc)
+			return rc;
+		if (cmp) {
+			XT_PUTPAGE(pmp);
+			return ESTALE;
+		}
+
+		/* retrieve search result */
+		XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
+
+		/* xtSearchNode() validated for exact match with a single entry
+		 */
+		xad = &pp->xad[index];
+	}
+	jEVENT(0, ("xtRelocate: parent xad entry validated.\n"));
+
+	/*
+	 *      2. relocate the extent
+	 */
+	if (xtype == DATAEXT) {
+		/* if the extent is allocated-but-not-recorded
+		 * there is no real data to be moved in this extent,
+		 */
+		if (xad->flag & XAD_NOTRECORDED)
+			goto out;
+		else
+			/* release xtpage for cmRead()/xtLookup() */
+			XT_PUTPAGE(pmp);
+
+		/*
+		 *      cmRelocate()
+		 *
+		 * copy target data pages to be relocated;
+		 *
+		 * data extent must start at page boundary and
+		 * multiple of page size (except the last data extent);
+		 * read in each page of the source data extent into cbuf,
+		 * update the cbuf extent descriptor of the page to be
+		 * homeward bound to new dst data extent
+		 * copy the data from the old extent to new extent.
+		 * copy is essential for compressed files to avoid problems
+		 * that can arise if there was a change in compression
+		 * algorithms.
+		 * it is a good strategy because it may disrupt cache
+		 * policy to keep the pages in memory afterwards.
+		 */
+		offset = xoff << JFS_SBI(ip->i_sb)->l2bsize;
+		assert((offset & CM_OFFSET) == 0);
+		nbytes = xlen << JFS_SBI(ip->i_sb)->l2bsize;
+		pno = offset >> CM_L2BSIZE;
+		npages = (nbytes + (CM_BSIZE - 1)) >> CM_L2BSIZE;
+/*
+                npages = ((offset + nbytes - 1) >> CM_L2BSIZE) -
+                         (offset >> CM_L2BSIZE) + 1;
+*/
+		sxaddr = oxaddr;
+		dxaddr = nxaddr;
+
+		/* process the request one cache buffer at a time */
+		for (nbrd = 0; nbrd < nbytes; nbrd += nb,
+		     offset += nb, pno++, npages--) {
+			/* compute page size */
+			nb = min(nbytes - nbrd, CM_BSIZE);
+
+			/* get the cache buffer of the page */
+			if (rc = cmRead(ip, offset, npages, &cp))
+				break;
+
+			assert(addressPXD(&cp->cm_pxd) == sxaddr);
+			assert(!cp->cm_modified);
+
+			/* bind buffer with the new extent address */
+			nblks = nb >> JFS_IP(ip->i_sb)->l2bsize;
+			cmSetXD(ip, cp, pno, dxaddr, nblks);
+
+			/* release the cbuf, mark it as modified */
+			cmPut(cp, TRUE);
+
+			dxaddr += nblks;
+			sxaddr += nblks;
+		}
+
+		/* get back parent page */
+		rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
+		XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
+		jEVENT(0, ("xtRelocate: target data extent relocated.\n"));
+	} else {		/* (xtype  == XTPAGE) */
+
+		/*
+		 * read in the target xtpage from the source extent;
+		 */
+		XT_GETPAGE(ip, oxaddr, mp, PSIZE, p, rc);
+		if (rc) {
+			XT_PUTPAGE(pmp);
+			return rc;
+		}
+
+		/*
+		 * read in sibling pages if any to update sibling pointers;
+		 */
+		rmp = NULL;
+		if (p->header.next) {
+			nextbn = le64_to_cpu(p->header.next);
+			XT_GETPAGE(ip, nextbn, rmp, PSIZE, rp, rc);
+			if (rc) {
+				XT_PUTPAGE(pmp);
+				XT_PUTPAGE(mp);
+				return (rc);
+			}
+		}
+
+		lmp = NULL;
+		if (p->header.prev) {
+			prevbn = le64_to_cpu(p->header.prev);
+			XT_GETPAGE(ip, prevbn, lmp, PSIZE, lp, rc);
+			if (rc) {
+				XT_PUTPAGE(pmp);
+				XT_PUTPAGE(mp);
+				if (rmp)
+					XT_PUTPAGE(rmp);
+				return (rc);
+			}
+		}
+
+		/* at this point, all xtpages to be updated are in memory */
+
+		/*
+		 * update sibling pointers of sibling xtpages if any;
+		 */
+		if (lmp) {
+			BT_MARK_DIRTY(lmp, ip);
+			tlck =
+			    txLock(tid, ip, lmp, tlckXTREE | tlckRELINK);
+			lp->header.next = cpu_to_le64(nxaddr);
+			XT_PUTPAGE(lmp);
+		}
+
+		if (rmp) {
+			BT_MARK_DIRTY(rmp, ip);
+			tlck =
+			    txLock(tid, ip, rmp, tlckXTREE | tlckRELINK);
+			rp->header.prev = cpu_to_le64(nxaddr);
+			XT_PUTPAGE(rmp);
+		}
+
+		/*
+		 * update the target xtpage to be relocated
+		 *
+		 * update the self address of the target page
+		 * and write to destination extent;
+		 * redo image covers the whole xtpage since it is new page
+		 * to the destination extent;
+		 * update of bmap for the free of source extent
+		 * of the target xtpage itself:
+		 * update of bmap for the allocation of destination extent
+		 * of the target xtpage itself:
+		 * update of bmap for the extents covered by xad entries in
+		 * the target xtpage is not necessary since they are not
+		 * updated;
+		 * if not committed before this relocation,
+		 * target page may contain XAD_NEW entries which must
+		 * be scanned for bmap update (logredo() always
+		 * scan xtpage REDOPAGE image for bmap update);
+		 * if committed before this relocation (tlckRELOCATE),
+		 * scan may be skipped by commit() and logredo();
+		 */
+		BT_MARK_DIRTY(mp, ip);
+		/* tlckNEW init  xtlck->lwm.offset = XTENTRYSTART; */
+		tlck = txLock(tid, ip, mp, tlckXTREE | tlckNEW);
+		xtlck = (xtlock_t *) & tlck->lock;
+
+		/* update the self address in the xtpage header */
+		pxd = &p->header.self;
+		PXDaddress(pxd, nxaddr);
+
+		/* linelock for the after image of the whole page */
+		xtlck->lwm.length =
+		    le16_to_cpu(p->header.nextindex) - xtlck->lwm.offset;
+
+		/* update the buffer extent descriptor of target xtpage */
+		xsize = xlen << JFS_SBI(ip->i_sb)->l2bsize;
+		bmSetXD(mp, nxaddr, xsize);
+
+		/* unpin the target page to new homeward bound */
+		XT_PUTPAGE(mp);
+		jEVENT(0, ("xtRelocate: target xtpage relocated.\n"));
+	}
+
+	/*
+	 *      3. acquire maplock for the source extent to be freed;
+	 *
+	 * acquire a maplock saving the src relocated extent address;
+	 * to free of the extent at commit time;
+	 */
+      out:
+	/* if DATAEXT relocation, write a LOG_UPDATEMAP record for
+	 * free PXD of the source data extent (logredo() will update
+	 * bmap for free of source data extent), and update bmap for
+	 * free of the source data extent;
+	 */
+	if (xtype == DATAEXT)
+		tlck = txMaplock(tid, ip, tlckMAP);
+	/* if XTPAGE relocation, write a LOG_NOREDOPAGE record
+	 * for the source xtpage (logredo() will init NoRedoPage
+	 * filter and will also update bmap for free of the source
+	 * xtpage), and update bmap for free of the source xtpage;
+	 * N.B. We use tlckMAP instead of tlkcXTREE because there
+	 *      is no buffer associated with this lock since the buffer
+	 *      has been redirected to the target location.
+	 */
+	else			/* (xtype  == XTPAGE) */
+		tlck = txMaplock(tid, ip, tlckMAP | tlckRELOCATE);
+
+	pxdlock = (pxdlock_t *) & tlck->lock;
+	pxdlock->flag = mlckFREEPXD;
+	PXDaddress(&pxdlock->pxd, oxaddr);
+	PXDlength(&pxdlock->pxd, xlen);
+	pxdlock->index = 1;
+
+	/*
+	 *      4. update the parent xad entry for relocation;
+	 *
+	 * acquire tlck for the parent entry with XAD_NEW as entry
+	 * update which will write LOG_REDOPAGE and update bmap for
+	 * allocation of XAD_NEW destination extent;
+	 */
+	jEVENT(0, ("xtRelocate: update parent xad entry.\n"));
+	BT_MARK_DIRTY(pmp, ip);
+	tlck = txLock(tid, ip, pmp, tlckXTREE | tlckGROW);
+	xtlck = (xtlock_t *) & tlck->lock;
+
+	/* update the XAD with the new destination extent; */
+	xad = &pp->xad[index];
+	xad->flag |= XAD_NEW;
+	XADaddress(xad, nxaddr);
+
+	xtlck->lwm.offset = min(index, xtlck->lwm.offset);
+	xtlck->lwm.length = le16_to_cpu(pp->header.nextindex) -
+	    xtlck->lwm.offset;
+
+	/* unpin the parent xtpage */
+	XT_PUTPAGE(pmp);
+
+	return rc;
+}
+
+
+/*
+ *      xtSearchNode()
+ *
+ * function:    search for the internal xad entry covering specified extent.
+ *              This function is mainly used by defragfs utility.
+ *
+ * parameters:
+ *      ip      - file object;
+ *      xad     - extent to find;
+ *      cmpp    - comparison result:
+ *      btstack - traverse stack;
+ *      flag    - search process flag;
+ *
+ * returns:
+ *      btstack contains (bn, index) of search path traversed to the entry.
+ *      *cmpp is set to result of comparison with the entry returned.
+ *      the page containing the entry is pinned at exit.
+ */
+static int xtSearchNode(struct inode *ip, xad_t * xad,	/* required XAD entry */
+			int *cmpp, btstack_t * btstack, int flag)
+{
+	int rc = 0;
+	s64 xoff, xaddr;
+	int xlen;
+	int cmp = 1;		/* init for empty page */
+	s64 bn;			/* block number */
+	metapage_t *mp;		/* meta-page buffer */
+	xtpage_t *p;		/* page */
+	int base, index, lim;
+	btframe_t *btsp;
+	s64 t64;
+
+	BT_CLR(btstack);
+
+	xoff = offsetXAD(xad);
+	xlen = lengthXAD(xad);
+	xaddr = addressXAD(xad);
+
+	/*
+	 *      search down tree from root:
+	 *
+	 * between two consecutive entries of <Ki, Pi> and <Kj, Pj> of
+	 * internal page, child page Pi contains entry with k, Ki <= K < Kj.
+	 *
+	 * if entry with search key K is not found
+	 * internal page search find the entry with largest key Ki
+	 * less than K which point to the child page to search;
+	 * leaf page search find the entry with smallest key Kj
+	 * greater than K so that the returned index is the position of
+	 * the entry to be shifted right for insertion of new entry.
+	 * for empty tree, search key is greater than any key of the tree.
+	 *
+	 * by convention, root bn = 0.
+	 */
+	for (bn = 0;;) {
+		/* get/pin the page to search */
+		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+		if (p->header.flag & BT_LEAF)
+			return ESTALE;
+
+		lim = le16_to_cpu(p->header.nextindex) - XTENTRYSTART;
+
+		/*
+		 * binary search with search key K on the current page
+		 */
+		for (base = XTENTRYSTART; lim; lim >>= 1) {
+			index = base + (lim >> 1);
+
+			XT_CMP(cmp, xoff, &p->xad[index], t64);
+			if (cmp == 0) {
+				/*
+				 *      search hit
+				 *
+				 * verify for exact match;
+				 */
+				if (xaddr == addressXAD(&p->xad[index]) &&
+				    xoff == offsetXAD(&p->xad[index])) {
+					*cmpp = cmp;
+
+					/* save search result */
+					btsp = btstack->top;
+					btsp->bn = bn;
+					btsp->index = index;
+					btsp->mp = mp;
+
+					return 0;
+				}
+
+				/* descend/search its child page */
+				goto next;
+			}
+
+			if (cmp > 0) {
+				base = index + 1;
+				--lim;
+			}
+		}
+
+		/*
+		 *      search miss - non-leaf page:
+		 *
+		 * base is the smallest index with key (Kj) greater than
+		 * search key (K) and may be zero or maxentry index.
+		 * if base is non-zero, decrement base by one to get the parent
+		 * entry of the child page to search.
+		 */
+		index = base ? base - 1 : base;
+
+		/*
+		 * go down to child page
+		 */
+	      next:
+		/* get the child page block number */
+		bn = addressXAD(&p->xad[index]);
+
+		/* unpin the parent page */
+		XT_PUTPAGE(mp);
+	}
+}
+
+
+/*
+ *      xtRelink()
+ *
+ * function:
+ *      link around a freed page.
+ *
+ * Parameter:
+ *      int           tid,
+ *      struct inode    *ip,
+ *      xtpage_t        *p)
+ *
+ * returns:
+ */
+static int xtRelink(tid_t tid, struct inode *ip, xtpage_t * p)
+{
+	int rc = 0;
+	metapage_t *mp;
+	s64 nextbn, prevbn;
+	tlock_t *tlck;
+
+	nextbn = le64_to_cpu(p->header.next);
+	prevbn = le64_to_cpu(p->header.prev);
+
+	/* update prev pointer of the next page */
+	if (nextbn != 0) {
+		XT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		/*
+		 * acquire a transaction lock on the page;
+		 *
+		 * action: update prev pointer;
+		 */
+		BT_MARK_DIRTY(mp, ip);
+		tlck = txLock(tid, ip, mp, tlckXTREE | tlckRELINK);
+
+		/* the page may already have been tlock'd */
+
+		p->header.prev = cpu_to_le64(prevbn);
+
+		XT_PUTPAGE(mp);
+	}
+
+	/* update next pointer of the previous page */
+	if (prevbn != 0) {
+		XT_GETPAGE(ip, prevbn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+
+		/*
+		 * acquire a transaction lock on the page;
+		 *
+		 * action: update next pointer;
+		 */
+		BT_MARK_DIRTY(mp, ip);
+		tlck = txLock(tid, ip, mp, tlckXTREE | tlckRELINK);
+
+		/* the page may already have been tlock'd */
+
+		p->header.next = le64_to_cpu(nextbn);
+
+		XT_PUTPAGE(mp);
+	}
+
+	return 0;
+}
+#endif				/*  _STILL_TO_PORT */
+
+
+/*
+ *      xtInitRoot()
+ *
+ * initialize file root (inline in inode)
+ */
+void xtInitRoot(tid_t tid, struct inode *ip)
+{
+	xtpage_t *p;
+	tlock_t *tlck;
+
+	/*
+	 * acquire a transaction lock on the root
+	 *
+	 * action:
+	 */
+	tlck = txLock(tid, ip, (metapage_t *) &JFS_IP(ip)->bxflag,
+		      tlckXTREE | tlckNEW);
+	p = &JFS_IP(ip)->i_xtroot;
+
+	p->header.flag = DXD_INDEX | BT_ROOT | BT_LEAF;
+	p->header.nextindex = cpu_to_le16(XTENTRYSTART);
+
+	if (S_ISDIR(ip->i_mode))
+		p->header.maxentry = cpu_to_le16(XTROOTINITSLOT_DIR);
+	else {
+		p->header.maxentry = cpu_to_le16(XTROOTINITSLOT);
+		ip->i_size = 0;
+	}
+
+
+	return;
+}
+
+
+/*
+ * We can run into a deadlock truncating a file with a large number of
+ * xtree pages (large fragmented file).  A robust fix would entail a
+ * reservation system where we would reserve a number of metadata pages
+ * and tlocks which we would be guaranteed without a deadlock.  Without
+ * this, a partial fix is to limit number of metadata pages we will lock
+ * in a single transaction.  Currently we will truncate the file so that
+ * no more than 50 leaf pages will be locked.  The caller of xtTruncate
+ * will be responsible for ensuring that the current transaction gets
+ * committed, and that subsequent transactions are created to truncate
+ * the file further if needed.
+ */
+#define MAX_TRUNCATE_LEAVES 50
+
+/*
+ *      xtTruncate()
+ *
+ * function:
+ *      traverse for truncation logging backward bottom up;
+ *      terminate at the last extent entry at the current subtree
+ *      root page covering new down size.
+ *      truncation may occur within the last extent entry.
+ *
+ * parameter:
+ *      int           tid,
+ *      struct inode    *ip,
+ *      s64           newsize,
+ *      int           type)   {PWMAP, PMAP, WMAP; DELETE, TRUNCATE}
+ *
+ * return:
+ *
+ * note:
+ *      PWMAP:
+ *       1. truncate (non-COMMIT_NOLINK file)
+ *          by jfs_truncate() or jfs_open(O_TRUNC):
+ *          xtree is updated;
+ *	 2. truncate index table of directory when last entry removed
+ *       map update via tlock at commit time;
+ *      PMAP:
+ *	 Call xtTruncate_pmap instead
+ *      WMAP:
+ *       1. remove (free zero link count) on last reference release
+ *          (pmap has been freed at commit zero link count);
+ *       2. truncate (COMMIT_NOLINK file, i.e., tmp file):
+ *          xtree is updated;
+ *       map update directly at truncation time;
+ *
+ *      if (DELETE)
+ *              no LOG_NOREDOPAGE is required (NOREDOFILE is sufficient);
+ *      else if (TRUNCATE)
+ *              must write LOG_NOREDOPAGE for deleted index page;
+ *
+ * pages may already have been tlocked by anonymous transactions
+ * during file growth (i.e., write) before truncation;
+ *
+ * except last truncated entry, deleted entries remains as is
+ * in the page (nextindex is updated) for other use
+ * (e.g., log/update allocation map): this avoid copying the page
+ * info but delay free of pages;
+ *
+ */
+s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
+{
+	int rc = 0;
+	s64 teof;
+	metapage_t *mp;
+	xtpage_t *p;
+	s64 bn;
+	int index, nextindex;
+	xad_t *xad;
+	s64 xoff, xaddr;
+	int xlen, len, freexlen;
+	btstack_t btstack;
+	btframe_t *parent;
+	tblock_t *tblk = 0;
+	tlock_t *tlck = 0;
+	xtlock_t *xtlck = 0;
+	xdlistlock_t xadlock;	/* maplock for COMMIT_WMAP */
+	pxdlock_t *pxdlock;	/* maplock for COMMIT_WMAP */
+	s64 nfreed;
+	int freed, log;
+	int locked_leaves = 0;
+
+	/* save object truncation type */
+	if (tid) {
+		tblk = tid_to_tblock(tid);
+		tblk->xflag |= flag;
+	}
+
+	nfreed = 0;
+
+	flag &= COMMIT_MAP;
+	assert(flag != COMMIT_PMAP);
+
+	if (flag == COMMIT_PWMAP)
+		log = 1;
+	else {
+		log = 0;
+		xadlock.flag = mlckFREEXADLIST;
+		xadlock.index = 1;
+	}
+
+	/*
+	 * if the newsize is not an integral number of pages,
+	 * the file between newsize and next page boundary will
+	 * be cleared.
+	 * if truncating into a file hole, it will cause
+	 * a full block to be allocated for the logical block.
+	 */
+
+	/*
+	 * release page blocks of truncated region <teof, eof>
+	 *
+	 * free the data blocks from the leaf index blocks.
+	 * delete the parent index entries corresponding to
+	 * the freed child data/index blocks.
+	 * free the index blocks themselves which aren't needed
+	 * in new sized file.
+	 *
+	 * index blocks are updated only if the blocks are to be
+	 * retained in the new sized file.
+	 * if type is PMAP, the data and index pages are NOT
+	 * freed, and the data and index blocks are NOT freed
+	 * from  working map.
+	 * (this will allow continued access of data/index of
+	 * temporary file (zerolink count file truncated to zero-length)).
+	 */
+	teof = (newsize + (JFS_SBI(ip->i_sb)->bsize - 1)) >>
+	    JFS_SBI(ip->i_sb)->l2bsize;
+
+	/* clear stack */
+	BT_CLR(&btstack);
+
+	/*
+	 * start with root
+	 *
+	 * root resides in the inode
+	 */
+	bn = 0;
+
+	/*
+	 * first access of each page:
+	 */
+      getPage:
+	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return -rc;
+
+	/* process entries backward from last index */
+	index = le16_to_cpu(p->header.nextindex) - 1;
+
+	if (p->header.flag & BT_INTERNAL)
+		goto getChild;
+
+	/*
+	 *      leaf page
+	 */
+
+	/* Since this is the rightmost leaf, and we may have already freed
+	 * a page that was formerly to the right, let's make sure that the
+	 * next pointer is zero.
+	 */
+	p->header.next = 0;
+
+	freed = 0;
+
+	/* does region covered by leaf page precede Teof ? */
+	xad = &p->xad[index];
+	xoff = offsetXAD(xad);
+	xlen = lengthXAD(xad);
+	if (teof >= xoff + xlen) {
+		XT_PUTPAGE(mp);
+		goto getParent;
+	}
+
+	/* (re)acquire tlock of the leaf page */
+	if (log) {
+		if (++locked_leaves > MAX_TRUNCATE_LEAVES) {
+			/*
+			 * We need to limit the size of the transaction
+			 * to avoid exhausting pagecache & tlocks
+			 */
+			XT_PUTPAGE(mp);
+			newsize = (xoff + xlen) << JFS_SBI(ip->i_sb)->l2bsize;
+			goto getParent;
+		}
+		tlck = txLock(tid, ip, mp, tlckXTREE);
+		tlck->type = tlckXTREE | tlckTRUNCATE;
+		xtlck = (xtlock_t *) & tlck->lock;
+		xtlck->hwm.offset = le16_to_cpu(p->header.nextindex) - 1;
+	}
+	BT_MARK_DIRTY(mp, ip);
+
+	/*
+	 * scan backward leaf page entries
+	 */
+	for (; index >= XTENTRYSTART; index--) {
+		xad = &p->xad[index];
+		xoff = offsetXAD(xad);
+		xlen = lengthXAD(xad);
+		xaddr = addressXAD(xad);
+
+		/*
+		 * entry beyond eof: continue scan of current page
+		 *          xad
+		 * ---|---=======------->
+		 *   eof
+		 */
+		if (teof < xoff) {
+			nfreed += xlen;
+			continue;
+		}
+
+		/*
+		 * (xoff <= teof): last entry to be deleted from page;
+		 * If other entries remain in page: keep and update the page.
+		 */
+
+		/*
+		 * eof == entry_start: delete the entry
+		 *           xad
+		 * -------|=======------->
+		 *       eof
+		 *
+		 */
+		if (teof == xoff) {
+			nfreed += xlen;
+
+			if (index == XTENTRYSTART)
+				break;
+
+			nextindex = index;
+		}
+		/*
+		 * eof within the entry: truncate the entry.
+		 *          xad
+		 * -------===|===------->
+		 *          eof
+		 */
+		else if (teof < xoff + xlen) {
+			/* update truncated entry */
+			len = teof - xoff;
+			freexlen = xlen - len;
+			XADlength(xad, len);
+
+			/* save pxd of truncated extent in tlck */
+			xaddr += len;
+			if (log) {	/* COMMIT_PWMAP */
+				xtlck->lwm.offset = (xtlck->lwm.offset) ?
+				    min(index, (int)xtlck->lwm.offset) : index;
+				xtlck->lwm.length = index + 1 -
+				    xtlck->lwm.offset;
+				pxdlock = (pxdlock_t *) & xtlck->pxdlock;
+				pxdlock->flag = mlckFREEPXD;
+				PXDaddress(&pxdlock->pxd, xaddr);
+				PXDlength(&pxdlock->pxd, freexlen);
+			}
+			/* free truncated extent */
+			else {	/* COMMIT_WMAP */
+
+				pxdlock = (pxdlock_t *) & xadlock;
+				pxdlock->flag = mlckFREEPXD;
+				PXDaddress(&pxdlock->pxd, xaddr);
+				PXDlength(&pxdlock->pxd, freexlen);
+				txFreeMap(ip, pxdlock, 0, COMMIT_WMAP);
+
+				/* reset map lock */
+				xadlock.flag = mlckFREEXADLIST;
+			}
+
+			/* current entry is new last entry; */
+			nextindex = index + 1;
+
+			nfreed += freexlen;
+		}
+		/*
+		 * eof beyond the entry:
+		 *          xad
+		 * -------=======---|--->
+		 *                 eof
+		 */
+		else {		/* (xoff + xlen < teof) */
+
+			nextindex = index + 1;
+		}
+
+		if (nextindex < le16_to_cpu(p->header.nextindex)) {
+			if (!log) {	/* COMMIT_WAMP */
+				xadlock.xdlist = &p->xad[nextindex];
+				xadlock.count =
+				    le16_to_cpu(p->header.nextindex) -
+				    nextindex;
+				txFreeMap(ip, (maplock_t *) & xadlock, 0,
+					  COMMIT_WMAP);
+			}
+			p->header.nextindex = cpu_to_le16(nextindex);
+		}
+
+		XT_PUTPAGE(mp);
+
+		/* assert(freed == 0); */
+		goto getParent;
+	}			/* end scan of leaf page entries */
+
+	freed = 1;
+
+	/*
+	 * leaf page become empty: free the page if type != PMAP
+	 */
+	if (log) {		/* COMMIT_PWMAP */
+		/* txCommit() with tlckFREE:
+		 * free data extents covered by leaf [XTENTRYSTART:hwm);
+		 * invalidate leaf if COMMIT_PWMAP;
+		 * if (TRUNCATE), will write LOG_NOREDOPAGE;
+		 */
+		tlck->type = tlckXTREE | tlckFREE;
+	} else {		/* COMMIT_WAMP */
+
+		/* free data extents covered by leaf */
+		xadlock.xdlist = &p->xad[XTENTRYSTART];
+		xadlock.count =
+		    le16_to_cpu(p->header.nextindex) - XTENTRYSTART;
+		txFreeMap(ip, (maplock_t *) & xadlock, 0, COMMIT_WMAP);
+	}
+
+	if (p->header.flag & BT_ROOT) {
+		p->header.flag &= ~BT_INTERNAL;
+		p->header.flag |= BT_LEAF;
+		p->header.nextindex = cpu_to_le16(XTENTRYSTART);
+
+		XT_PUTPAGE(mp);	/* debug */
+		goto out;
+	} else {
+		if (log) {	/* COMMIT_PWMAP */
+			/* page will be invalidated at tx completion
+			 */
+			XT_PUTPAGE(mp);
+		} else {	/* COMMIT_WMAP */
+
+			if (mp->lid)
+				lid_to_tlock(mp->lid)->flag |= tlckFREELOCK;
+
+			/* invalidate empty leaf page */
+			discard_metapage(mp);
+		}
+	}
+
+	/*
+	 * the leaf page become empty: delete the parent entry
+	 * for the leaf page if the parent page is to be kept
+	 * in the new sized file.
+	 */
+
+	/*
+	 * go back up to the parent page
+	 */
+      getParent:
+	/* pop/restore parent entry for the current child page */
+	if ((parent = BT_POP(&btstack)) == NULL)
+		/* current page must have been root */
+		goto out;
+
+	/* get back the parent page */
+	bn = parent->bn;
+	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return -rc;
+
+	index = parent->index;
+
+	/*
+	 * child page was not empty:
+	 */
+	if (freed == 0) {
+		/* has any entry deleted from parent ? */
+		if (index < le16_to_cpu(p->header.nextindex) - 1) {
+			/* (re)acquire tlock on the parent page */
+			if (log) {	/* COMMIT_PWMAP */
+				/* txCommit() with tlckTRUNCATE:
+				 * free child extents covered by parent [);
+				 */
+				tlck = txLock(tid, ip, mp, tlckXTREE);
+				xtlck = (xtlock_t *) & tlck->lock;
+				xtlck->twm.offset = index;
+				if (!(tlck->type & tlckTRUNCATE)) {
+					xtlck->hwm.offset =
+					    le16_to_cpu(p->header.
+							nextindex) - 1;
+					tlck->type =
+					    tlckXTREE | tlckTRUNCATE;
+				}
+			} else {	/* COMMIT_WMAP */
+
+				/* free child extents covered by parent */
+				xadlock.xdlist = &p->xad[index + 1];
+				xadlock.count =
+				    le16_to_cpu(p->header.nextindex) -
+				    index - 1;
+				txFreeMap(ip, (maplock_t *) & xadlock, 0,
+					  COMMIT_WMAP);
+			}
+			BT_MARK_DIRTY(mp, ip);
+
+			p->header.nextindex = cpu_to_le16(index + 1);
+		}
+		XT_PUTPAGE(mp);
+		goto getParent;
+	}
+
+	/*
+	 * child page was empty:
+	 */
+	nfreed += lengthXAD(&p->xad[index]);
+
+	/*
+	 * During working map update, child page's tlock must be handled
+	 * before parent's.  This is because the parent's tlock will cause
+	 * the child's disk space to be marked available in the wmap, so
+	 * it's important that the child page be released by that time.
+	 *
+	 * ToDo:  tlocks should be on doubly-linked list, so we can
+	 * quickly remove it and add it to the end.
+	 */
+
+	/*
+	 * Move parent page's tlock to the end of the tid's tlock list
+	 */
+	if (log && mp->lid && (tblk->last != mp->lid) &&
+	    lid_to_tlock(mp->lid)->tid) {
+		lid_t lid = mp->lid;
+		tlock_t *prev;
+
+		tlck = lid_to_tlock(lid);
+
+		if (tblk->next == lid)
+			tblk->next = tlck->next;
+		else {
+			for (prev = lid_to_tlock(tblk->next);
+			     prev->next != lid;
+			     prev = lid_to_tlock(prev->next)) {
+				assert(prev->next);
+			}
+			prev->next = tlck->next;
+		}
+		lid_to_tlock(tblk->last)->next = lid;
+		tlck->next = 0;
+		tblk->last = lid;
+	}
+
+	/*
+	 * parent page become empty: free the page
+	 */
+	if (index == XTENTRYSTART) {
+		if (log) {	/* COMMIT_PWMAP */
+			/* txCommit() with tlckFREE:
+			 * free child extents covered by parent;
+			 * invalidate parent if COMMIT_PWMAP;
+			 */
+			tlck = txLock(tid, ip, mp, tlckXTREE);
+			xtlck = (xtlock_t *) & tlck->lock;
+			xtlck->twm.offset = index;
+			xtlck->hwm.offset =
+			    le16_to_cpu(p->header.nextindex) - 1;
+			tlck->type = tlckXTREE | tlckFREE;
+		} else {	/* COMMIT_WMAP */
+
+			/* free child extents covered by parent */
+			xadlock.xdlist = &p->xad[XTENTRYSTART];
+			xadlock.count =
+			    le16_to_cpu(p->header.nextindex) -
+			    XTENTRYSTART;
+			txFreeMap(ip, (maplock_t *) & xadlock, 0,
+				  COMMIT_WMAP);
+		}
+		BT_MARK_DIRTY(mp, ip);
+
+		if (p->header.flag & BT_ROOT) {
+			p->header.flag &= ~BT_INTERNAL;
+			p->header.flag |= BT_LEAF;
+			p->header.nextindex = cpu_to_le16(XTENTRYSTART);
+			if (le16_to_cpu(p->header.maxentry) == XTROOTMAXSLOT) {
+				/*
+				 * Shrink root down to allow inline
+				 * EA (otherwise fsck complains)
+				 */
+				p->header.maxentry =
+				    cpu_to_le16(XTROOTINITSLOT);
+				JFS_IP(ip)->mode2 |= INLINEEA;
+			}
+
+			XT_PUTPAGE(mp);	/* debug */
+			goto out;
+		} else {
+			if (log) {	/* COMMIT_PWMAP */
+				/* page will be invalidated at tx completion
+				 */
+				XT_PUTPAGE(mp);
+			} else {	/* COMMIT_WMAP */
+
+				if (mp->lid)
+					lid_to_tlock(mp->lid)->flag |=
+						tlckFREELOCK;
+
+				/* invalidate parent page */
+				discard_metapage(mp);
+			}
+
+			/* parent has become empty and freed:
+			 * go back up to its parent page
+			 */
+			/* freed = 1; */
+			goto getParent;
+		}
+	}
+	/*
+	 * parent page still has entries for front region;
+	 */
+	else {
+		/* try truncate region covered by preceding entry
+		 * (process backward)
+		 */
+		index--;
+
+		/* go back down to the child page corresponding
+		 * to the entry
+		 */
+		goto getChild;
+	}
+
+	/*
+	 *      internal page: go down to child page of current entry
+	 */
+      getChild:
+	/* save current parent entry for the child page */
+	BT_PUSH(&btstack, bn, index);
+
+	/* get child page */
+	xad = &p->xad[index];
+	bn = addressXAD(xad);
+
+	/*
+	 * first access of each internal entry:
+	 */
+	/* release parent page */
+	XT_PUTPAGE(mp);
+
+	/* process the child page */
+	goto getPage;
+
+      out:
+	/*
+	 * update file resource stat
+	 */
+	/* set size
+	 */
+	if (S_ISDIR(ip->i_mode) && !newsize)
+		ip->i_size = 1;	/* fsck hates zero-length directories */
+	else
+		ip->i_size = newsize;
+
+	/* update nblocks to reflect freed blocks */
+	ip->i_blocks -= LBLK2PBLK(ip->i_sb, nfreed);
+
+	/*
+	 * free tlock of invalidated pages
+	 */
+	if (flag == COMMIT_WMAP)
+		txFreelock(ip);
+
+	return newsize;
+}
+
+
+/*
+ *      xtTruncate_pmap()
+ *
+ * function:
+ *	Perform truncate to zero lenghth for deleted file, leaving the
+ *	the xtree and working map untouched.  This allows the file to
+ *	be accessed via open file handles, while the delete of the file
+ *	is committed to disk.
+ *
+ * parameter:
+ *      tid_t		tid,
+ *      struct inode	*ip,
+ *      s64		committed_size)
+ *
+ * return: new committed size
+ *
+ * note:
+ *
+ *	To avoid deadlock by holding too many transaction locks, the
+ *	truncation may be broken up into multiple transactions.
+ *	The committed_size keeps track of part of the file has been
+ *	freed from the pmaps.
+ */
+s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
+{
+	s64 bn;
+	btstack_t btstack;
+	int cmp;
+	int index;
+	int locked_leaves = 0;
+	metapage_t *mp;
+	xtpage_t *p;
+	btframe_t *parent;
+	int rc;
+	tblock_t *tblk;
+	tlock_t *tlck = 0;
+	xad_t *xad;
+	int xlen;
+	s64 xoff;
+	xtlock_t *xtlck = 0;
+
+	/* save object truncation type */
+	tblk = tid_to_tblock(tid);
+	tblk->xflag |= COMMIT_PMAP;
+
+	/* clear stack */
+	BT_CLR(&btstack);
+
+	if (committed_size) {
+		xoff = (committed_size >> JFS_SBI(ip->i_sb)->l2bsize) - 1;
+		rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
+		if (rc)
+			return -rc;
+		assert(cmp == 0);
+		XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+	} else {
+		/*
+		 * start with root
+		 *
+		 * root resides in the inode
+		 */
+		bn = 0;
+
+		/*
+		 * first access of each page:
+		 */
+      getPage:
+		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return -rc;
+
+		/* process entries backward from last index */
+		index = le16_to_cpu(p->header.nextindex) - 1;
+
+		if (p->header.flag & BT_INTERNAL)
+			goto getChild;
+	}
+
+	/*
+	 *      leaf page
+	 */
+
+	if (++locked_leaves > MAX_TRUNCATE_LEAVES) {
+		/*
+		 * We need to limit the size of the transaction
+		 * to avoid exhausting pagecache & tlocks
+		 */
+		xad = &p->xad[index];
+		xoff = offsetXAD(xad);
+		xlen = lengthXAD(xad);
+		XT_PUTPAGE(mp);
+		return  (xoff + xlen) << JFS_SBI(ip->i_sb)->l2bsize;
+	}
+	tlck = txLock(tid, ip, mp, tlckXTREE);
+	tlck->type = tlckXTREE | tlckTRUNCATE;
+	xtlck = (xtlock_t *) & tlck->lock;
+	xtlck->hwm.offset = index;
+
+	tlck->type = tlckXTREE | tlckFREE;
+
+	XT_PUTPAGE(mp);
+
+	/*
+	 * go back up to the parent page
+	 */
+      getParent:
+	/* pop/restore parent entry for the current child page */
+	if ((parent = BT_POP(&btstack)) == NULL)
+		/* current page must have been root */
+		goto out;
+
+	/* get back the parent page */
+	bn = parent->bn;
+	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return -rc;
+
+	index = parent->index;
+
+	/*
+	 * parent page become empty: free the page
+	 */
+	if (index == XTENTRYSTART) {
+		/* txCommit() with tlckFREE:
+		 * free child extents covered by parent;
+		 * invalidate parent if COMMIT_PWMAP;
+		 */
+		tlck = txLock(tid, ip, mp, tlckXTREE);
+		xtlck = (xtlock_t *) & tlck->lock;
+		xtlck->twm.offset = index;
+		xtlck->hwm.offset =
+		    le16_to_cpu(p->header.nextindex) - 1;
+		tlck->type = tlckXTREE | tlckFREE;
+
+		XT_PUTPAGE(mp);
+
+		if (p->header.flag & BT_ROOT) {
+
+			goto out;
+		} else {
+			goto getParent;
+		}
+	}
+	/*
+	 * parent page still has entries for front region;
+	 */
+	else
+		index--;
+	/*
+	 *      internal page: go down to child page of current entry
+	 */
+      getChild:
+	/* save current parent entry for the child page */
+	BT_PUSH(&btstack, bn, index);
+
+	/* get child page */
+	xad = &p->xad[index];
+	bn = addressXAD(xad);
+
+	/*
+	 * first access of each internal entry:
+	 */
+	/* release parent page */
+	XT_PUTPAGE(mp);
+
+	/* process the child page */
+	goto getPage;
+
+      out:
+
+	return 0;
+}
+
+
+#ifdef _JFS_DEBUG_XTREE
+/*
+ *      xtDisplayTree()
+ *
+ * function: traverse forward
+ */
+int xtDisplayTree(struct inode *ip)
+{
+	int rc = 0;
+	metapage_t *mp;
+	xtpage_t *p;
+	s64 bn, pbn;
+	int index, lastindex, v, h;
+	xad_t *xad;
+	btstack_t btstack;
+	btframe_t *btsp;
+	btframe_t *parent;
+
+	printk("display B+-tree.\n");
+
+	/* clear stack */
+	btsp = btstack.stack;
+
+	/*
+	 * start with root
+	 *
+	 * root resides in the inode
+	 */
+	bn = 0;
+	v = h = 0;
+
+	/*
+	 * first access of each page:
+	 */
+      getPage:
+	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	/* process entries forward from first index */
+	index = XTENTRYSTART;
+	lastindex = le16_to_cpu(p->header.nextindex) - 1;
+
+	if (p->header.flag & BT_INTERNAL) {
+		/*
+		 * first access of each internal page
+		 */
+		goto getChild;
+	} else {		/* (p->header.flag & BT_LEAF) */
+
+		/*
+		 * first access of each leaf page
+		 */
+		printf("leaf page ");
+		xtDisplayPage(ip, bn, p);
+
+		/* unpin the leaf page */
+		XT_PUTPAGE(mp);
+	}
+
+	/*
+	 * go back up to the parent page
+	 */
+      getParent:
+	/* pop/restore parent entry for the current child page */
+	if ((parent = (btsp == btstack.stack ? NULL : --btsp)) == NULL)
+		/* current page must have been root */
+		return;
+
+	/*
+	 * parent page scan completed
+	 */
+	if ((index = parent->index) == (lastindex = parent->lastindex)) {
+		/* go back up to the parent page */
+		goto getParent;
+	}
+
+	/*
+	 * parent page has entries remaining
+	 */
+	/* get back the parent page */
+	bn = parent->bn;
+	/* v = parent->level; */
+	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	/* get next parent entry */
+	index++;
+
+	/*
+	 * internal page: go down to child page of current entry
+	 */
+      getChild:
+	/* push/save current parent entry for the child page */
+	btsp->bn = pbn = bn;
+	btsp->index = index;
+	btsp->lastindex = lastindex;
+	/* btsp->level = v; */
+	/* btsp->node = h; */
+	++btsp;
+
+	/* get child page */
+	xad = &p->xad[index];
+	bn = addressXAD(xad);
+
+	/*
+	 * first access of each internal entry:
+	 */
+	/* release parent page */
+	XT_PUTPAGE(mp);
+
+	printk("traverse down 0x%lx[%d]->0x%lx\n", (ulong) pbn, index,
+	       (ulong) bn);
+	v++;
+	h = index;
+
+	/* process the child page */
+	goto getPage;
+}
+
+
+/*
+ *      xtDisplayPage()
+ *
+ * function: display page
+ */
+int xtDisplayPage(struct inode *ip, s64 bn, xtpage_t * p)
+{
+	int rc = 0;
+	metapage_t *mp;
+	xad_t *xad;
+	s64 xaddr, xoff;
+	int xlen, i, j;
+
+	if (p == NULL) {
+		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
+	}
+
+	/* display page control */
+	printf("bn:0x%lx flag:0x%x nextindex:%d\n",
+	       (ulong) bn, p->header.flag,
+	       le16_to_cpu(p->header.nextindex));
+
+	/* display entries */
+	xad = &p->xad[XTENTRYSTART];
+		for (i = XTENTRYSTART, j = 1; i < le16_to_cpu(p->header.nextindex);
+		     i++, xad++, j++) {
+			xoff = offsetXAD(xad);
+			xaddr = addressXAD(xad);
+			xlen = lengthXAD(xad);
+			printf("\t[%d] 0x%lx:0x%lx(0x%x)", i, (ulong) xoff,
+			       (ulong) xaddr, xlen);
+
+			if (j == 4) {
+				printf("\n");
+				j = 0;
+		}
+	}
+
+	printf("\n");
+}
+#endif				/* _JFS_DEBUG_XTREE */
+
+
+#ifdef _JFS_WIP
+/*
+ *      xtGather()
+ *
+ * function:
+ *      traverse for allocation acquiring tlock at commit time
+ *      (vs at the time of update) logging backward top down
+ *
+ * note:
+ *      problem - establishing that all new allocation have been
+ *      processed both for append and random write in sparse file
+ *      at the current entry at the current subtree root page
+ *
+ */
+int xtGather(t)
+btree_t *t;
+{
+	int rc = 0;
+	xtpage_t *p;
+	u64 bn;
+	int index;
+	btentry_t *e;
+	btstack_t btstack;
+	struct btsf *parent;
+
+	/* clear stack */
+	BT_CLR(&btstack);
+
+	/*
+	 * start with root
+	 *
+	 * root resides in the inode
+	 */
+	bn = 0;
+	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	/* new root is NOT pointed by a new entry
+	   if (p->header.flag & NEW)
+	   allocate new page lock;
+	   write a NEWPAGE log;
+	 */
+
+      dopage:
+	/*
+	 * first access of each page:
+	 */
+	/* process entries backward from last index */
+	index = le16_to_cpu(p->header.nextindex) - 1;
+
+	if (p->header.flag & BT_LEAF) {
+		/*
+		 * first access of each leaf page
+		 */
+		/* process leaf page entries backward */
+		for (; index >= XTENTRYSTART; index--) {
+			e = &p->xad[index];
+			/*
+			 * if newpage, log NEWPAGE.
+			 *
+			 if (e->flag & XAD_NEW) {
+			 nfound =+ entry->length;
+			 update current page lock for the entry;
+			 newpage(entry);
+			 *
+			 * if moved, log move.
+			 *
+			 } else if (e->flag & XAD_MOVED) {
+			 reset flag;
+			 update current page lock for the entry;
+			 }
+			 */
+		}
+
+		/* unpin the leaf page */
+		XT_PUTPAGE(mp);
+
+		/*
+		 * go back up to the parent page
+		 */
+	      getParent:
+		/* restore parent entry for the current child page */
+		if ((parent = BT_POP(&btstack)) == NULL)
+			/* current page must have been root */
+			return 0;
+
+		if ((index = parent->index) == XTENTRYSTART) {
+			/*
+			 * parent page scan completed
+			 */
+			/* go back up to the parent page */
+			goto getParent;
+		} else {
+			/*
+			 * parent page has entries remaining
+			 */
+			/* get back the parent page */
+			bn = parent->bn;
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+			if (rc)
+				return EIO;
+
+			/* first subroot page which
+			 * covers all new allocated blocks
+			 * itself not new/modified.
+			 * (if modified from split of descendent,
+			 * go down path of split page)
+
+			 if (nfound == nnew &&
+			 !(p->header.flag & (NEW | MOD)))
+			 exit scan;
+			 */
+
+			/* process parent page entries backward */
+			index--;
+		}
+	} else {
+		/*
+		 * first access of each internal page
+		 */
+	}
+
+	/*
+	 * internal page: go down to child page of current entry
+	 */
+
+	/* save current parent entry for the child page */
+	BT_PUSH(&btstack, bn, index);
+
+	/* get current entry for the child page */
+	e = &p->xad[index];
+
+	/*
+	 * first access of each internal entry:
+	 */
+	/*
+	 * if new entry, log btree_tnewentry.
+	 *
+	 if (e->flag & XAD_NEW)
+	 update parent page lock for the entry;
+	 */
+
+	/* release parent page */
+	XT_PUTPAGE(mp);
+
+	/* get child page */
+	bn = e->bn;
+	XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+	if (rc)
+		return rc;
+
+	/*
+	 * first access of each non-root page:
+	 */
+	/*
+	 * if new, log btree_newpage.
+	 *
+	 if (p->header.flag & NEW)
+	 allocate new page lock;
+	 write a NEWPAGE log (next, prev);
+	 */
+
+	/* process the child page */
+	goto dopage;
+
+      out:
+	return 0;
+}
+#endif				/* _JFS_WIP */
+
+
+#ifdef CONFIG_JFS_STATISTICS
+int jfs_xtstat_read(char *buffer, char **start, off_t offset, int length,
+		    int *eof, void *data)
+{
+	int len = 0;
+	off_t begin;
+
+	len += sprintf(buffer,
+		       "JFS Xtree statistics\n"
+		       "====================\n"
+		       "searches = %d\n"
+		       "fast searches = %d\n"
+		       "splits = %d\n",
+		       xtStat.search,
+		       xtStat.fastSearch,
+		       xtStat.split);
+
+	begin = offset;
+	*start = buffer + begin;
+	len -= begin;
+
+	if (len > length)
+		len = length;
+	else
+		*eof = 1;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+#endif
diff -urN linux-2.5.6-pre1/fs/jfs/jfs_xtree.h linux-2.5.6-pre2/fs/jfs/jfs_xtree.h
--- linux-2.5.6-pre1/fs/jfs/jfs_xtree.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/jfs_xtree.h	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,143 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   This program is free software;  you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or 
+ *   (at your option) any later version.
+ * 
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program;  if not, write to the Free Software 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+/*
+ * Change History :
+ *
+*/
+
+#ifndef _H_JFS_XTREE
+#define _H_JFS_XTREE
+
+/*
+ *      jfs_xtree.h: extent allocation descriptor B+-tree manager
+ */
+
+#include "jfs_btree.h"
+
+
+/*
+ *      extent allocation descriptor (xad)
+ */
+typedef struct xad {
+	unsigned flag:8;	/* 1: flag */
+	unsigned rsvrd:16;	/* 2: reserved */
+	unsigned off1:8;	/* 1: offset in unit of fsblksize */
+	u32 off2;		/* 4: offset in unit of fsblksize */
+	unsigned len:24;	/* 3: length in unit of fsblksize */
+	unsigned addr1:8;	/* 1: address in unit of fsblksize */
+	u32 addr2;		/* 4: address in unit of fsblksize */
+} xad_t;			/* (16) */
+
+#define MAXXLEN         ((1 << 24) - 1)
+
+#define XTSLOTSIZE      16
+#define L2XTSLOTSIZE    4
+
+/* xad_t field construction */
+#define XADoffset(xad, offset64)\
+{\
+        (xad)->off1 = ((u64)offset64) >> 32;\
+        (xad)->off2 = __cpu_to_le32((offset64) & 0xffffffff);\
+}
+#define XADaddress(xad, address64)\
+{\
+        (xad)->addr1 = ((u64)address64) >> 32;\
+        (xad)->addr2 = __cpu_to_le32((address64) & 0xffffffff);\
+}
+#define XADlength(xad, length32)        (xad)->len = __cpu_to_le24(length32)
+
+/* xad_t field extraction */
+#define offsetXAD(xad)\
+        ( ((s64)((xad)->off1)) << 32 | __le32_to_cpu((xad)->off2))
+#define addressXAD(xad)\
+        ( ((s64)((xad)->addr1)) << 32 | __le32_to_cpu((xad)->addr2))
+#define lengthXAD(xad)  __le24_to_cpu((xad)->len)
+
+/* xad list */
+typedef struct {
+	s16 maxnxad;
+	s16 nxad;
+	xad_t *xad;
+} xadlist_t;
+
+/* xad_t flags */
+#define XAD_NEW         0x01	/* new */
+#define XAD_EXTENDED    0x02	/* extended */
+#define XAD_COMPRESSED  0x04	/* compressed with recorded length */
+#define XAD_NOTRECORDED 0x08	/* allocated but not recorded */
+#define XAD_COW         0x10	/* copy-on-write */
+
+
+/* possible values for maxentry */
+#define XTROOTINITSLOT_DIR  6
+#define XTROOTINITSLOT  10
+#define XTROOTMAXSLOT   18
+#define XTPAGEMAXSLOT   256
+#define XTENTRYSTART    2
+
+/*
+ *      xtree page:
+ */
+typedef union {
+	struct xtheader {
+		s64 next;	/* 8: */
+		s64 prev;	/* 8: */
+
+		u8 flag;	/* 1: */
+		u8 rsrvd1;	/* 1: */
+		s16 nextindex;	/* 2: next index = number of entries */
+		s16 maxentry;	/* 2: max number of entries */
+		s16 rsrvd2;	/* 2: */
+
+		pxd_t self;	/* 8: self */
+	} header;		/* (32) */
+
+	xad_t xad[XTROOTMAXSLOT];	/* 16 * maxentry: xad array */
+} xtpage_t;
+
+/*
+ *      external declaration
+ */
+extern int xtLookup(struct inode *ip, s64 lstart, s64 llen,
+		    int *pflag, s64 * paddr, int *plen, int flag);
+extern int xtLookupList(struct inode *ip, lxdlist_t * lxdlist,
+			xadlist_t * xadlist, int flag);
+extern void xtInitRoot(tid_t tid, struct inode *ip);
+extern int xtInsert(tid_t tid, struct inode *ip,
+		    int xflag, s64 xoff, int xlen, s64 * xaddrp, int flag);
+extern int xtExtend(tid_t tid, struct inode *ip, s64 xoff, int xlen,
+		    int flag);
+extern int xtTailgate(tid_t tid, struct inode *ip,
+		      s64 xoff, int xlen, s64 xaddr, int flag);
+extern int xtUpdate(tid_t tid, struct inode *ip, struct xad *nxad);
+extern int xtDelete(tid_t tid, struct inode *ip, s64 xoff, int xlen,
+		    int flag);
+extern s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int type);
+extern s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size);
+extern int xtRelocate(tid_t tid, struct inode *ip,
+		      xad_t * oxad, s64 nxaddr, int xtype);
+extern int xtAppend(tid_t tid,
+		    struct inode *ip, int xflag, s64 xoff, int maxblocks,
+		    int *xlenp, s64 * xaddrp, int flag);
+
+#ifdef  _JFS_DEBUG_XTREE
+extern int xtDisplayTree(struct inode *ip);
+extern int xtDisplayPage(struct inode *ip, s64 bn, xtpage_t * p);
+#endif				/* _JFS_DEBUG_XTREE */
+
+#endif				/* !_H_JFS_XTREE */
diff -urN linux-2.5.6-pre1/fs/jfs/namei.c linux-2.5.6-pre2/fs/jfs/namei.c
--- linux-2.5.6-pre1/fs/jfs/namei.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/namei.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,1499 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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
+ *
+ * Module: jfs/namei.c
+ *
+ */
+
+/*
+ * Change History :
+ *
+ */
+
+#include <linux/fs.h>
+#include "jfs_incore.h"
+#include "jfs_inode.h"
+#include "jfs_dinode.h"
+#include "jfs_dmap.h"
+#include "jfs_unicode.h"
+#include "jfs_metapage.h"
+#include "jfs_debug.h"
+#include <linux/locks.h>
+#include <linux/slab.h>
+
+extern struct inode_operations jfs_file_inode_operations;
+extern struct inode_operations jfs_symlink_inode_operations;
+extern struct file_operations jfs_file_operations;
+extern struct address_space_operations jfs_aops;
+
+extern int jfs_fsync(struct file *, struct dentry *, int);
+extern void jfs_truncate_nolock(struct inode *, loff_t);
+
+/*
+ * forward references
+ */
+struct inode_operations jfs_dir_inode_operations;
+struct file_operations jfs_dir_operations;
+
+s64 commitZeroLink(tid_t, struct inode *);
+
+/*
+ * NAME:	jfs_create(dip, dentry, mode)
+ *
+ * FUNCTION:	create a regular file in the parent directory <dip>
+ *		with name = <from dentry> and mode = <mode>
+ *
+ * PARAMETER:	dip 	- parent directory vnode
+ *		dentry	- dentry of new file
+ *		mode	- create mode (rwxrwxrwx).
+ *
+ * RETURN:	Errors from subroutines
+ *
+ */
+int jfs_create(struct inode *dip, struct dentry *dentry, int mode)
+{
+	int rc = 0;
+	tid_t tid;		/* transaction id */
+	struct inode *ip = NULL;	/* child directory inode */
+	ino_t ino;
+	component_t dname;	/* child directory name */
+	btstack_t btstack;
+	struct inode *iplist[2];
+	tblock_t *tblk;
+
+	jFYI(1, ("jfs_create: dip:0x%p name:%s\n", dip, dentry->d_name.name));
+
+	IWRITE_LOCK(dip);
+
+	/*
+	 * search parent directory for entry/freespace
+	 * (dtSearch() returns parent directory page pinned)
+	 */
+	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
+		goto out1;
+
+	/*
+	 * Either iAlloc() or txBegin() may block.  Deadlock can occur if we
+	 * block there while holding dtree page, so we allocate the inode &
+	 * begin the transaction before we search the directory.
+	 */
+	ip = ialloc(dip, mode);
+	if (ip == NULL) {
+		rc = ENOSPC;
+		goto out2;
+	}
+
+	tid = txBegin(dip->i_sb, 0);
+
+	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
+		jERROR(1, ("jfs_create: dtSearch returned %d\n", rc));
+		ip->i_nlink = 0;
+		iput(ip);
+		txEnd(tid);
+		goto out2;
+	}
+
+	tblk = tid_to_tblock(tid);
+	tblk->xflag |= COMMIT_CREATE;
+	tblk->ip = ip;
+
+	iplist[0] = dip;
+	iplist[1] = ip;
+
+	/*
+	 * initialize the child XAD tree root in-line in inode
+	 */
+	xtInitRoot(tid, ip);
+
+	/*
+	 * create entry in parent directory for child directory
+	 * (dtInsert() releases parent directory page)
+	 */
+	ino = ip->i_ino;
+	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
+		jERROR(1, ("jfs_create: dtInsert returned %d\n", rc));
+		/* discard new inode */
+		ip->i_nlink = 0;
+		iput(ip);
+
+		if (rc == EIO)
+			txAbort(tid, 1);	/* Marks Filesystem dirty */
+		else
+			txAbort(tid, 0);	/* Filesystem full */
+		txEnd(tid);
+		goto out2;
+	}
+
+	ip->i_op = &jfs_file_inode_operations;
+	ip->i_fop = &jfs_file_operations;
+	ip->i_mapping->a_ops = &jfs_aops;
+
+	insert_inode_hash(ip);
+	mark_inode_dirty(ip);
+	d_instantiate(dentry, ip);
+
+	dip->i_version = ++event;
+	dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+
+	mark_inode_dirty(dip);
+
+	rc = txCommit(tid, 2, &iplist[0], 0);
+	txEnd(tid);
+
+      out2:
+	free_UCSname(&dname);
+
+      out1:
+
+	IWRITE_UNLOCK(dip);
+	jFYI(1, ("jfs_create: rc:%d\n", -rc));
+	return -rc;
+}
+
+
+/*
+ * NAME:	jfs_mkdir(dip, dentry, mode)
+ *
+ * FUNCTION:	create a child directory in the parent directory <dip>
+ *		with name = <from dentry> and mode = <mode>
+ *
+ * PARAMETER:	dip 	- parent directory vnode
+ *		dentry	- dentry of child directory
+ *		mode	- create mode (rwxrwxrwx).
+ *
+ * RETURN:	Errors from subroutines
+ *
+ * note:
+ * EACCESS: user needs search+write permission on the parent directory
+ */
+int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
+{
+	int rc = 0;
+	tid_t tid;		/* transaction id */
+	struct inode *ip = NULL;	/* child directory inode */
+	ino_t ino;
+	component_t dname;	/* child directory name */
+	btstack_t btstack;
+	struct inode *iplist[2];
+	tblock_t *tblk;
+
+	jFYI(1, ("jfs_mkdir: dip:0x%p name:%s\n", dip, dentry->d_name.name));
+
+	IWRITE_LOCK(dip);
+
+	/* link count overflow on parent directory ? */
+	if (dip->i_nlink == JFS_LINK_MAX) {
+		rc = EMLINK;
+		goto out1;
+	}
+
+	/*
+	 * search parent directory for entry/freespace
+	 * (dtSearch() returns parent directory page pinned)
+	 */
+	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
+		goto out1;
+
+	/*
+	 * Either iAlloc() or txBegin() may block.  Deadlock can occur if we
+	 * block there while holding dtree page, so we allocate the inode &
+	 * begin the transaction before we search the directory.
+	 */
+	ip = ialloc(dip, S_IFDIR | mode);
+	if (ip == NULL) {
+		rc = ENOSPC;
+		goto out2;
+	}
+
+	tid = txBegin(dip->i_sb, 0);
+
+	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
+		jERROR(1, ("jfs_mkdir: dtSearch returned %d\n", rc));
+		ip->i_nlink = 0;
+		iput(ip);
+		txEnd(tid);
+		goto out2;
+	}
+
+	tblk = tid_to_tblock(tid);
+	tblk->xflag |= COMMIT_CREATE;
+	tblk->ip = ip;
+
+	iplist[0] = dip;
+	iplist[1] = ip;
+
+	/*
+	 * initialize the child directory in-line in inode
+	 */
+	dtInitRoot(tid, ip, dip->i_ino);
+
+	/*
+	 * create entry in parent directory for child directory
+	 * (dtInsert() releases parent directory page)
+	 */
+	ino = ip->i_ino;
+	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
+		jERROR(1, ("jfs_mkdir: dtInsert returned %d\n", rc));
+		/* discard new directory inode */
+		ip->i_nlink = 0;
+		iput(ip);
+
+		if (rc == EIO)
+			txAbort(tid, 1);	/* Marks Filesystem dirty */
+		else
+			txAbort(tid, 0);	/* Filesystem full */
+		txEnd(tid);
+		goto out2;
+	}
+
+	ip->i_nlink = 2;	/* for '.' */
+	ip->i_op = &jfs_dir_inode_operations;
+	ip->i_fop = &jfs_dir_operations;
+	ip->i_mapping->a_ops = &jfs_aops;
+	ip->i_mapping->gfp_mask = GFP_NOFS;
+
+	insert_inode_hash(ip);
+	mark_inode_dirty(ip);
+	d_instantiate(dentry, ip);
+
+	/* update parent directory inode */
+	dip->i_nlink++;		/* for '..' from child directory */
+	dip->i_version = ++event;
+	dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+	mark_inode_dirty(dip);
+
+	rc = txCommit(tid, 2, &iplist[0], 0);
+	txEnd(tid);
+
+      out2:
+	free_UCSname(&dname);
+
+      out1:
+
+	IWRITE_UNLOCK(dip);
+
+	jFYI(1, ("jfs_mkdir: rc:%d\n", -rc));
+	return -rc;
+}
+
+/*
+ * NAME:	jfs_rmdir(dip, dentry)
+ *
+ * FUNCTION:	remove a link to child directory
+ *
+ * PARAMETER:	dip 	- parent inode
+ *		dentry	- child directory dentry
+ *
+ * RETURN:	EINVAL	- if name is . or ..
+ *		EINVAL  - if . or .. exist but are invalid.
+ *		errors from subroutines
+ *
+ * note:
+ * if other threads have the directory open when the last link 
+ * is removed, the "." and ".." entries, if present, are removed before 
+ * rmdir() returns and no new entries may be created in the directory, 
+ * but the directory is not removed until the last reference to 
+ * the directory is released (cf.unlink() of regular file).
+ */
+int jfs_rmdir(struct inode *dip, struct dentry *dentry)
+{
+	int rc;
+	tid_t tid;		/* transaction id */
+	struct inode *ip = dentry->d_inode;
+	ino_t ino;
+	component_t dname;
+	struct inode *iplist[2];
+	tblock_t *tblk;
+
+	jFYI(1, ("jfs_rmdir: dip:0x%p name:%s\n", dip, dentry->d_name.name));
+
+	IWRITE_LOCK_LIST(2, dip, ip);
+
+	/* directory must be empty to be removed */
+	if (!dtEmpty(ip)) {
+		IWRITE_UNLOCK(ip);
+		IWRITE_UNLOCK(dip);
+		rc = ENOTEMPTY;
+		goto out;
+	}
+
+	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab))) {
+		IWRITE_UNLOCK(ip);
+		IWRITE_UNLOCK(dip);
+		goto out;
+	}
+
+	tid = txBegin(dip->i_sb, 0);
+
+	iplist[0] = dip;
+	iplist[1] = ip;
+
+	tblk = tid_to_tblock(tid);
+	tblk->xflag |= COMMIT_DELETE;
+	tblk->ip = ip;
+
+	/*
+	 * delete the entry of target directory from parent directory
+	 */
+	ino = ip->i_ino;
+	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
+		jERROR(1, ("jfs_rmdir: dtDelete returned %d\n", rc));
+		if (rc == EIO)
+			txAbort(tid, 1);
+		txEnd(tid);
+
+		IWRITE_UNLOCK(ip);
+		IWRITE_UNLOCK(dip);
+
+		goto out2;
+	}
+
+	/* update parent directory's link count corresponding
+	 * to ".." entry of the target directory deleted
+	 */
+	dip->i_nlink--;
+	dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+	dip->i_version = ++event;
+	mark_inode_dirty(dip);
+
+	/*
+	 * OS/2 could have created EA and/or ACL
+	 */
+	/* free EA from both persistent and working map */
+	if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
+		/* free EA pages */
+		txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
+	}
+	JFS_IP(ip)->ea.flag = 0;
+
+	/* free ACL from both persistent and working map */
+	if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
+		/* free ACL pages */
+		txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
+	}
+	JFS_IP(ip)->acl.flag = 0;
+
+	/* mark the target directory as deleted */
+	ip->i_nlink = 0;
+	mark_inode_dirty(ip);
+
+	rc = txCommit(tid, 2, &iplist[0], 0);
+
+	txEnd(tid);
+
+	IWRITE_UNLOCK(ip);
+
+	/*
+	 * Truncating the directory index table is not guaranteed.  It
+	 * may need to be done iteratively
+	 */
+	if (test_cflag(COMMIT_Stale, dip)) {
+		if (dip->i_size > 1)
+			jfs_truncate_nolock(dip, 0);
+
+		clear_cflag(COMMIT_Stale, dip);
+	}
+
+	IWRITE_UNLOCK(dip);
+
+	d_delete(dentry);
+
+      out2:
+	free_UCSname(&dname);
+
+      out:
+	jFYI(1, ("jfs_rmdir: rc:%d\n", rc));
+	return -rc;
+}
+
+/*
+ * NAME:	jfs_unlink(dip, dentry)
+ *
+ * FUNCTION:	remove a link to object <vp> named by <name> 
+ *		from parent directory <dvp>
+ *
+ * PARAMETER:	dip 	- inode of parent directory
+ *		dentry 	- dentry of object to be removed
+ *
+ * RETURN:	errors from subroutines
+ *
+ * note:
+ * temporary file: if one or more processes have the file open
+ * when the last link is removed, the link will be removed before
+ * unlink() returns, but the removal of the file contents will be
+ * postponed until all references to the files are closed.
+ *
+ * JFS does NOT support unlink() on directories.
+ *
+ */
+int jfs_unlink(struct inode *dip, struct dentry *dentry)
+{
+	int rc;
+	tid_t tid;		/* transaction id */
+	struct inode *ip = dentry->d_inode;
+	ino_t ino;
+	component_t dname;	/* object name */
+	struct inode *iplist[2];
+	tblock_t *tblk;
+	s64 new_size = 0;
+	int commit_flag;
+
+	jFYI(1, ("jfs_unlink: dip:0x%p name:%s\n", dip, dentry->d_name.name));
+
+	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
+		goto out;
+
+	IWRITE_LOCK_LIST(2, ip, dip);
+
+	tid = txBegin(dip->i_sb, 0);
+
+	iplist[0] = dip;
+	iplist[1] = ip;
+
+	/*
+	 * delete the entry of target file from parent directory
+	 */
+	ino = ip->i_ino;
+	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
+		jERROR(1, ("jfs_unlink: dtDelete returned %d\n", rc));
+		if (rc == EIO)
+			txAbort(tid, 1);	/* Marks FS Dirty */
+		txEnd(tid);
+		IWRITE_UNLOCK(ip);
+		IWRITE_UNLOCK(dip);
+		goto out1;
+	}
+
+	ASSERT(ip->i_nlink);
+
+	ip->i_ctime = dip->i_ctime = dip->i_mtime = CURRENT_TIME;
+	dip->i_version = ++event;
+	mark_inode_dirty(dip);
+
+	/* update target's inode */
+	ip->i_nlink--;
+	mark_inode_dirty(ip);
+
+	/*
+	 *      commit zero link count object
+	 */
+	if (ip->i_nlink == 0) {
+		assert(!test_cflag(COMMIT_Nolink, ip));
+		/* free block resources */
+		if ((new_size = commitZeroLink(tid, ip)) < 0) {
+			txAbort(tid, 1);	/* Marks FS Dirty */
+			txEnd(tid);
+			IWRITE_UNLOCK(ip);
+			IWRITE_UNLOCK(dip);
+			rc = -new_size;		/* We return -rc */
+			goto out1;
+		}
+		tblk = tid_to_tblock(tid);
+		tblk->xflag |= COMMIT_DELETE;
+		tblk->ip = ip;
+	}
+
+	/*
+	 * Incomplete truncate of file data can
+	 * result in timing problems unless we synchronously commit the
+	 * transaction.
+	 */
+	if (new_size)
+		commit_flag = COMMIT_SYNC;
+	else
+		commit_flag = 0;
+
+	/*
+	 * If xtTruncate was incomplete, commit synchronously to avoid
+	 * timing complications
+	 */
+	rc = txCommit(tid, 2, &iplist[0], commit_flag);
+
+	txEnd(tid);
+
+	while (new_size && (rc == 0)) {
+		tid = txBegin(dip->i_sb, 0);
+		new_size = xtTruncate_pmap(tid, ip, new_size);
+		if (new_size < 0) {
+			txAbort(tid, 1);	/* Marks FS Dirty */
+			rc = -new_size;		/* We return -rc */
+		} else
+			rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC);
+		txEnd(tid);
+	}
+
+	if (!test_cflag(COMMIT_Holdlock, ip))
+		IWRITE_UNLOCK(ip);
+
+	/*
+	 * Truncating the directory index table is not guaranteed.  It
+	 * may need to be done iteratively
+	 */
+	if (test_cflag(COMMIT_Stale, dip)) {
+		if (dip->i_size > 1)
+			jfs_truncate_nolock(dip, 0);
+
+		clear_cflag(COMMIT_Stale, dip);
+	}
+
+	IWRITE_UNLOCK(dip);
+
+	d_delete(dentry);
+
+      out1:
+	free_UCSname(&dname);
+      out:
+	jFYI(1, ("jfs_unlink: rc:%d\n", -rc));
+	return -rc;
+}
+
+/*
+ * NAME:	commitZeroLink()
+ *
+ * FUNCTION:    for non-directory, called by jfs_remove(),
+ *		truncate a regular file, directory or symbolic
+ *		link to zero length. return 0 if type is not 
+ *		one of these.
+ *
+ *		if the file is currently associated with a VM segment
+ *		only permanent disk and inode map resources are freed,
+ *		and neither the inode nor indirect blocks are modified
+ *		so that the resources can be later freed in the work
+ *		map by ctrunc1.
+ *		if there is no VM segment on entry, the resources are
+ *		freed in both work and permanent map.
+ *		(? for temporary file - memory object is cached even 
+ *		after no reference:
+ *		reference count > 0 -   )
+ *
+ * PARAMETERS:	cd	- pointer to commit data structure.
+ *			  current inode is the one to truncate.
+ *
+ * RETURN :	Errors from subroutines
+ */
+s64 commitZeroLink(tid_t tid, struct inode *ip)
+{
+	int filetype, committype;
+	tblock_t *tblk;
+
+	jFYI(1, ("commitZeroLink: tid = %d, ip = 0x%p\n", tid, ip));
+
+	filetype = ip->i_mode & S_IFMT;
+	switch (filetype) {
+	case S_IFREG:
+		break;
+	case S_IFLNK:
+		/* fast symbolic link */
+		if (ip->i_size <= 256) {
+			ip->i_size = 0;
+			return 0;
+		}
+		break;
+	default:
+		assert(filetype != S_IFDIR);
+		return 0;
+	}
+
+#ifdef _STILL_TO_PORT
+	/*
+	 *      free from block allocation map:
+	 *
+	 * if there is no cache control element associated with 
+	 * the file, free resources in both persistent and work map;
+	 * otherwise just persistent map. 
+	 */
+	if (ip->i_cacheid) {
+		committype = COMMIT_PMAP;
+
+		/* mark for iClose() to free from working map */
+		set_cflag(COMMIT_Freewmap, ip);
+	} else
+		committype = COMMIT_PWMAP;
+#else				/* _STILL_TO_PORT */
+
+	set_cflag(COMMIT_Freewmap, ip);
+	committype = COMMIT_PMAP;
+#endif				/* _STILL_TO_PORT */
+
+	/* mark transaction of block map update type */
+	tblk = tid_to_tblock(tid);
+	tblk->xflag |= committype;
+
+	/*
+	 * free EA
+	 */
+	if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
+#ifdef _STILL_TO_PORT
+		/* free EA pages from cache */
+		if (committype == COMMIT_PWMAP)
+			bmExtentInvalidate(ip, addressDXD(&ip->i_ea),
+					   lengthDXD(&ip->i_ea));
+#endif				/* _STILL_TO_PORT */
+
+		/* acquire maplock on EA to be freed from block map */
+		txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
+
+		if (committype == COMMIT_PWMAP)
+			JFS_IP(ip)->ea.flag = 0;
+	}
+
+	/*
+	 * free ACL
+	 */
+	if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
+#ifdef _STILL_TO_PORT
+		/* free ACL pages from cache */
+		if (committype == COMMIT_PWMAP)
+			bmExtentInvalidate(ip, addressDXD(&ip->i_acl),
+					   lengthDXD(&ip->i_acl));
+#endif				/* _STILL_TO_PORT */
+
+		/* acquire maplock on EA to be freed from block map */
+		txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
+
+		if (committype == COMMIT_PWMAP)
+			JFS_IP(ip)->acl.flag = 0;
+	}
+
+	/*
+	 * free xtree/data (truncate to zero length):
+	 * free xtree/data pages from cache if COMMIT_PWMAP, 
+	 * free xtree/data blocks from persistent block map, and
+	 * free xtree/data blocks from working block map if COMMIT_PWMAP;
+	 */
+	if (ip->i_size)
+		return xtTruncate_pmap(tid, ip, 0);
+
+	return 0;
+}
+
+
+/*
+ * NAME:	freeZeroLink()
+ *
+ * FUNCTION:    for non-directory, called by iClose(),
+ *		free resources of a file from cache and WORKING map 
+ *		for a file previously committed with zero link count
+ *		while associated with a pager object,
+ *
+ * PARAMETER:	ip	- pointer to inode of file.
+ *
+ * RETURN:	0 -ok
+ */
+int freeZeroLink(struct inode *ip)
+{
+	int rc = 0;
+	int type;
+
+	jFYI(1, ("freeZeroLink: ip = 0x%p\n", ip));
+
+	/* return if not reg or symbolic link or if size is
+	 * already ok.
+	 */
+	type = ip->i_mode & S_IFMT;
+
+	switch (type) {
+	case S_IFREG:
+		break;
+	case S_IFLNK:
+		/* if its contained in inode nothing to do */
+		if (ip->i_size <= 256)
+			return 0;
+		break;
+	default:
+		return 0;
+	}
+
+	/*
+	 * free EA
+	 */
+	if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
+		s64 xaddr;
+		int xlen;
+		maplock_t maplock;	/* maplock for COMMIT_WMAP */
+		pxdlock_t *pxdlock;	/* maplock for COMMIT_WMAP */
+
+		/* free EA pages from cache */
+		xaddr = addressDXD(&JFS_IP(ip)->ea);
+		xlen = lengthDXD(&JFS_IP(ip)->ea);
+#ifdef _STILL_TO_PORT
+		bmExtentInvalidate(ip, xaddr, xlen);
+#endif
+
+		/* free EA extent from working block map */
+		maplock.index = 1;
+		pxdlock = (pxdlock_t *) & maplock;
+		pxdlock->flag = mlckFREEPXD;
+		PXDaddress(&pxdlock->pxd, xaddr);
+		PXDlength(&pxdlock->pxd, xlen);
+		txFreeMap(ip, pxdlock, 0, COMMIT_WMAP);
+	}
+
+	/*
+	 * free ACL
+	 */
+	if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
+		s64 xaddr;
+		int xlen;
+		maplock_t maplock;	/* maplock for COMMIT_WMAP */
+		pxdlock_t *pxdlock;	/* maplock for COMMIT_WMAP */
+
+		/* free ACL pages from cache */
+		xaddr = addressDXD(&JFS_IP(ip)->acl);
+		xlen = lengthDXD(&JFS_IP(ip)->acl);
+#ifdef _STILL_TO_PORT
+		bmExtentInvalidate(ip, xaddr, xlen);
+#endif
+
+		/* free ACL extent from working block map */
+		maplock.index = 1;
+		pxdlock = (pxdlock_t *) & maplock;
+		pxdlock->flag = mlckFREEPXD;
+		PXDaddress(&pxdlock->pxd, xaddr);
+		PXDlength(&pxdlock->pxd, xlen);
+		txFreeMap(ip, pxdlock, 0, COMMIT_WMAP);
+	}
+
+	/*
+	 * free xtree/data (truncate to zero length):
+	 * free xtree/data pages from cache, and
+	 * free xtree/data blocks from working block map;
+	 */
+	if (ip->i_size)
+		rc = xtTruncate(0, ip, 0, COMMIT_WMAP);
+
+	return rc;
+}
+
+/*
+ * NAME:	jfs_link(vp, dvp, name, crp)
+ *
+ * FUNCTION:	create a link to <vp> by the name = <name>
+ *		in the parent directory <dvp>
+ *
+ * PARAMETER:	vp 	- target object
+ *		dvp	- parent directory of new link
+ *		name	- name of new link to target object
+ *		crp	- credential
+ *
+ * RETURN:	Errors from subroutines
+ *
+ * note:
+ * JFS does NOT support link() on directories (to prevent circular
+ * path in the directory hierarchy);
+ * EPERM: the target object is a directory, and either the caller
+ * does not have appropriate privileges or the implementation prohibits
+ * using link() on directories [XPG4.2].
+ *
+ * JFS does NOT support links between file systems:
+ * EXDEV: target object and new link are on different file systems and
+ * implementation does not support links between file systems [XPG4.2].
+ */
+int jfs_link(struct dentry *old_dentry,
+	     struct inode *dir, struct dentry *dentry)
+{
+	int rc;
+	tid_t tid;
+	struct inode *ip = old_dentry->d_inode;
+	ino_t ino;
+	component_t dname;
+	btstack_t btstack;
+	struct inode *iplist[2];
+
+	jFYI(1,
+	     ("jfs_link: %s %s\n", old_dentry->d_name.name,
+	      dentry->d_name.name));
+
+	IWRITE_LOCK_LIST(2, dir, ip);
+
+	tid = txBegin(ip->i_sb, 0);
+
+	if (ip->i_nlink == JFS_LINK_MAX) {
+		rc = EMLINK;
+		goto out;
+	}
+
+	/*
+	 * scan parent directory for entry/freespace
+	 */
+	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(ip->i_sb)->nls_tab)))
+		goto out;
+
+	if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
+		goto out;
+
+	/*
+	 * create entry for new link in parent directory
+	 */
+	ino = ip->i_ino;
+	if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack)))
+		goto out;
+
+	dir->i_version = ++event;
+
+	/* update object inode */
+	ip->i_nlink++;		/* for new link */
+	ip->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(dir);
+	atomic_inc(&ip->i_count);
+	d_instantiate(dentry, ip);
+
+	iplist[0] = ip;
+	iplist[1] = dir;
+	rc = txCommit(tid, 2, &iplist[0], 0);
+
+      out:
+	IWRITE_UNLOCK(dir);
+	IWRITE_UNLOCK(ip);
+
+	txEnd(tid);
+
+	jFYI(1, ("jfs_link: rc:%d\n", rc));
+	return -rc;
+}
+
+/*
+ * NAME:	jfs_symlink(dip, dentry, name)
+ *
+ * FUNCTION:	creates a symbolic link to <symlink> by name <name>
+ *		        in directory <dip>
+ *
+ * PARAMETER:	dip	    - parent directory vnode
+ *		        dentry 	- dentry of symbolic link
+ *		        name    - the path name of the existing object 
+ *			              that will be the source of the link
+ *
+ * RETURN:	errors from subroutines
+ *
+ * note:
+ * ENAMETOOLONG: pathname resolution of a symbolic link produced
+ * an intermediate result whose length exceeds PATH_MAX [XPG4.2]
+*/
+
+int jfs_symlink(struct inode *dip, struct dentry *dentry, const char *name)
+{
+	int rc;
+	tid_t tid;
+	ino_t ino = 0;
+	component_t dname;
+	int ssize;		/* source pathname size */
+	btstack_t btstack;
+	struct inode *ip = dentry->d_inode;
+	unchar *i_fastsymlink;
+	s64 xlen = 0;
+	int bmask = 0, xsize;
+	s64 xaddr;
+	metapage_t *mp;
+	struct super_block *sb;
+	tblock_t *tblk;
+
+	struct inode *iplist[2];
+
+	jFYI(1, ("jfs_symlink: dip:0x%p name:%s\n", dip, name));
+
+	IWRITE_LOCK(dip);
+
+	ssize = strlen(name) + 1;
+
+	tid = txBegin(dip->i_sb, 0);
+
+	/*
+	 * search parent directory for entry/freespace
+	 * (dtSearch() returns parent directory page pinned)
+	 */
+
+	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
+		goto out1;
+
+	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE)))
+		goto out2;
+
+
+
+	/*
+	 * allocate on-disk/in-memory inode for symbolic link:
+	 * (iAlloc() returns new, locked inode)
+	 */
+
+	ip = ialloc(dip, S_IFLNK | 0777);
+	if (ip == NULL) {
+		BT_PUTSEARCH(&btstack);
+		rc = ENOSPC;
+		goto out2;
+	}
+
+	tblk = tid_to_tblock(tid);
+	tblk->xflag |= COMMIT_CREATE;
+	tblk->ip = ip;
+
+	/*
+	 * create entry for symbolic link in parent directory
+	 */
+
+	ino = ip->i_ino;
+
+
+
+	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
+		jERROR(1, ("jfs_symlink: dtInsert returned %d\n", rc));
+		/* discard ne inode */
+		ip->i_nlink = 0;
+		iput(ip);
+		goto out2;
+
+	}
+
+	/* fix symlink access permission
+	 * (dir_create() ANDs in the u.u_cmask, 
+	 * but symlinks really need to be 777 access)
+	 */
+	ip->i_mode |= 0777;
+
+	/*
+	   *       write symbolic link target path name
+	 */
+	xtInitRoot(tid, ip);
+
+	/*
+	 * write source path name inline in on-disk inode (fast symbolic link)
+	 */
+
+	if (ssize <= IDATASIZE) {
+		ip->i_op = &jfs_symlink_inode_operations;
+
+		i_fastsymlink = JFS_IP(ip)->i_inline;
+		memcpy(i_fastsymlink, name, ssize);
+		ip->i_size = ssize - 1;
+		jFYI(1,
+		     ("jfs_symlink: fast symlink added  ssize:%d name:%s \n",
+		      ssize, name));
+	}
+	/*
+	 * write source path name in a single extent
+	 */
+	else {
+		jFYI(1, ("jfs_symlink: allocate extent ip:0x%p\n", ip));
+
+		ip->i_op = &page_symlink_inode_operations;
+		ip->i_mapping->a_ops = &jfs_aops;
+
+		/*
+		 * even though the data of symlink object (source 
+		 * path name) is treated as non-journaled user data,
+		 * it is read/written thru buffer cache for performance.
+		 */
+		sb = ip->i_sb;
+		bmask = JFS_SBI(sb)->bsize - 1;
+		xsize = (ssize + bmask) & ~bmask;
+		xaddr = 0;
+		xlen = xsize >> JFS_SBI(sb)->l2bsize;
+		if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0)) == 0) {
+			ip->i_size = ssize - 1;
+			while (ssize) {
+				int copy_size = min(ssize, PSIZE);
+
+				mp = get_metapage(ip, xaddr, PSIZE, 1);
+
+				if (mp == NULL) {
+					dtDelete(tid, dip, &dname, &ino,
+						 JFS_REMOVE);
+					ip->i_nlink = 0;
+					iput(ip);
+					rc = EIO;
+					goto out2;
+				}
+				memcpy(mp->data, name, copy_size);
+				flush_metapage(mp);
+#if 0
+				mark_buffer_uptodate(bp, 1);
+				mark_buffer_dirty(bp, 1);
+				if (IS_SYNC(dip)) {
+					ll_rw_block(WRITE, 1, &bp);
+					wait_on_buffer(bp);
+				}
+				brelse(bp);
+#endif				/* 0 */
+				ssize -= copy_size;
+				xaddr += JFS_SBI(sb)->nbperpage;
+			}
+			ip->i_blocks = LBLK2PBLK(sb, xlen);
+		} else {
+			dtDelete(tid, dip, &dname, &ino, JFS_REMOVE);
+			ip->i_nlink = 0;
+			iput(ip);
+			rc = ENOSPC;
+			goto out2;
+		}
+	}
+	dip->i_version = ++event;
+
+	insert_inode_hash(ip);
+	mark_inode_dirty(ip);
+	d_instantiate(dentry, ip);
+
+	/*
+	 * commit update of parent directory and link object
+	 *
+	 * if extent allocation failed (ENOSPC),
+	 * the parent inode is committed regardless to avoid
+	 * backing out parent directory update (by dtInsert())
+	 * and subsequent dtDelete() which is harmless wrt 
+	 * integrity concern.  
+	 * the symlink inode will be freed by iput() at exit
+	 * as it has a zero link count (by dtDelete()) and 
+	 * no permanant resources. 
+	 */
+
+	iplist[0] = dip;
+	if (rc == 0) {
+		iplist[1] = ip;
+		rc = txCommit(tid, 2, &iplist[0], 0);
+	} else
+		rc = txCommit(tid, 1, &iplist[0], 0);
+
+      out2:
+
+	free_UCSname(&dname);
+      out1:
+	IWRITE_UNLOCK(dip);
+
+	txEnd(tid);
+
+	jFYI(1, ("jfs_symlink: rc:%d\n", -rc));
+	return -rc;
+}
+
+
+/*
+ * NAME:        jfs_rename
+ *
+ * FUNCTION:    rename a file or directory
+ */
+int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+	       struct inode *new_dir, struct dentry *new_dentry)
+{
+	btstack_t btstack;
+	ino_t ino;
+	component_t new_dname;
+	struct inode *new_ip;
+	component_t old_dname;
+	struct inode *old_ip;
+	int rc;
+	tid_t tid;
+	tlock_t *tlck;
+	dtlock_t *dtlck;
+	lv_t *lv;
+	int ipcount;
+	struct inode *iplist[4];
+	tblock_t *tblk;
+	s64 new_size = 0;
+	int commit_flag;
+
+
+	jFYI(1,
+	     ("jfs_rename: %s %s\n", old_dentry->d_name.name,
+	      new_dentry->d_name.name));
+
+	old_ip = old_dentry->d_inode;
+	new_ip = new_dentry->d_inode;
+
+	if (old_dir == new_dir) {
+		if (new_ip)
+			IWRITE_LOCK_LIST(3, old_dir, old_ip, new_ip);
+		else
+			IWRITE_LOCK_LIST(2, old_dir, old_ip);
+	} else {
+		if (new_ip)
+			IWRITE_LOCK_LIST(4, old_dir, new_dir, old_ip,
+					 new_ip);
+		else
+			IWRITE_LOCK_LIST(3, old_dir, new_dir, old_ip);
+	}
+
+	if ((rc = get_UCSname(&old_dname, old_dentry,
+			      JFS_SBI(old_dir->i_sb)->nls_tab)))
+		goto out1;
+
+	if ((rc = get_UCSname(&new_dname, new_dentry,
+			      JFS_SBI(old_dir->i_sb)->nls_tab)))
+		goto out2;
+
+	/*
+	 * Make sure source inode number is what we think it is
+	 */
+	rc = dtSearch(old_dir, &old_dname, &ino, &btstack, JFS_LOOKUP);
+	if (rc || (ino != old_ip->i_ino)) {
+		rc = ENOENT;
+		goto out3;
+	}
+
+	/*
+	 * Make sure dest inode number (if any) is what we think it is
+	 */
+	rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP);
+	if (rc == 0) {
+		if ((new_ip == 0) || (ino != new_ip->i_ino)) {
+			rc = ESTALE;
+			goto out3;
+		}
+	} else if (rc != ENOENT)
+		goto out3;
+	else if (new_ip) {
+		/* no entry exists, but one was expected */
+		rc = ESTALE;
+		goto out3;
+	}
+
+	if (S_ISDIR(old_ip->i_mode)) {
+		if (new_ip) {
+			if (!dtEmpty(new_ip)) {
+				rc = ENOTEMPTY;
+				goto out3;
+			}
+		} else if ((new_dir != old_dir) &&
+			   (new_dir->i_nlink == JFS_LINK_MAX)) {
+			rc = EMLINK;
+			goto out3;
+		}
+	}
+
+	/*
+	 * The real work starts here
+	 */
+	tid = txBegin(new_dir->i_sb, 0);
+
+	if (new_ip) {
+		/*
+		 * Change existing directory entry to new inode number
+		 */
+		ino = new_ip->i_ino;
+		rc = dtModify(tid, new_dir, &new_dname, &ino,
+			      old_ip->i_ino, JFS_RENAME);
+		if (rc)
+			goto out4;
+		new_ip->i_nlink--;
+		if (S_ISDIR(new_ip->i_mode)) {
+			new_ip->i_nlink--;
+			assert(new_ip->i_nlink == 0);
+			tblk = tid_to_tblock(tid);
+			tblk->xflag |= COMMIT_DELETE;
+			tblk->ip = new_ip;
+		} else if (new_ip->i_nlink == 0) {
+			assert(!test_cflag(COMMIT_Nolink, new_ip));
+			/* free block resources */
+			if ((new_size = commitZeroLink(tid, new_ip)) < 0) {
+				txAbort(tid, 1);	/* Marks FS Dirty */
+				rc = -new_size;		/* We return -rc */
+				goto out4;
+			}
+			tblk = tid_to_tblock(tid);
+			tblk->xflag |= COMMIT_DELETE;
+			tblk->ip = new_ip;
+		} else {
+			new_ip->i_ctime = CURRENT_TIME;
+			mark_inode_dirty(new_ip);
+		}
+	} else {
+		/*
+		 * Add new directory entry
+		 */
+		rc = dtSearch(new_dir, &new_dname, &ino, &btstack,
+			      JFS_CREATE);
+		if (rc) {
+			jERROR(1,
+			       ("jfs_rename didn't expect dtSearch to fail w/rc = %d\n",
+				rc));
+			goto out4;
+		}
+
+		ino = old_ip->i_ino;
+		rc = dtInsert(tid, new_dir, &new_dname, &ino, &btstack);
+		if (rc) {
+			jERROR(1,
+			       ("jfs_rename: dtInsert failed w/rc = %d\n",
+				rc));
+			goto out4;
+		}
+		if (S_ISDIR(old_ip->i_mode))
+			new_dir->i_nlink++;
+	}
+	/*
+	 * Remove old directory entry
+	 */
+
+	ino = old_ip->i_ino;
+	rc = dtDelete(tid, old_dir, &old_dname, &ino, JFS_REMOVE);
+	if (rc) {
+		jERROR(1,
+		       ("jfs_rename did not expect dtDelete to return rc = %d\n",
+			rc));
+		txAbort(tid, 1);	/* Marks Filesystem dirty */
+		goto out4;
+	}
+	if (S_ISDIR(old_ip->i_mode)) {
+		old_dir->i_nlink--;
+		if (old_dir != new_dir) {
+			/*
+			 * Change inode number of parent for moved directory
+			 */
+
+			JFS_IP(old_ip)->i_dtroot.header.idotdot =
+				cpu_to_le32(new_dir->i_ino);
+
+			/* Linelock header of dtree */
+			tlck = txLock(tid, old_ip,
+				      (metapage_t *) & JFS_IP(old_ip)->bxflag,
+				      tlckDTREE | tlckBTROOT);
+			dtlck = (dtlock_t *) & tlck->lock;
+			ASSERT(dtlck->index == 0);
+			lv = (lv_t *) & dtlck->lv[0];
+			lv->offset = 0;
+			lv->length = 1;
+			dtlck->index++;
+		}
+	}
+
+	/*
+	 * Update ctime on changed/moved inodes & mark dirty
+	 */
+	old_ip->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(old_ip);
+
+	new_dir->i_version = ++event;
+	new_dir->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(new_dir);
+
+	/* Build list of inodes modified by this transaction */
+	ipcount = 0;
+	iplist[ipcount++] = old_ip;
+	if (new_ip)
+		iplist[ipcount++] = new_ip;
+	iplist[ipcount++] = old_dir;
+
+	if (old_dir != new_dir) {
+		iplist[ipcount++] = new_dir;
+		old_dir->i_version = ++event;
+		old_dir->i_ctime = CURRENT_TIME;
+		mark_inode_dirty(old_dir);
+	}
+
+	/*
+	 * Incomplete truncate of file data can
+	 * result in timing problems unless we synchronously commit the
+	 * transaction.
+	 */
+	if (new_size)
+		commit_flag = COMMIT_SYNC;
+	else
+		commit_flag = 0;
+
+	rc = txCommit(tid, ipcount, iplist, commit_flag);
+
+	/*
+	 * Don't unlock new_ip if COMMIT_HOLDLOCK is set
+	 */
+	if (new_ip && test_cflag(COMMIT_Holdlock, new_ip))
+		new_ip = 0;
+
+      out4:
+	txEnd(tid);
+
+	while (new_size && (rc == 0)) {
+		tid = txBegin(new_ip->i_sb, 0);
+		new_size = xtTruncate_pmap(tid, new_ip, new_size);
+		if (new_size < 0) {
+			txAbort(tid, 1);
+			rc = -new_size;		/* We return -rc */
+		} else
+			rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC);
+		txEnd(tid);
+	}
+      out3:
+	free_UCSname(&new_dname);
+      out2:
+	free_UCSname(&old_dname);
+      out1:
+	IWRITE_UNLOCK(old_ip);
+	if (old_dir != new_dir)
+		IWRITE_UNLOCK(new_dir);
+	if (new_ip)
+		IWRITE_UNLOCK(new_ip);
+
+	/*
+	 * Truncating the directory index table is not guaranteed.  It
+	 * may need to be done iteratively
+	 */
+	if (test_cflag(COMMIT_Stale, old_dir)) {
+		if (old_dir->i_size > 1)
+			jfs_truncate_nolock(old_dir, 0);
+
+		clear_cflag(COMMIT_Stale, old_dir);
+	}
+
+	IWRITE_UNLOCK(old_dir);
+
+	jFYI(1, ("jfs_rename: returning %d\n", rc));
+	return -rc;
+}
+
+
+/*
+ * NAME:        jfs_mknod
+ *
+ * FUNCTION:    Create a special file (device)
+ */
+int jfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
+{
+	btstack_t btstack;
+	component_t dname;
+	ino_t ino;
+	struct inode *ip;
+	struct inode *iplist[2];
+	int rc;
+	tid_t tid;
+	tblock_t *tblk;
+
+	jFYI(1, ("jfs_mknod: %s\n", dentry->d_name.name));
+
+	if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dir->i_sb)->nls_tab)))
+		goto out;
+
+	IWRITE_LOCK(dir);
+
+	ip = ialloc(dir, mode);
+	if (ip == NULL) {
+		rc = ENOSPC;
+		goto out1;
+	}
+
+	tid = txBegin(dir->i_sb, 0);
+
+	if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) {
+		ip->i_nlink = 0;
+		iput(ip);
+		txEnd(tid);
+		goto out1;
+	}
+
+	tblk = tid_to_tblock(tid);
+	tblk->xflag |= COMMIT_CREATE;
+	tblk->ip = ip;
+
+	ino = ip->i_ino;
+	if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) {
+		ip->i_nlink = 0;
+		iput(ip);
+		txEnd(tid);
+		goto out1;
+	}
+
+	if (S_ISREG(ip->i_mode)) {
+		ip->i_op = &jfs_file_inode_operations;
+		ip->i_fop = &jfs_file_operations;
+		ip->i_mapping->a_ops = &jfs_aops;
+	} else
+		init_special_inode(ip, ip->i_mode, rdev);
+
+	insert_inode_hash(ip);
+	mark_inode_dirty(ip);
+	d_instantiate(dentry, ip);
+
+	dir->i_version = ++event;
+	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+
+	mark_inode_dirty(dir);
+
+	iplist[0] = dir;
+	iplist[1] = ip;
+	rc = txCommit(tid, 2, iplist, 0);
+	txEnd(tid);
+
+      out1:
+	IWRITE_UNLOCK(dir);
+	free_UCSname(&dname);
+
+      out:
+	jFYI(1, ("jfs_mknod: returning %d\n", rc));
+	return -rc;
+}
+
+static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry)
+{
+	btstack_t btstack;
+	ino_t inum;
+	struct inode *ip;
+	component_t key;
+	const char *name = dentry->d_name.name;
+	int len = dentry->d_name.len;
+	int rc;
+
+	jFYI(1, ("jfs_lookup: name = %s\n", name));
+
+
+	if ((name[0] == '.') && (len == 1))
+		inum = dip->i_ino;
+	else if (strcmp(name, "..") == 0)
+		inum = PARENT(dip);
+	else {
+		if ((rc =
+		     get_UCSname(&key, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
+			return ERR_PTR(-rc);
+		IREAD_LOCK(dip);
+		rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
+		IREAD_UNLOCK(dip);
+		free_UCSname(&key);
+		if (rc == ENOENT) {
+			d_add(dentry, NULL);
+			return ERR_PTR(0);
+		} else if (rc) {
+			jERROR(1,
+			       ("jfs_lookup: dtSearch returned %d\n", rc));
+			return ERR_PTR(-rc);
+		}
+	}
+
+	ip = iget(dip->i_sb, inum);
+	if (ip == NULL) {
+		jERROR(1,
+		       ("jfs_lookup: iget failed on inum %d\n",
+			(uint) inum));
+		return ERR_PTR(-EACCES);
+	}
+
+	d_add(dentry, ip);
+
+	return ERR_PTR(0);
+}
+
+struct inode_operations jfs_dir_inode_operations = {
+	create:		jfs_create,
+	lookup:		jfs_lookup,
+	link:		jfs_link,
+	unlink:		jfs_unlink,
+	symlink:	jfs_symlink,
+	mkdir:		jfs_mkdir,
+	rmdir:		jfs_rmdir,
+	mknod:		jfs_mknod,
+	rename:		jfs_rename,
+};
+
+struct file_operations jfs_dir_operations = {
+	read:		generic_read_dir,
+	readdir:	jfs_readdir,
+	fsync:		jfs_fsync,
+};
diff -urN linux-2.5.6-pre1/fs/jfs/super.c linux-2.5.6-pre2/fs/jfs/super.c
--- linux-2.5.6-pre1/fs/jfs/super.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/super.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,499 @@
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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/fs.h>
+#include <linux/locks.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include "jfs_incore.h"
+#include "jfs_filsys.h"
+#include "jfs_metapage.h"
+#include "jfs_superblock.h"
+#include "jfs_dmap.h"
+#include "jfs_imap.h"
+#include "jfs_debug.h"
+
+MODULE_DESCRIPTION("The Journaled Filesystem (JFS)");
+MODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM");
+MODULE_LICENSE("GPL");
+
+static kmem_cache_t * jfs_inode_cachep;
+
+static int in_shutdown;
+static pid_t jfsIOthread;
+static pid_t jfsCommitThread;
+static pid_t jfsSyncThread;
+struct task_struct *jfsIOtask;
+struct task_struct *jfsCommitTask;
+struct task_struct *jfsSyncTask;
+DECLARE_COMPLETION(jfsIOwait);
+
+#ifdef CONFIG_JFS_DEBUG
+int jfsloglevel = 1;
+MODULE_PARM(jfsloglevel, "i");
+MODULE_PARM_DESC(jfsloglevel, "Specify JFS loglevel (0, 1 or 2)");
+#endif
+
+/*
+ * External declarations
+ */
+extern int jfs_mount(struct super_block *);
+extern int jfs_mount_rw(struct super_block *, int);
+extern int jfs_umount(struct super_block *);
+extern int jfs_umount_rw(struct super_block *);
+
+extern int jfsIOWait(void *);
+extern int jfs_lazycommit(void *);
+extern int jfs_sync(void *);
+extern void jfs_put_inode(struct inode *inode);
+extern void jfs_read_inode(struct inode *inode);
+extern void jfs_dirty_inode(struct inode *inode);
+extern void jfs_delete_inode(struct inode *inode);
+extern void jfs_write_inode(struct inode *inode, int wait);
+
+#if defined(CONFIG_JFS_DEBUG) && defined(CONFIG_PROC_FS)
+extern void jfs_proc_init(void);
+extern void jfs_proc_clean(void);
+#endif
+
+int jfs_thread_stopped(void)
+{
+	unsigned long signr;
+	siginfo_t info;
+
+	spin_lock_irq(&current->sigmask_lock);
+	signr = dequeue_signal(&current->blocked, &info);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	if (signr == SIGKILL && in_shutdown)
+		return 1;
+	return 0;
+}
+
+static struct inode *jfs_alloc_inode(struct super_block *sb)
+{
+	struct jfs_inode_info *jfs_inode;
+
+	jfs_inode = kmem_cache_alloc(jfs_inode_cachep, GFP_NOFS);
+	if (!jfs_inode)
+		return NULL;
+	return &jfs_inode->vfs_inode;
+}
+
+static void jfs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(jfs_inode_cachep, JFS_IP(inode));
+}
+
+static int jfs_statfs(struct super_block *sb, struct statfs *buf)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	s64 maxinodes;
+	imap_t *imap = JFS_IP(sbi->ipimap)->i_imap;
+
+	jFYI(1, ("In jfs_statfs\n"));
+	buf->f_type = JFS_SUPER_MAGIC;
+	buf->f_bsize = sbi->bsize;
+	buf->f_blocks = sbi->bmap->db_mapsize;
+	buf->f_bfree = sbi->bmap->db_nfree;
+	buf->f_bavail = sbi->bmap->db_nfree;
+	/*
+	 * If we really return the number of allocated & free inodes, some
+	 * applications will fail because they won't see enough free inodes.
+	 * We'll try to calculate some guess as to how may inodes we can
+	 * really allocate
+	 *
+	 * buf->f_files = atomic_read(&imap->im_numinos);
+	 * buf->f_ffree = atomic_read(&imap->im_numfree);
+	 */
+	maxinodes = min((s64) atomic_read(&imap->im_numinos) +
+			((sbi->bmap->db_nfree >> imap->im_l2nbperiext)
+			 << L2INOSPEREXT), (s64)0xffffffffLL);
+	buf->f_files = maxinodes;
+	buf->f_ffree = maxinodes - (atomic_read(&imap->im_numinos) -
+				    atomic_read(&imap->im_numfree));
+
+	buf->f_namelen = JFS_NAME_MAX;
+	return 0;
+}
+
+static void jfs_put_super(struct super_block *sb)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+	int rc;
+
+	jFYI(1, ("In jfs_put_super\n"));
+	rc = jfs_umount(sb);
+	if (rc) {
+		jERROR(1, ("jfs_umount failed with return code %d\n", rc));
+	}
+	unload_nls(sbi->nls_tab);
+	sbi->nls_tab = NULL;
+
+	/*
+	 * We need to clean out the direct_inode pages since this inode
+	 * is not in the inode hash.
+	 */
+	fsync_inode_data_buffers(sbi->direct_inode);
+	truncate_inode_pages(sbi->direct_mapping, 0);
+	iput(sbi->direct_inode);
+	sbi->direct_inode = NULL;
+	sbi->direct_mapping = NULL;
+
+	JFS_SBI(sb) = 0;
+	kfree(sbi);
+}
+
+static int parse_options (char * options, struct jfs_sb_info *sbi)
+{
+	void *nls_map = NULL;
+	char * this_char;
+	char * value;
+
+	if (!options)
+		return 1;
+	for (this_char = strtok (options, ",");
+	     this_char != NULL;
+	     this_char = strtok (NULL, ",")) {
+		if ((value = strchr (this_char, '=')) != NULL)
+			*value++ = 0;
+		if (!strcmp (this_char, "iocharset")) {
+			if (!value || !*value)
+				goto needs_arg;
+			if (nls_map)	/* specified iocharset twice! */
+				unload_nls(nls_map);
+			nls_map = load_nls(value);
+			if (!nls_map) {
+				printk(KERN_ERR "JFS: charset not found\n");
+				goto cleanup;
+			}
+		/* Silently ignore the quota options */
+		} else if (!strcmp (this_char, "grpquota")
+		         || !strcmp (this_char, "noquota")
+		         || !strcmp (this_char, "quota")
+		         || !strcmp (this_char, "usrquota"))
+			/* Don't do anything ;-) */ ;
+		else {
+			printk ("jfs: Unrecognized mount option %s\n", this_char);
+			goto cleanup;
+		}
+	}
+	if (nls_map) {
+		/* Discard old (if remount) */
+		if (sbi->nls_tab)
+			unload_nls(sbi->nls_tab);
+		sbi->nls_tab = nls_map;
+	}
+	return 1;
+needs_arg:
+	printk(KERN_ERR "JFS: %s needs an argument\n", this_char);
+cleanup:
+	if (nls_map)
+		unload_nls(nls_map);
+	return 0;
+}
+
+int jfs_remount(struct super_block *sb, int *flags, char *data)
+{
+	struct jfs_sb_info *sbi = JFS_SBI(sb);
+
+	if (!parse_options(data, sbi)) {
+		return -EINVAL;
+	}
+
+	if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
+		/*
+		 * Invalidate any previously read metadata.  fsck may
+		 * have changed the on-disk data since we mounted r/o
+		 */
+		truncate_inode_pages(sbi->direct_mapping, 0);
+
+		return jfs_mount_rw(sb, 1);
+	} else if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY))
+		return jfs_umount_rw(sb);
+
+	return 0;
+}
+
+static struct super_operations jfs_sops = {
+	alloc_inode:	jfs_alloc_inode,
+	destroy_inode:	jfs_destroy_inode,
+	read_inode:	jfs_read_inode,
+	dirty_inode:	jfs_dirty_inode,
+	write_inode:	jfs_write_inode,
+	put_inode:	jfs_put_inode,
+	delete_inode:	jfs_delete_inode,
+	put_super:	jfs_put_super,
+	statfs:		jfs_statfs,
+	remount_fs:	jfs_remount,
+};
+
+static int jfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+	struct jfs_sb_info *sbi;
+	struct inode *inode;
+	int rc;
+
+	jFYI(1, ("In jfs_read_super: s_flags=0x%lx\n", sb->s_flags));
+
+	sbi = kmalloc(sizeof(struct jfs_sb_info), GFP_KERNEL);
+	JFS_SBI(sb) = sbi;
+	if (!sbi)
+		return -ENOSPC;
+	memset(sbi, 0, sizeof(struct jfs_sb_info));
+
+	if (!parse_options((char *)data, sbi)) {
+		kfree(sbi);
+		return -EINVAL;
+	}
+
+	/*
+	 * Initialize blocksize to 4K.
+	 */
+	sb->s_blocksize = PSIZE;
+	sb->s_blocksize_bits = L2PSIZE;
+	set_blocksize(sb->s_dev, PSIZE);
+
+	sb->s_op = &jfs_sops;
+	/*
+	 * Initialize direct-mapping inode/address-space
+	 */
+	inode = new_inode(sb);
+	if (inode == NULL)
+		goto out_kfree;
+	inode->i_ino = 0;
+	inode->i_nlink = 1;
+	inode->i_size = 0x0000010000000000LL;
+	inode->i_mapping->a_ops = &direct_aops;
+	inode->i_mapping->gfp_mask = GFP_NOFS;
+
+	sbi->direct_inode = inode;
+	sbi->direct_mapping = inode->i_mapping;
+
+	rc = jfs_mount(sb);
+	if (rc) {
+		if (!silent) {
+			jERROR(1,
+			       ("jfs_mount failed w/return code = %d\n",
+				rc));
+		}
+		goto out_mount_failed;
+	}
+	if (sb->s_flags & MS_RDONLY)
+		sbi->log = 0;
+	else {
+		rc = jfs_mount_rw(sb, 0);
+		if (rc) {
+			if (!silent) {
+				jERROR(1,
+				       ("jfs_mount_rw failed w/return code = %d\n",
+					rc));
+			}
+			goto out_no_rw;
+		}
+	}
+
+	sb->s_magic = JFS_SUPER_MAGIC;
+
+	inode = iget(sb, ROOT_I);
+	if (!inode || is_bad_inode(inode))
+		goto out_no_root;
+	sb->s_root = d_alloc_root(inode);
+	if (!sb->s_root)
+		goto out_no_root;
+
+	if (!sbi->nls_tab)
+		sbi->nls_tab = load_nls_default();
+
+	sb->s_maxbytes = ((u64) sb->s_blocksize) << 40;
+#if BITS_PER_LONG == 32
+	sb->s_maxbytes = min((u64)PAGE_CACHE_SIZE << 32, sb->s_maxbytes);
+#endif
+
+	return 0;
+
+out_no_root:
+	jEVENT(1, ("jfs_read_super: get root inode failed\n"));
+	if (inode)
+		iput(inode);
+
+out_no_rw:
+	rc = jfs_umount(sb);
+	if (rc) {
+		jERROR(1, ("jfs_umount failed with return code %d\n", rc));
+	}
+out_mount_failed:
+	fsync_inode_data_buffers(sbi->direct_inode);
+	truncate_inode_pages(sbi->direct_mapping, 0);
+	make_bad_inode(sbi->direct_inode);
+	iput(sbi->direct_inode);
+	sbi->direct_inode = NULL;
+	sbi->direct_mapping = NULL;
+out_kfree:
+	if (sbi->nls_tab)
+		unload_nls(sbi->nls_tab);
+	kfree(sbi);
+	return -EINVAL;
+}
+
+static struct super_block *jfs_get_sb(struct file_system_type *fs_type,
+		int flags, char *dev_name, void *data)
+{
+	return get_sb_bdev(fs_type, flags, dev_name, data, jfs_fill_super);
+}
+
+static struct file_system_type jfs_fs_type = {
+	owner:		THIS_MODULE,
+	name:		"jfs",
+	get_sb:		jfs_get_sb,
+	fs_flags:	FS_REQUIRES_DEV,
+};
+
+extern int metapage_init(void);
+extern int txInit(void);
+extern void txExit(void);
+extern void metapage_exit(void);
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		INIT_LIST_HEAD(&jfs_ip->anon_inode_list);
+		INIT_LIST_HEAD(&jfs_ip->mp_list);
+		RDWRLOCK_INIT(&jfs_ip->rdwrlock);
+		inode_init_once(&jfs_ip->vfs_inode);
+	}
+}
+
+static int __init init_jfs_fs(void)
+{
+	int rc;
+
+	jfs_inode_cachep =
+	    kmem_cache_create("jfs_ip",
+			    sizeof(struct jfs_inode_info),
+			    0, 0, init_once, NULL);
+	if (jfs_inode_cachep == NULL)
+		return -ENOMEM;
+
+	/*
+	 * Metapage initialization
+	 */
+	rc = metapage_init();
+	if (rc) {
+		jERROR(1, ("metapage_init failed w/rc = %d\n", rc));
+		goto free_slab;
+	}
+
+	/*
+	 * Transaction Manager initialization
+	 */
+	rc = txInit();
+	if (rc) {
+		jERROR(1, ("txInit failed w/rc = %d\n", rc));
+		goto free_metapage;
+	}
+
+	/*
+	 * I/O completion thread (endio)
+	 */
+	jfsIOthread = kernel_thread(jfsIOWait, 0,
+				    CLONE_FS | CLONE_FILES |
+				    CLONE_SIGHAND);
+	if (jfsIOthread < 0) {
+		jERROR(1,
+		       ("init_jfs_fs: fork failed w/rc = %d\n",
+			jfsIOthread));
+		goto end_txmngr;
+	}
+	wait_for_completion(&jfsIOwait);	/* Wait until IO thread starts */
+
+	jfsCommitThread = kernel_thread(jfs_lazycommit, 0,
+					CLONE_FS | CLONE_FILES |
+					CLONE_SIGHAND);
+	if (jfsCommitThread < 0) {
+		jERROR(1,
+		       ("init_jfs_fs: fork failed w/rc = %d\n",
+			jfsCommitThread));
+		goto kill_iotask;
+	}
+	wait_for_completion(&jfsIOwait);	/* Wait until IO thread starts */
+
+	jfsSyncThread = kernel_thread(jfs_sync, 0,
+				      CLONE_FS | CLONE_FILES |
+				      CLONE_SIGHAND);
+	if (jfsSyncThread < 0) {
+		jERROR(1,
+		       ("init_jfs_fs: fork failed w/rc = %d\n",
+			jfsSyncThread));
+		goto kill_committask;
+	}
+	wait_for_completion(&jfsIOwait);	/* Wait until IO thread starts */
+
+#if defined(CONFIG_JFS_DEBUG) && defined(CONFIG_PROC_FS)
+	jfs_proc_init();
+#endif
+
+	return register_filesystem(&jfs_fs_type);
+
+
+kill_committask:
+	send_sig(SIGKILL, jfsCommitTask, 1);
+	wait_for_completion(&jfsIOwait);	/* Wait until Commit thread exits */
+kill_iotask:
+	send_sig(SIGKILL, jfsIOtask, 1);
+	wait_for_completion(&jfsIOwait);	/* Wait until IO thread exits */
+end_txmngr:
+	txExit();
+free_metapage:
+	metapage_exit();
+free_slab:
+	kmem_cache_destroy(jfs_inode_cachep);
+	return -rc;
+}
+
+static void __exit exit_jfs_fs(void)
+{
+	jFYI(1, ("exit_jfs_fs called\n"));
+
+	in_shutdown = 1;
+	txExit();
+	metapage_exit();
+	send_sig(SIGKILL, jfsIOtask, 1);
+	wait_for_completion(&jfsIOwait);	/* Wait until IO thread exits */
+	send_sig(SIGKILL, jfsCommitTask, 1);
+	wait_for_completion(&jfsIOwait);	/* Wait until Commit thread exits */
+	send_sig(SIGKILL, jfsSyncTask, 1);
+	wait_for_completion(&jfsIOwait);	/* Wait until Sync thread exits */
+#if defined(CONFIG_JFS_DEBUG) && defined(CONFIG_PROC_FS)
+	jfs_proc_clean();
+#endif
+	unregister_filesystem(&jfs_fs_type);
+	kmem_cache_destroy(jfs_inode_cachep);
+}
+
+
+EXPORT_NO_SYMBOLS;
+
+module_init(init_jfs_fs)
+module_exit(exit_jfs_fs)
diff -urN linux-2.5.6-pre1/fs/jfs/symlink.c linux-2.5.6-pre2/fs/jfs/symlink.c
--- linux-2.5.6-pre1/fs/jfs/symlink.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/fs/jfs/symlink.c	Thu Feb 28 13:34:22 2002
@@ -0,0 +1,47 @@
+
+/*
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000
+ *
+ *   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
+ *
+ *  JFS fast symlink handling code
+ */
+
+#include <linux/fs.h>
+#include "jfs_incore.h"
+
+static int jfs_readlink(struct dentry *, char *buffer, int buflen);
+static int jfs_follow_link(struct dentry *dentry, struct nameidata *nd);
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations jfs_symlink_inode_operations = {
+	readlink:	jfs_readlink,
+	follow_link:	jfs_follow_link,
+};
+
+static int jfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	char *s = JFS_IP(dentry->d_inode)->i_inline;
+	return vfs_follow_link(nd, s);
+}
+
+static int jfs_readlink(struct dentry *dentry, char *buffer, int buflen)
+{
+	char *s = JFS_IP(dentry->d_inode)->i_inline;
+	return vfs_readlink(dentry, buffer, buflen, s);
+}
diff -urN linux-2.5.6-pre1/fs/lockd/svc4proc.c linux-2.5.6-pre2/fs/lockd/svc4proc.c
--- linux-2.5.6-pre1/fs/lockd/svc4proc.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/fs/lockd/svc4proc.c	Thu Feb 28 13:34:22 2002
@@ -524,7 +524,7 @@
 
 struct nlm_void			{ int dummy; };
 
-#define PROC(name, xargt, xrest, argt, rest)	\
+#define PROC(name, xargt, xrest, argt, rest, respsize)	\
  { (svc_procfunc) nlm4svc_proc_##name,	\
    (kxdrproc_t) nlm4svc_decode_##xargt,	\
    (kxdrproc_t) nlm4svc_encode_##xrest,	\
@@ -532,33 +532,34 @@
    sizeof(struct nlm_##argt),		\
    sizeof(struct nlm_##rest),		\
    0,					\
-   0					\
+   0,					\
+   respsize,				\
  }
 struct svc_procedure		nlmsvc_procedures4[] = {
-  PROC(null,		void,		void,		void,	void),
-  PROC(test,		testargs,	testres,	args,	res),
-  PROC(lock,		lockargs,	res,		args,	res),
-  PROC(cancel,		cancargs,	res,		args,	res),
-  PROC(unlock,		unlockargs,	res,		args,	res),
-  PROC(granted,		testargs,	res,		args,	res),
-  PROC(test_msg,	testargs,	norep,		args,	void),
-  PROC(lock_msg,	lockargs,	norep,		args,	void),
-  PROC(cancel_msg,	cancargs,	norep,		args,	void),
-  PROC(unlock_msg,	unlockargs,	norep,		args,	void),
-  PROC(granted_msg,	testargs,	norep,		args,	void),
-  PROC(test_res,	testres,	norep,		res,	void),
-  PROC(lock_res,	lockres,	norep,		res,	void),
-  PROC(cancel_res,	cancelres,	norep,		res,	void),
-  PROC(unlock_res,	unlockres,	norep,		res,	void),
-  PROC(granted_res,	grantedres,	norep,		res,	void),
+  PROC(null,		void,		void,		void,	void, 0),
+  PROC(test,		testargs,	testres,	args,	res, 0),
+  PROC(lock,		lockargs,	res,		args,	res, 0),
+  PROC(cancel,		cancargs,	res,		args,	res, 0),
+  PROC(unlock,		unlockargs,	res,		args,	res, 0),
+  PROC(granted,		testargs,	res,		args,	res, 0),
+  PROC(test_msg,	testargs,	norep,		args,	void, 0),
+  PROC(lock_msg,	lockargs,	norep,		args,	void, 0),
+  PROC(cancel_msg,	cancargs,	norep,		args,	void, 0),
+  PROC(unlock_msg,	unlockargs,	norep,		args,	void, 0),
+  PROC(granted_msg,	testargs,	norep,		args,	void, 0),
+  PROC(test_res,	testres,	norep,		res,	void, 0),
+  PROC(lock_res,	lockres,	norep,		res,	void, 0),
+  PROC(cancel_res,	cancelres,	norep,		res,	void, 0),
+  PROC(unlock_res,	unlockres,	norep,		res,	void, 0),
+  PROC(granted_res,	grantedres,	norep,		res,	void, 0),
   /* statd callback */
-  PROC(sm_notify,	reboot,		void,		reboot,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(share,		shareargs,	shareres,	args,	res),
-  PROC(unshare,		shareargs,	shareres,	args,	res),
-  PROC(nm_lock,		lockargs,	res,		args,	res),
-  PROC(free_all,	notify,		void,		args,	void),
+  PROC(sm_notify,	reboot,		void,		reboot,	void, 0),
+  PROC(none,		void,		void,		void,	void, 0),
+  PROC(none,		void,		void,		void,	void, 0),
+  PROC(none,		void,		void,		void,	void, 0),
+  PROC(share,		shareargs,	shareres,	args,	res, 0),
+  PROC(unshare,		shareargs,	shareres,	args,	res, 0),
+  PROC(nm_lock,		lockargs,	res,		args,	res, 0),
+  PROC(free_all,	notify,		void,		args,	void, 0),
 
 };
diff -urN linux-2.5.6-pre1/fs/lockd/svcproc.c linux-2.5.6-pre2/fs/lockd/svcproc.c
--- linux-2.5.6-pre1/fs/lockd/svcproc.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/fs/lockd/svcproc.c	Thu Feb 28 13:34:22 2002
@@ -552,7 +552,7 @@
 
 struct nlm_void			{ int dummy; };
 
-#define PROC(name, xargt, xrest, argt, rest)	\
+#define PROC(name, xargt, xrest, argt, rest, respsize)	\
  { (svc_procfunc) nlmsvc_proc_##name,	\
    (kxdrproc_t) nlmsvc_decode_##xargt,	\
    (kxdrproc_t) nlmsvc_encode_##xrest,	\
@@ -560,33 +560,34 @@
    sizeof(struct nlm_##argt),		\
    sizeof(struct nlm_##rest),		\
    0,					\
-   0					\
+   0,					\
+   respsize,				\
  }
 struct svc_procedure		nlmsvc_procedures[] = {
-  PROC(null,		void,		void,		void,	void),
-  PROC(test,		testargs,	testres,	args,	res),
-  PROC(lock,		lockargs,	res,		args,	res),
-  PROC(cancel,		cancargs,	res,		args,	res),
-  PROC(unlock,		unlockargs,	res,		args,	res),
-  PROC(granted,		testargs,	res,		args,	res),
-  PROC(test_msg,	testargs,	norep,		args,	void),
-  PROC(lock_msg,	lockargs,	norep,		args,	void),
-  PROC(cancel_msg,	cancargs,	norep,		args,	void),
-  PROC(unlock_msg,	unlockargs,	norep,		args,	void),
-  PROC(granted_msg,	testargs,	norep,		args,	void),
-  PROC(test_res,	testres,	norep,		res,	void),
-  PROC(lock_res,	lockres,	norep,		res,	void),
-  PROC(cancel_res,	cancelres,	norep,		res,	void),
-  PROC(unlock_res,	unlockres,	norep,		res,	void),
-  PROC(granted_res,	grantedres,	norep,		res,	void),
+  PROC(null,		void,		void,		void,	void, 0),
+  PROC(test,		testargs,	testres,	args,	res, 0),
+  PROC(lock,		lockargs,	res,		args,	res, 0),
+  PROC(cancel,		cancargs,	res,		args,	res, 0),
+  PROC(unlock,		unlockargs,	res,		args,	res, 0),
+  PROC(granted,		testargs,	res,		args,	res, 0),
+  PROC(test_msg,	testargs,	norep,		args,	void, 0),
+  PROC(lock_msg,	lockargs,	norep,		args,	void, 0),
+  PROC(cancel_msg,	cancargs,	norep,		args,	void, 0),
+  PROC(unlock_msg,	unlockargs,	norep,		args,	void, 0),
+  PROC(granted_msg,	testargs,	norep,		args,	void, 0),
+  PROC(test_res,	testres,	norep,		res,	void, 0),
+  PROC(lock_res,	lockres,	norep,		res,	void, 0),
+  PROC(cancel_res,	cancelres,	norep,		res,	void, 0),
+  PROC(unlock_res,	unlockres,	norep,		res,	void, 0),
+  PROC(granted_res,	grantedres,	norep,		res,	void, 0),
   /* statd callback */
-  PROC(sm_notify,	reboot,		void,		reboot,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(none,		void,		void,		void,	void),
-  PROC(share,		shareargs,	shareres,	args,	res),
-  PROC(unshare,		shareargs,	shareres,	args,	res),
-  PROC(nm_lock,		lockargs,	res,		args,	res),
-  PROC(free_all,	notify,		void,		args,	void),
+  PROC(sm_notify,	reboot,		void,		reboot,	void, 0),
+  PROC(none,		void,		void,		void,	void, 0),
+  PROC(none,		void,		void,		void,	void, 0),
+  PROC(none,		void,		void,		void,	void, 0),
+  PROC(share,		shareargs,	shareres,	args,	res, 0),
+  PROC(unshare,		shareargs,	shareres,	args,	res, 0),
+  PROC(nm_lock,		lockargs,	res,		args,	res, 0),
+  PROC(free_all,	notify,		void,		args,	void, 0),
 
 };
diff -urN linux-2.5.6-pre1/fs/nfs/flushd.c linux-2.5.6-pre2/fs/nfs/flushd.c
--- linux-2.5.6-pre1/fs/nfs/flushd.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/fs/nfs/flushd.c	Thu Feb 28 13:34:22 2002
@@ -50,7 +50,7 @@
 /*
  * This is the wait queue all cluster daemons sleep on
  */
-static struct rpc_wait_queue    flushd_queue = RPC_INIT_WAITQ("nfs_flushd");
+static RPC_WAITQ(flushd_queue, "nfs_flushd");
 
 /*
  * Local function declarations.
diff -urN linux-2.5.6-pre1/fs/nfs/unlink.c linux-2.5.6-pre2/fs/nfs/unlink.c
--- linux-2.5.6-pre1/fs/nfs/unlink.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre2/fs/nfs/unlink.c	Thu Feb 28 13:34:22 2002
@@ -24,7 +24,7 @@
 };
 
 static struct nfs_unlinkdata	*nfs_deletes;
-static struct rpc_wait_queue	nfs_delete_queue = RPC_INIT_WAITQ("nfs_delete_queue");
+static RPC_WAITQ(nfs_delete_queue, "nfs_delete_queue");
 
 /**
  * nfs_detach_unlinkdata - Remove asynchronous unlink from global list
diff -urN linux-2.5.6-pre1/fs/nfsd/export.c linux-2.5.6-pre2/fs/nfsd/export.c
--- linux-2.5.6-pre1/fs/nfsd/export.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/fs/nfsd/export.c	Thu Feb 28 13:34:22 2002
@@ -20,6 +20,7 @@
 #include <linux/stat.h>
 #include <linux/in.h>
 #include <linux/seq_file.h>
+#include <linux/rwsem.h>
 
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
@@ -60,10 +61,6 @@
 static struct svc_clnthash *	clnt_hash[CLIENT_HASHMAX];
 static svc_client *		clients;
 
-static int			hash_lock;
-static int			want_lock;
-static int			hash_count;
-static DECLARE_WAIT_QUEUE_HEAD(	hash_wait );
 
 /*
  * Find the client's export entry matching xdev/xino.
@@ -163,6 +160,39 @@
 }
 
 /*
+ * Hashtable locking. Write locks are placed only by user processes
+ * wanting to modify export information.
+ * Write locking only done in this file.  Read locking
+ * needed externally.
+ */
+
+static DECLARE_RWSEM(hash_sem);
+
+void
+exp_readlock(void)
+{
+	down_read(&hash_sem);
+}
+
+static inline void
+exp_writelock(void)
+{
+	down_write(&hash_sem);
+}
+
+void
+exp_readunlock(void)
+{
+	up_read(&hash_sem);
+}
+
+static inline void
+exp_writeunlock(void)
+{
+	up_write(&hash_sem);
+}
+
+/*
  * Export a file system.
  */
 int
@@ -189,11 +219,9 @@
 	ino = nxp->ex_ino;
 
 	/* Try to lock the export table for update */
-	if ((err = exp_writelock()) < 0)
-		goto out;
+	exp_writelock();
 
 	/* Look up client info */
-	err = -EINVAL;
 	if (!(clp = exp_getclientbyname(nxp->ex_client)))
 		goto out_unlock;
 
@@ -278,7 +306,7 @@
 
 	/* Unlock hashtable */
 out_unlock:
-	exp_unlock();
+	exp_writeunlock();
 out:
 	return err;
 
@@ -345,8 +373,7 @@
 	if (!exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
 		return -EINVAL;
 
-	if ((err = exp_writelock()) < 0)
-		goto out;
+	exp_writelock();
 
 	err = -EINVAL;
 	clp = exp_getclientbyname(nxp->ex_client);
@@ -361,8 +388,7 @@
 		}
 	}
 
-	exp_unlock();
-out:
+	exp_writeunlock();
 	return err;
 }
 
@@ -415,58 +441,6 @@
 	return err;
 }
 
-/*
- * Hashtable locking. Write locks are placed only by user processes
- * wanting to modify export information.
- */
-void
-exp_readlock(void)
-{
-	while (hash_lock || want_lock)
-		sleep_on(&hash_wait);
-	hash_count++;
-}
-
-int
-exp_writelock(void)
-{
-	/* fast track */
-	if (!hash_count && !hash_lock) {
-	lock_it:
-		hash_lock = 1;
-		return 0;
-	}
-
-	clear_thread_flag(TIF_SIGPENDING);
-	want_lock++;
-	while (hash_count || hash_lock) {
-		interruptible_sleep_on(&hash_wait);
-		if (signal_pending(current))
-			break;
-	}
-	want_lock--;
-
-	/* restore the task's signals */
-	spin_lock_irq(&current->sigmask_lock);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
-
-	if (!hash_count && !hash_lock)
-		goto lock_it;
-	return -EINTR;
-}
-
-void
-exp_unlock(void)
-{
-	if (!hash_count && !hash_lock)
-		printk(KERN_WARNING "exp_unlock: not locked!\n");
-	if (hash_count)
-		hash_count--;
-	else
-		hash_lock = 0;
-	wake_up(&hash_wait);
-}
 
 /*
  * Find a valid client given an inet address. We always move the most
@@ -572,7 +546,7 @@
 
 static void e_stop(struct seq_file *m, void *p)
 {
-	exp_unlock();
+	exp_readunlock();
 }
 
 struct flags {
@@ -688,8 +662,7 @@
 		goto out;
 
 	/* Lock the hashtable */
-	if ((err = exp_writelock()) < 0)
-		goto out;
+	exp_writelock();
 
 	/* First check if this is a change request for a client. */
 	for (clp = clients; clp; clp = clp->cl_next)
@@ -754,7 +727,7 @@
 	err = 0;
 
 out_unlock:
-	exp_unlock();
+	exp_writeunlock();
 out:
 	return err;
 }
@@ -773,10 +746,8 @@
 		goto out;
 
 	/* Lock the hashtable */
-	if ((err = exp_writelock()) < 0)
-		goto out;
+	exp_writelock();
 
-	err = -EINVAL;
 	for (clpp = &clients; (clp = *clpp); clpp = &(clp->cl_next))
 		if (!strcmp(ncp->cl_ident, clp->cl_ident))
 			break;
@@ -787,7 +758,7 @@
 		err = 0;
 	}
 
-	exp_unlock();
+	exp_writeunlock();
 out:
 	return err;
 }
@@ -893,16 +864,14 @@
 
 	dprintk("nfsd: shutting down export module.\n");
 
-	if (exp_writelock() < 0) {
-		printk(KERN_WARNING "Weird: hashtable locked in exp_shutdown");
-		return;
-	}
+	exp_writelock();
+
 	for (i = 0; i < CLIENT_HASHMAX; i++) {
 		while (clnt_hash[i])
 			exp_freeclient(clnt_hash[i]->h_client);
 	}
 	clients = NULL; /* we may be restarted before the module unloads */
 	
-	exp_unlock();
+	exp_writeunlock();
 	dprintk("nfsd: export shutdown complete.\n");
 }
diff -urN linux-2.5.6-pre1/fs/nfsd/lockd.c linux-2.5.6-pre2/fs/nfsd/lockd.c
--- linux-2.5.6-pre1/fs/nfsd/lockd.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/fs/nfsd/lockd.c	Thu Feb 28 13:34:22 2002
@@ -62,7 +62,7 @@
 
 struct nlmsvc_binding		nfsd_nlm_ops = {
 	exp_readlock,		/* lock export table for reading */
-	exp_unlock,		/* unlock export table */
+	exp_readunlock,		/* unlock export table */
 	exp_getclient,		/* look up NFS client */
 	nlm_fopen,		/* open file for locking */
 	nlm_fclose,		/* close file */
diff -urN linux-2.5.6-pre1/fs/nfsd/nfs3proc.c linux-2.5.6-pre2/fs/nfsd/nfs3proc.c
--- linux-2.5.6-pre1/fs/nfsd/nfs3proc.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/fs/nfsd/nfs3proc.c	Thu Feb 28 13:34:22 2002
@@ -183,11 +183,12 @@
 	 */
 	svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &avail,
 			1 + NFS3_POST_OP_ATTR_WORDS + 3);
-
 	resp->count = argp->count;
 	if ((avail << 2) < resp->count)
 		resp->count = avail << 2;
 
+	svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + argp->count +4);
+
 	fh_copy(&resp->fh, &argp->fh);
 	nfserr = nfsd_read(rqstp, &resp->fh,
 				  argp->offset,
@@ -646,7 +647,7 @@
 #define nfsd3_voidres			nfsd3_voidargs
 struct nfsd3_voidargs { int dummy; };
 
-#define PROC(name, argt, rest, relt, cache)	\
+#define PROC(name, argt, rest, relt, cache, respsize)	\
  { (svc_procfunc) nfsd3_proc_##name,		\
    (kxdrproc_t) nfs3svc_decode_##argt##args,	\
    (kxdrproc_t) nfs3svc_encode_##rest##res,	\
@@ -654,29 +655,30 @@
    sizeof(struct nfsd3_##argt##args),		\
    sizeof(struct nfsd3_##rest##res),		\
    0,						\
-   cache					\
+   cache,					\
+   respsize,					\
  }
 struct svc_procedure		nfsd_procedures3[22] = {
-  PROC(null,	 void,		void,		void,	 RC_NOCACHE),
-  PROC(getattr,	 fhandle,	attrstat,	fhandle, RC_NOCACHE),
-  PROC(setattr,  sattr,		wccstat,	fhandle,  RC_REPLBUFF),
-  PROC(lookup,	 dirop,		dirop,		fhandle2, RC_NOCACHE),
-  PROC(access,	 access,	access,		fhandle,  RC_NOCACHE),
-  PROC(readlink, fhandle,	readlink,	fhandle,  RC_NOCACHE),
-  PROC(read,	 read,		read,		fhandle, RC_NOCACHE),
-  PROC(write,	 write,		write,		fhandle,  RC_REPLBUFF),
-  PROC(create,	 create,	create,		fhandle2, RC_REPLBUFF),
-  PROC(mkdir,	 mkdir,		create,		fhandle2, RC_REPLBUFF),
-  PROC(symlink,	 symlink,	create,		fhandle2, RC_REPLBUFF),
-  PROC(mknod,	 mknod,		create,		fhandle2, RC_REPLBUFF),
-  PROC(remove,	 dirop,		wccstat,	fhandle,  RC_REPLBUFF),
-  PROC(rmdir,	 dirop,		wccstat,	fhandle,  RC_REPLBUFF),
-  PROC(rename,	 rename,	rename,		fhandle2, RC_REPLBUFF),
-  PROC(link,	 link,		link,		fhandle2, RC_REPLBUFF),
-  PROC(readdir,	 readdir,	readdir,	fhandle,  RC_NOCACHE),
-  PROC(readdirplus,readdirplus,	readdir,	fhandle,  RC_NOCACHE),
-  PROC(fsstat,	 fhandle,	fsstat,		void,     RC_NOCACHE),
-  PROC(fsinfo,   fhandle,	fsinfo,		void,     RC_NOCACHE),
-  PROC(pathconf, fhandle,	pathconf,	void,     RC_NOCACHE),
-  PROC(commit,	 commit,	commit,		fhandle,  RC_NOCACHE)
+  PROC(null,	 void,		void,		void,	 RC_NOCACHE, 1),
+  PROC(getattr,	 fhandle,	attrstat,	fhandle, RC_NOCACHE, 1+21),
+  PROC(setattr,  sattr,		wccstat,	fhandle,  RC_REPLBUFF, 1+7+22),
+  PROC(lookup,	 dirop,		dirop,		fhandle2, RC_NOCACHE, 1+9+22+22),
+  PROC(access,	 access,	access,		fhandle,  RC_NOCACHE, 1+22+1),
+  PROC(readlink, fhandle,	readlink,	fhandle,  RC_NOCACHE, 1+22+1+256),
+  PROC(read,	 read,		read,		fhandle, RC_NOCACHE, 1+22+4+NFSSVC_MAXBLKSIZE),
+  PROC(write,	 write,		write,		fhandle,  RC_REPLBUFF, 1+7+22+4),
+  PROC(create,	 create,	create,		fhandle2, RC_REPLBUFF, 1+(1+9+22)+7+22),
+  PROC(mkdir,	 mkdir,		create,		fhandle2, RC_REPLBUFF, 1+(1+9+22)+7+22),
+  PROC(symlink,	 symlink,	create,		fhandle2, RC_REPLBUFF, 1+(1+9+22)+7+22),
+  PROC(mknod,	 mknod,		create,		fhandle2, RC_REPLBUFF, 1+(1+9+22)+7+22),
+  PROC(remove,	 dirop,		wccstat,	fhandle,  RC_REPLBUFF, 1+7+22),
+  PROC(rmdir,	 dirop,		wccstat,	fhandle,  RC_REPLBUFF, 1+7+22),
+  PROC(rename,	 rename,	rename,		fhandle2, RC_REPLBUFF, 1+7+22+7+22),
+  PROC(link,	 link,		link,		fhandle2, RC_REPLBUFF, 1+22+7+22),
+  PROC(readdir,	 readdir,	readdir,	fhandle,  RC_NOCACHE, 0),
+  PROC(readdirplus,readdirplus,	readdir,	fhandle,  RC_NOCACHE, 0),
+  PROC(fsstat,	 fhandle,	fsstat,		void,     RC_NOCACHE, 1+14),
+  PROC(fsinfo,   fhandle,	fsinfo,		void,     RC_NOCACHE, 1+13),
+  PROC(pathconf, fhandle,	pathconf,	void,     RC_NOCACHE, 1+6),
+  PROC(commit,	 commit,	commit,		fhandle,  RC_NOCACHE, 1+7+22+2),
 };
diff -urN linux-2.5.6-pre1/fs/nfsd/nfscache.c linux-2.5.6-pre2/fs/nfsd/nfscache.c
--- linux-2.5.6-pre1/fs/nfsd/nfscache.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/fs/nfsd/nfscache.c	Thu Feb 28 13:34:22 2002
@@ -14,6 +14,7 @@
 #include <linux/time.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/spinlock.h>
 
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
@@ -38,11 +39,17 @@
 static struct svc_cacherep *	lru_head;
 static struct svc_cacherep *	lru_tail;
 static struct svc_cacherep *	nfscache;
-static int			cache_initialized;
 static int			cache_disabled = 1;
 
 static int	nfsd_cache_append(struct svc_rqst *rqstp, struct svc_buf *data);
 
+/* 
+ * locking for the reply cache:
+ * A cache entry is "single use" if c_state == RC_INPROG
+ * Otherwise, it when accessing _prev or _next, the lock must be held.
+ */
+static spinlock_t cache_lock = SPIN_LOCK_UNLOCKED;
+
 void
 nfsd_cache_init(void)
 {
@@ -51,8 +58,6 @@
 	size_t			i;
 	unsigned long		order;
 
-	if (cache_initialized)
-		return;
 
 	i = CACHESIZE * sizeof (struct svc_cacherep);
 	for (order = 0; (PAGE_SIZE << order) < i; order++)
@@ -90,7 +95,6 @@
 	lru_head->c_lru_prev = NULL;
 	lru_tail->c_lru_next = NULL;
 
-	cache_initialized = 1;
 	cache_disabled = 0;
 }
 
@@ -101,15 +105,11 @@
 	size_t			i;
 	unsigned long		order;
 
-	if (!cache_initialized)
-		return;
-
 	for (rp = lru_head; rp; rp = rp->c_lru_next) {
 		if (rp->c_state == RC_DONE && rp->c_type == RC_REPLBUFF)
 			kfree(rp->c_replbuf.buf);
 	}
 
-	cache_initialized = 0;
 	cache_disabled = 1;
 
 	i = CACHESIZE * sizeof (struct svc_cacherep);
@@ -179,6 +179,7 @@
 				vers = rqstp->rq_vers,
 				proc = rqstp->rq_proc;
 	unsigned long		age;
+	int rtn;
 
 	rqstp->rq_cacherep = NULL;
 	if (cache_disabled || type == RC_NOCACHE) {
@@ -186,6 +187,9 @@
 		return RC_DOIT;
 	}
 
+	spin_lock(&cache_lock);
+	rtn = RC_DOIT;
+
 	rp = rh = (struct svc_cacherep *) &hash_list[REQHASH(xid)];
 	while ((rp = rp->c_hash_next) != rh) {
 		if (rp->c_state != RC_UNUSED &&
@@ -208,7 +212,7 @@
 		if (safe++ > CACHESIZE) {
 			printk("nfsd: loop in repcache LRU list\n");
 			cache_disabled = 1;
-			return RC_DOIT;
+			goto out;
 		}
 	}
 	}
@@ -222,7 +226,7 @@
 			printk(KERN_WARNING "nfsd: disabling repcache.\n");
 			cache_disabled = 1;
 		}
-		return RC_DOIT;
+		goto out;
 	}
 
 	rqstp->rq_cacherep = rp;
@@ -242,8 +246,9 @@
 		rp->c_replbuf.buf = NULL;
 	}
 	rp->c_type = RC_NOCACHE;
-
-	return RC_DOIT;
+ out:
+	spin_unlock(&cache_lock);
+	return rtn;
 
 found_entry:
 	/* We found a matching entry which is either in progress or done. */
@@ -251,33 +256,36 @@
 	rp->c_timestamp = jiffies;
 	lru_put_front(rp);
 
+	rtn = RC_DROPIT;
 	/* Request being processed or excessive rexmits */
 	if (rp->c_state == RC_INPROG || age < RC_DELAY)
-		return RC_DROPIT;
+		goto out;
 
 	/* From the hall of fame of impractical attacks:
 	 * Is this a user who tries to snoop on the cache? */
+	rtn = RC_DOIT;
 	if (!rqstp->rq_secure && rp->c_secure)
-		return RC_DOIT;
+		goto out;
 
 	/* Compose RPC reply header */
 	switch (rp->c_type) {
 	case RC_NOCACHE:
-		return RC_DOIT;
+		break;
 	case RC_REPLSTAT:
 		svc_putlong(&rqstp->rq_resbuf, rp->c_replstat);
+		rtn = RC_REPLY;
 		break;
 	case RC_REPLBUFF:
 		if (!nfsd_cache_append(rqstp, &rp->c_replbuf))
-			return RC_DOIT;	/* should not happen */
+			goto out;	/* should not happen */
+		rtn = RC_REPLY;
 		break;
 	default:
 		printk(KERN_WARNING "nfsd: bad repcache type %d\n", rp->c_type);
 		rp->c_state = RC_UNUSED;
-		return RC_DOIT;
 	}
 
-	return RC_REPLY;
+	goto out;
 }
 
 /*
@@ -324,20 +332,22 @@
 		cachp = &rp->c_replbuf;
 		cachp->buf = (u32 *) kmalloc(len << 2, GFP_KERNEL);
 		if (!cachp->buf) {
+			spin_lock(&cache_lock);
 			rp->c_state = RC_UNUSED;
+			spin_unlock(&cache_lock);
 			return;
 		}
 		cachp->len = len;
 		memcpy(cachp->buf, statp, len << 2);
 		break;
 	}
-
+	spin_lock(&cache_lock);
 	lru_put_front(rp);
 	rp->c_secure = rqstp->rq_secure;
 	rp->c_type = cachetype;
 	rp->c_state = RC_DONE;
 	rp->c_timestamp = jiffies;
-
+	spin_unlock(&cache_lock);
 	return;
 }
 
diff -urN linux-2.5.6-pre1/fs/nfsd/nfsctl.c linux-2.5.6-pre2/fs/nfsd/nfsctl.c
--- linux-2.5.6-pre1/fs/nfsd/nfsctl.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/fs/nfsd/nfsctl.c	Thu Feb 28 13:34:22 2002
@@ -121,7 +121,7 @@
 		err = -EPERM;
 	else
 		err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
-	exp_unlock();
+	exp_readunlock();
 	return err;
 }
 
@@ -144,7 +144,7 @@
 		err = -EPERM;
 	else
 		err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
-	exp_unlock();
+	exp_readunlock();
 
 	if (err == 0) {
 		if (fh.fh_size > NFS_FHSIZE)
@@ -187,7 +187,6 @@
 	int			err;
 	int			argsize, respsize;
 
-	lock_kernel ();
 
 	err = -EPERM;
 	if (!capable(CAP_SYS_ADMIN)) {
@@ -257,7 +256,6 @@
 	if (res)
 		kfree(res);
 
-	unlock_kernel ();
 	return err;
 }
 
diff -urN linux-2.5.6-pre1/fs/nfsd/nfsfh.c linux-2.5.6-pre2/fs/nfsd/nfsfh.c
--- linux-2.5.6-pre1/fs/nfsd/nfsfh.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/fs/nfsd/nfsfh.c	Thu Feb 28 13:34:22 2002
@@ -10,6 +10,7 @@
 
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <linux/unistd.h>
 #include <linux/string.h>
@@ -273,7 +274,9 @@
 	/* I'm going to assume that if the returned dentry is different, then
 	 * it is well connected.  But nobody returns different dentrys do they?
 	 */
+	down(&child->d_inode->i_sem);
 	pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
+	up(&child->d_inode->i_sem);
 	d_drop(tdentry); /* we never want ".." hashed */
 	if (!pdentry && tdentry->d_inode == NULL) {
 		/* File system cannot find ".." ... sad but possible */
@@ -426,6 +429,7 @@
 	 */
 	dprintk("nfs_fh: need to look harder for %s/%d\n", sb->s_id, datap[0]);
 
+	lock_kernel();
 	if (!S_ISDIR(result->d_inode->i_mode)) {
 		nfsdstats.fh_nocache_nondir++;
 			/* need to iget dirino and make sure this inode is in that directory */
@@ -499,6 +503,7 @@
 			dput(dentry);
 			dput(result);	/* this will discard the whole free path, so we can up the semaphore */
 			up(&sb->s_nfsd_free_path_sem);
+			unlock_kernel();
 			goto retry;
 		}
 		dput(dentry);
@@ -506,6 +511,7 @@
 	}
 	dput(dentry);
 	up(&sb->s_nfsd_free_path_sem);
+	unlock_kernel();
 	return result;
 
 err_dentry:
@@ -513,6 +519,7 @@
 err_result:
 	dput(result);
 	up(&sb->s_nfsd_free_path_sem);
+	unlock_kernel();
 err_out:
 	if (err == -ESTALE)
 		nfsdstats.fh_stale++;
diff -urN linux-2.5.6-pre1/fs/nfsd/nfsproc.c linux-2.5.6-pre2/fs/nfsd/nfsproc.c
--- linux-2.5.6-pre1/fs/nfsd/nfsproc.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/fs/nfsd/nfsproc.c	Thu Feb 28 13:34:22 2002
@@ -148,6 +148,7 @@
 				argp->count);
 		argp->count = avail << 2;
 	}
+	svc_reserve(rqstp, (19<<2) + argp->count + 4);
 
 	resp->count = argp->count;
 	nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
@@ -522,7 +523,7 @@
 #define nfssvc_release_none	NULL
 struct nfsd_void { int dummy; };
 
-#define PROC(name, argt, rest, relt, cache)	\
+#define PROC(name, argt, rest, relt, cache, respsize)	\
  { (svc_procfunc) nfsd_proc_##name,		\
    (kxdrproc_t) nfssvc_decode_##argt,		\
    (kxdrproc_t) nfssvc_encode_##rest,		\
@@ -530,27 +531,28 @@
    sizeof(struct nfsd_##argt),			\
    sizeof(struct nfsd_##rest),			\
    0,						\
-   cache					\
+   cache,					\
+   respsize,				       	\
  }
 struct svc_procedure		nfsd_procedures2[18] = {
-  PROC(null,	 void,		void,		none,		RC_NOCACHE),
-  PROC(getattr,	 fhandle,	attrstat,	fhandle,	RC_NOCACHE),
-  PROC(setattr,  sattrargs,	attrstat,	fhandle,	RC_REPLBUFF),
-  PROC(none,	 void,		void,		none,		RC_NOCACHE),
-  PROC(lookup,	 diropargs,	diropres,	fhandle,	RC_NOCACHE),
-  PROC(readlink, fhandle,	readlinkres,	none,		RC_NOCACHE),
-  PROC(read,	 readargs,	readres,	fhandle,	RC_NOCACHE),
-  PROC(none,	 void,		void,		none,		RC_NOCACHE),
-  PROC(write,	 writeargs,	attrstat,	fhandle,	RC_REPLBUFF),
-  PROC(create,	 createargs,	diropres,	fhandle,	RC_REPLBUFF),
-  PROC(remove,	 diropargs,	void,		none,		RC_REPLSTAT),
-  PROC(rename,	 renameargs,	void,		none,		RC_REPLSTAT),
-  PROC(link,	 linkargs,	void,		none,		RC_REPLSTAT),
-  PROC(symlink,	 symlinkargs,	void,		none,		RC_REPLSTAT),
-  PROC(mkdir,	 createargs,	diropres,	fhandle,	RC_REPLBUFF),
-  PROC(rmdir,	 diropargs,	void,		none,		RC_REPLSTAT),
-  PROC(readdir,	 readdirargs,	readdirres,	none,		RC_REPLBUFF),
-  PROC(statfs,	 fhandle,	statfsres,	none,		RC_NOCACHE),
+  PROC(null,	 void,		void,		none,		RC_NOCACHE, 1),
+  PROC(getattr,	 fhandle,	attrstat,	fhandle,	RC_NOCACHE, 1+18),
+  PROC(setattr,  sattrargs,	attrstat,	fhandle,	RC_REPLBUFF, 1+18),
+  PROC(none,	 void,		void,		none,		RC_NOCACHE, 1),
+  PROC(lookup,	 diropargs,	diropres,	fhandle,	RC_NOCACHE, 1+8+18),
+  PROC(readlink, fhandle,	readlinkres,	none,		RC_NOCACHE, 1+1+256),
+  PROC(read,	 readargs,	readres,	fhandle,	RC_NOCACHE, 1+18+1+NFSSVC_MAXBLKSIZE),
+  PROC(none,	 void,		void,		none,		RC_NOCACHE, 1),
+  PROC(write,	 writeargs,	attrstat,	fhandle,	RC_REPLBUFF, 1+18),
+  PROC(create,	 createargs,	diropres,	fhandle,	RC_REPLBUFF, 1+8+18),
+  PROC(remove,	 diropargs,	void,		none,		RC_REPLSTAT, 1),
+  PROC(rename,	 renameargs,	void,		none,		RC_REPLSTAT, 1),
+  PROC(link,	 linkargs,	void,		none,		RC_REPLSTAT, 1),
+  PROC(symlink,	 symlinkargs,	void,		none,		RC_REPLSTAT, 1),
+  PROC(mkdir,	 createargs,	diropres,	fhandle,	RC_REPLBUFF, 1+8+18),
+  PROC(rmdir,	 diropargs,	void,		none,		RC_REPLSTAT, 1),
+  PROC(readdir,	 readdirargs,	readdirres,	none,		RC_REPLBUFF, 0),
+  PROC(statfs,	 fhandle,	statfsres,	none,		RC_NOCACHE, 1+5),
 };
 
 
diff -urN linux-2.5.6-pre1/fs/nfsd/nfssvc.c linux-2.5.6-pre2/fs/nfsd/nfssvc.c
--- linux-2.5.6-pre1/fs/nfsd/nfssvc.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/fs/nfsd/nfssvc.c	Thu Feb 28 13:34:22 2002
@@ -54,8 +54,9 @@
 static void			nfsd(struct svc_rqst *rqstp);
 struct timeval			nfssvc_boot;
 static struct svc_serv 		*nfsd_serv;
-static int			nfsd_busy;
+static atomic_t			nfsd_busy;
 static unsigned long		nfsd_last_call;
+static spinlock_t		nfsd_call_lock = SPIN_LOCK_UNLOCKED;
 
 struct nfsd_list {
 	struct list_head 	list;
@@ -74,7 +75,8 @@
 	int	error;
 	int	none_left;	
 	struct list_head *victim;
-
+	
+	lock_kernel();
 	dprintk("nfsd: creating service\n");
 	error = -EINVAL;
 	if (nrservs <= 0)
@@ -87,6 +89,7 @@
 	if (error<0)
 		goto out;
 	if (!nfsd_serv) {
+		atomic_set(&nfsd_busy, 0);
 		nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE, NFSSVC_XDRSIZE);
 		if (nfsd_serv == NULL)
 			goto out;
@@ -94,7 +97,7 @@
 		if (error < 0)
 			goto failure;
 
-#if 0	/* Don't even pretend that TCP works. It doesn't. */
+#if CONFIG_NFSD_TCP
 		error = svc_makesock(nfsd_serv, IPPROTO_TCP, port);
 		if (error < 0)
 			goto failure;
@@ -125,6 +128,7 @@
 		nfsd_racache_shutdown();
 	}
  out:
+	unlock_kernel();
 	return error;
 }
 
@@ -135,6 +139,7 @@
 	unsigned long diff;
 	int decile;
 
+	spin_lock(&nfsd_call_lock);
 	prev_call = nfsd_last_call;
 	nfsd_last_call = jiffies;
 	decile = busy_threads*10/nfsdstats.th_cnt;
@@ -145,6 +150,7 @@
 		if (decile == 10)
 			nfsdstats.th_fullcnt++;
 	}
+	spin_unlock(&nfsd_call_lock);
 }
 
 /*
@@ -173,6 +179,7 @@
 	me.task = current;
 	list_add(&me.list, &nfsd_list);
 
+	unlock_kernel();
 	/*
 	 * The main request loop
 	 */
@@ -188,12 +195,12 @@
 		 * recvfrom routine.
 		 */
 		while ((err = svc_recv(serv, rqstp,
-				       MAX_SCHEDULE_TIMEOUT)) == -EAGAIN)
+				       5*60*HZ)) == -EAGAIN)
 		    ;
 		if (err < 0)
 			break;
-		update_thread_usage(nfsd_busy);
-		nfsd_busy++;
+		update_thread_usage(atomic_read(&nfsd_busy));
+		atomic_inc(&nfsd_busy);
 
 		/* Lock the export hash tables for reading. */
 		exp_readlock();
@@ -211,9 +218,9 @@
 		svc_process(serv, rqstp);
 
 		/* Unlock export hash tables */
-		exp_unlock();
-		update_thread_usage(nfsd_busy);
-		nfsd_busy--;
+		exp_readunlock();
+		update_thread_usage(atomic_read(&nfsd_busy));
+		atomic_dec(&nfsd_busy);
 	}
 
 	if (err != -EINTR) {
@@ -228,6 +235,8 @@
 		err = signo;
 	}
 
+	lock_kernel();
+
 	/* Release lockd */
 	lockd_down();
 
diff -urN linux-2.5.6-pre1/fs/nfsd/vfs.c linux-2.5.6-pre2/fs/nfsd/vfs.c
--- linux-2.5.6-pre1/fs/nfsd/vfs.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/fs/nfsd/vfs.c	Thu Feb 28 13:34:22 2002
@@ -549,12 +549,15 @@
  * Obtain the readahead parameters for the file
  * specified by (dev, ino).
  */
+static spinlock_t ra_lock = SPIN_LOCK_UNLOCKED;
+
 static inline struct raparms *
 nfsd_get_raparms(kdev_t dev, ino_t ino)
 {
 	struct raparms	*ra, **rap, **frap = NULL;
 	int depth = 0;
-	
+
+	spin_lock(&ra_lock);
 	for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) {
 		if (ra->p_ino == ino && kdev_same(ra->p_dev, dev))
 			goto found;
@@ -563,8 +566,10 @@
 			frap = rap;
 	}
 	depth = nfsdstats.ra_size*11/10;
-	if (!frap)
+	if (!frap) {	
+		spin_unlock(&ra_lock);
 		return NULL;
+	}
 	rap = frap;
 	ra = *frap;
 	ra->p_dev = dev;
@@ -582,6 +587,7 @@
 	}
 	ra->p_count++;
 	nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++;
+	spin_unlock(&ra_lock);
 	return ra;
 }
 
diff -urN linux-2.5.6-pre1/fs/nls/Config.in linux-2.5.6-pre2/fs/nls/Config.in
--- linux-2.5.6-pre1/fs/nls/Config.in	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/fs/nls/Config.in	Thu Feb 28 13:34:22 2002
@@ -12,7 +12,7 @@
 # msdos and Joliet want NLS
 if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \
 	-o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \
-	-o "$CONFIG_SMB_NLS" = "y" ]; then
+	-o "$CONFIG_SMB_NLS" = "y" -o "$CONFIG_JFS_FS" != "n" ]; then
   define_bool CONFIG_NLS y
 else
   define_bool CONFIG_NLS n
diff -urN linux-2.5.6-pre1/fs/reiserfs/bitmap.c linux-2.5.6-pre2/fs/reiserfs/bitmap.c
--- linux-2.5.6-pre1/fs/reiserfs/bitmap.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/fs/reiserfs/bitmap.c	Thu Feb 28 13:34:22 2002
@@ -103,7 +103,7 @@
   if (nr >= sb_bmap_nr (rs)) {
 	  reiserfs_warning ("vs-4075: reiserfs_free_block: "
 			    "block %lu is out of range on %s\n", 
-			    block, bdevname(s->s_dev));
+			    block, s->s_id);
 	  return;
   }
 
diff -urN linux-2.5.6-pre1/fs/reiserfs/super.c linux-2.5.6-pre2/fs/reiserfs/super.c
--- linux-2.5.6-pre1/fs/reiserfs/super.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/fs/reiserfs/super.c	Thu Feb 28 13:34:22 2002
@@ -662,7 +662,7 @@
 	return 1;
     for (i = 0, bmp = REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize + 1;
 	 i < SB_BMAP_NR(s); i++, bmp = s->s_blocksize * 8 * i) {
-	SB_AP_BITMAP (s)[i] = getblk (s->s_dev, bmp, s->s_blocksize);
+	SB_AP_BITMAP (s)[i] = sb_getblk(s, bmp);
 	if (!buffer_uptodate(SB_AP_BITMAP(s)[i]))
 	    ll_rw_block(READ, 1, SB_AP_BITMAP(s) + i);
     }
@@ -770,7 +770,7 @@
        brelse(bh) ;
        printk("dev %s: Unfinished reiserfsck --rebuild-tree run detected. Please run\n"
               "reiserfsck --rebuild-tree and wait for a completion. If that fais\n"
-              "get newer reiserfsprogs package\n", kdevname (s->s_dev));
+              "get newer reiserfsprogs package\n", s->s_id);
        return 1;
     }
 
@@ -881,7 +881,7 @@
 	     ( (r5hash == yurahash) && (yurahash == GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])))) ) ) {
 	    reiserfs_warning("reiserfs: Unable to automatically detect hash"
 		"function for device %s\n"
-		"please mount with -o hash={tea,rupasov,r5}\n", kdevname (s->s_dev));
+		"please mount with -o hash={tea,rupasov,r5}\n", s->s_id);
 	    hash = UNSET_HASH;
 	    break;
 	}
@@ -893,7 +893,7 @@
 	    hash = R5_HASH;
 	else {
 	    reiserfs_warning("reiserfs: Unrecognised hash function for "
-			     "device %s\n", kdevname (s->s_dev));
+			     "device %s\n", s->s_id);
 	    hash = UNSET_HASH;
 	}
     } while (0);
diff -urN linux-2.5.6-pre1/fs/super.c linux-2.5.6-pre2/fs/super.c
--- linux-2.5.6-pre1/fs/super.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/fs/super.c	Thu Feb 28 13:34:22 2002
@@ -499,19 +499,9 @@
  * hold up the sync while mounting a device. (The newly
  * mounted device won't need syncing.)
  */
-void sync_supers(kdev_t dev)
+void sync_supers(void)
 {
 	struct super_block * sb;
-
-	if (!kdev_none(dev)) {
-		sb = get_super(dev);
-		if (sb) {
-			if (sb->s_dirt)
-				write_super(sb);
-			drop_super(sb);
-		}
-		return;
-	}
 restart:
 	spin_lock(&sb_lock);
 	sb = sb_entry(super_blocks.next);
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-adifcc/irq.h linux-2.5.6-pre2/include/asm-arm/arch-adifcc/irq.h
--- linux-2.5.6-pre1/include/asm-arm/arch-adifcc/irq.h	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-adifcc/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,13 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-adifcc/irq.h
- *
- *  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.
- */
-
-#define fixup_irq(irq)  (irq)
-
-
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-adifcc/irqs.h linux-2.5.6-pre2/include/asm-arm/arch-adifcc/irqs.h
--- linux-2.5.6-pre1/include/asm-arm/arch-adifcc/irqs.h	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-adifcc/irqs.h	Thu Feb 28 13:34:22 2002
@@ -18,11 +18,3 @@
 #define NR_IRQS			NR_XS80200_IRQS
 
 #define	IRQ_XSCALE_PMU		IRQ_XS80200_PMU
-
-#ifdef CONFIG_XSCALE_ADI_EVB
-
-/* Interrupts available on the ADI Eval Board */
-
-#endif
-
-
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-anakin/irq.h linux-2.5.6-pre2/include/asm-arm/arch-anakin/irq.h
--- linux-2.5.6-pre1/include/asm-arm/arch-anakin/irq.h	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-anakin/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,19 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-anakin/irq.h
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Changelog:
- *   10-Apr-2001 TTC	Created
- */
-
-#ifndef __ASM_ARCH_IRQ_H
-#define __ASM_ARCH_IRQ_H
-
-#define fixup_irq(i)		i
-
-#endif
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-anakin/time.h linux-2.5.6-pre2/include/asm-arm/arch-anakin/time.h
--- linux-2.5.6-pre1/include/asm-arm/arch-anakin/time.h	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-anakin/time.h	Thu Feb 28 13:34:22 2002
@@ -24,7 +24,7 @@
 {
 	timer_irq.handler = anakin_timer_interrupt;
 	timer_irq.flags = SA_INTERRUPT;
-	setup_arm_irq(IRQ_TICK, &timer_irq);
+	setup_irq(IRQ_TICK, &timer_irq);
 }
 
 #endif
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-arc/irq.h linux-2.5.6-pre2/include/asm-arm/arch-arc/irq.h
--- linux-2.5.6-pre1/include/asm-arm/arch-arc/irq.h	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-arc/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,10 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-arc/irq.h
- *
- *  Copyright (C) 1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#define fixup_irq(x) (x)
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-arc/time.h linux-2.5.6-pre2/include/asm-arm/arch-arc/time.h
--- linux-2.5.6-pre1/include/asm-arm/arch-arc/time.h	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-arc/time.h	Thu Feb 28 13:34:22 2002
@@ -30,5 +30,5 @@
 
 	timer_irq.handler = timer_interrupt;
 
-	setup_arm_irq(IRQ_TIMER, &timer_irq);
+	setup_irq(IRQ_TIMER, &timer_irq);
 }
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-cl7500/time.h linux-2.5.6-pre2/include/asm-arm/arch-cl7500/time.h
--- linux-2.5.6-pre1/include/asm-arm/arch-cl7500/time.h	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-cl7500/time.h	Thu Feb 28 13:34:22 2002
@@ -37,5 +37,5 @@
 
 	timer_irq.handler = timer_interrupt;
 
-	setup_arm_irq(IRQ_TIMER, &timer_irq);
+	setup_irq(IRQ_TIMER, &timer_irq);
 }
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-clps711x/irq.h linux-2.5.6-pre2/include/asm-arm/arch-clps711x/irq.h
--- linux-2.5.6-pre1/include/asm-arm/arch-clps711x/irq.h	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-clps711x/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,20 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-clps711x/irq.h
- *
- *  Copyright (C) 2000 Deep Blue Solutions Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#define fixup_irq(i)	(i)
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-clps711x/time.h linux-2.5.6-pre2/include/asm-arm/arch-clps711x/time.h
--- linux-2.5.6-pre1/include/asm-arm/arch-clps711x/time.h	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-clps711x/time.h	Thu Feb 28 13:34:22 2002
@@ -39,5 +39,5 @@
 {
 	clps711x_setup_timer();
 	timer_irq.handler = p720t_timer_interrupt;
-	setup_arm_irq(IRQ_TC2OI, &timer_irq);
+	setup_irq(IRQ_TC2OI, &timer_irq);
 }
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-ebsa110/irq.h linux-2.5.6-pre2/include/asm-arm/arch-ebsa110/irq.h
--- linux-2.5.6-pre1/include/asm-arm/arch-ebsa110/irq.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-ebsa110/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,13 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-ebsa110/irq.h
- *
- *  Copyright (C) 1996-1998 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Changelog:
- *   22-08-1998	RMK	Restructured IRQ routines
- */
-#define fixup_irq(i)	(i)
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-ebsa110/time.h linux-2.5.6-pre2/include/asm-arm/arch-ebsa110/time.h
--- linux-2.5.6-pre1/include/asm-arm/arch-ebsa110/time.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-ebsa110/time.h	Thu Feb 28 13:34:22 2002
@@ -39,7 +39,7 @@
 
 	timer_irq.handler = timer_interrupt;
 
-	setup_arm_irq(IRQ_EBSA110_TIMER0, &timer_irq);
+	setup_irq(IRQ_EBSA110_TIMER0, &timer_irq);
 }
 
 
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-ebsa285/irq.h linux-2.5.6-pre2/include/asm-arm/arch-ebsa285/irq.h
--- linux-2.5.6-pre1/include/asm-arm/arch-ebsa285/irq.h	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-ebsa285/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,33 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-ebsa285/irq.h
- *
- *  Copyright (C) 1996-1998 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Changelog:
- *   22-Aug-1998 RMK	Restructured IRQ routines
- *   03-Sep-1998 PJB	Merged CATS support
- *   20-Jan-1998 RMK	Started merge of EBSA286, CATS and NetWinder
- *   26-Jan-1999 PJB	Don't use IACK on CATS
- *   16-Mar-1999 RMK	Added autodetect of ISA PICs
- */
-#include <asm/hardware.h>
-#include <asm/hardware/dec21285.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-int isa_irq = -1;
-
-static inline int fixup_irq(unsigned int irq)
-{
-#ifdef PCIIACK_BASE
-	if (irq == isa_irq)
-		irq = *(unsigned char *)PCIIACK_BASE;
-#endif
-
-	return irq;
-}
-
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-ebsa285/time.h linux-2.5.6-pre2/include/asm-arm/arch-ebsa285/time.h
--- linux-2.5.6-pre1/include/asm-arm/arch-ebsa285/time.h	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-ebsa285/time.h	Thu Feb 28 13:34:22 2002
@@ -270,5 +270,5 @@
 		timer_irq.handler = isa_timer_interrupt;
 		irq = IRQ_ISA_TIMER;
 	}
-	setup_arm_irq(irq, &timer_irq);
+	setup_irq(irq, &timer_irq);
 }
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-epxa10db/irq.h linux-2.5.6-pre2/include/asm-arm/arch-epxa10db/irq.h
--- linux-2.5.6-pre1/include/asm-arm/arch-epxa10db/irq.h	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-epxa10db/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,20 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-epxa10/irq.h
- *
- *  Copyright (C) 1999 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#define fixup_irq(i)	(i)
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-epxa10db/time.h linux-2.5.6-pre2/include/asm-arm/arch-epxa10db/time.h
--- linux-2.5.6-pre1/include/asm-arm/arch-epxa10db/time.h	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-epxa10db/time.h	Thu Feb 28 13:34:22 2002
@@ -48,7 +48,7 @@
 	/* 
 	 * Make irqs happen for the system timer
 	 */
-	setup_arm_irq(IRQ_TIMER0, &timer_irq);
+	setup_irq(IRQ_TIMER0, &timer_irq);
 
 	/* Start the timer */
 	*TIMER0_LIMIT(IO_ADDRESS(EXC_TIMER00_BASE))=(unsigned int)(EXC_AHB2_CLK_FREQUENCY/200);
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-epxa10db/uncompress.h linux-2.5.6-pre2/include/asm-arm/arch-epxa10db/uncompress.h
--- linux-2.5.6-pre1/include/asm-arm/arch-epxa10db/uncompress.h	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-epxa10db/uncompress.h	Thu Feb 28 13:34:22 2002
@@ -29,14 +29,18 @@
 static void puts(const char *s)
 {
 	while (*s) {
-		while ((*UART_TSR(IO_ADDRESS(EXC_UART00_BASE)) & UART_TSR_TX_LEVEL_MSK)==15);
+		while ((*UART_TSR(EXC_UART00_BASE) &
+		       UART_TSR_TX_LEVEL_MSK)==15)
+			barrier();
 
-		*UART_TD(IO_ADDRESS(EXC_UART00_BASE)) = *s;
+		*UART_TD(EXC_UART00_BASE) = *s;
 
 		if (*s == '\n') {
-		while ((*UART_TSR(IO_ADDRESS(EXC_UART00_BASE)) & UART_TSR_TX_LEVEL_MSK)==15);
+			while ((*UART_TSR(EXC_UART00_BASE) &
+			       UART_TSR_TX_LEVEL_MSK)==15)
+				barrier();
 
-			*UART_TD(IO_ADDRESS(EXC_UART00_BASE)) = '\r';
+			*UART_TD(EXC_UART00_BASE) = '\r';
 		}
 		s++;
 	}
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-integrator/irq.h linux-2.5.6-pre2/include/asm-arm/arch-integrator/irq.h
--- linux-2.5.6-pre1/include/asm-arm/arch-integrator/irq.h	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-integrator/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,20 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-integrator/irq.h
- *
- *  Copyright (C) 1999 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#define fixup_irq(i)	(i)
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-integrator/time.h linux-2.5.6-pre2/include/asm-arm/arch-integrator/time.h
--- linux-2.5.6-pre1/include/asm-arm/arch-integrator/time.h	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-integrator/time.h	Thu Feb 28 13:34:22 2002
@@ -135,6 +135,6 @@
 	/* 
 	 * Make irqs happen for the system timer
 	 */
-	setup_arm_irq(IRQ_TIMERINT1, &timer_irq);
+	setup_irq(IRQ_TIMERINT1, &timer_irq);
 	gettimeoffset = integrator_gettimeoffset;
 }
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-iop310/irq.h linux-2.5.6-pre2/include/asm-arm/arch-iop310/irq.h
--- linux-2.5.6-pre1/include/asm-arm/arch-iop310/irq.h	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-iop310/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,13 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-iop80310/irq.h
- *
- *  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.
- */
-
-#define fixup_irq(irq)  (irq)
-
-
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-l7200/irq.h linux-2.5.6-pre2/include/asm-arm/arch-l7200/irq.h
--- linux-2.5.6-pre1/include/asm-arm/arch-l7200/irq.h	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-l7200/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,12 +0,0 @@
-/*
- * include/asm-arm/arch-l7200/irq.h
- *
- * Copyright (C) 2000 Rob Scott (rscott@mtrob.fdns.ne
- *                    Steve Hill (sjhill@cotw.com)
- *
- * Changelog:
- *   01-02-2000	RS	Created l7200 version, derived from ebsa110 code
- *   04-15-2000 RS      Made dependent on hardware.h
- *   05-05-2000 SJH     Complete rewrite
- */
-#define fixup_irq(x) (x)
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-l7200/time.h linux-2.5.6-pre2/include/asm-arm/arch-l7200/time.h
--- linux-2.5.6-pre1/include/asm-arm/arch-l7200/time.h	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-l7200/time.h	Thu Feb 28 13:34:23 2002
@@ -58,7 +58,7 @@
 
 	timer_irq.handler = timer_interrupt;
 
-	setup_arm_irq(IRQ_RTC_TICK, &timer_irq);
+	setup_irq(IRQ_RTC_TICK, &timer_irq);
 
 	RTC_RTCCR = RTC_RATE_128 | RTC_EN_TIC;	/* Set rate and enable timer */
 }
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-nexuspci/irq.h linux-2.5.6-pre2/include/asm-arm/arch-nexuspci/irq.h
--- linux-2.5.6-pre1/include/asm-arm/arch-nexuspci/irq.h	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-nexuspci/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-/*
- * include/asm-arm/arch-nexuspci/irq.h
- *
- * Copyright (C) 1998, 1999, 2000 Philip Blundell
- */
-
-/*
- * 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.
- */
-#define fixup_irq(x) (x)
-
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-nexuspci/time.h linux-2.5.6-pre2/include/asm-arm/arch-nexuspci/time.h
--- linux-2.5.6-pre1/include/asm-arm/arch-nexuspci/time.h	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-nexuspci/time.h	Thu Feb 28 13:34:23 2002
@@ -55,5 +55,5 @@
 	timer_irq.handler = timer_interrupt;
 	timer_irq.flags = SA_SHIRQ;
 
-	setup_arm_irq(IRQ_TIMER, &timer_irq);
+	setup_irq(IRQ_TIMER, &timer_irq);
 }
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-rpc/irq.h linux-2.5.6-pre2/include/asm-arm/arch-rpc/irq.h
--- linux-2.5.6-pre1/include/asm-arm/arch-rpc/irq.h	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-rpc/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-rpc/irq.h
- *
- *  Copyright (C) 1996 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Changelog:
- *   10-10-1996	RMK	Brought up to date with arch-sa110eval
- *   22-08-1998	RMK	Restructured IRQ routines
- */
-#define fixup_irq(x) (x)
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-rpc/time.h linux-2.5.6-pre2/include/asm-arm/arch-rpc/time.h
--- linux-2.5.6-pre1/include/asm-arm/arch-rpc/time.h	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-rpc/time.h	Thu Feb 28 13:34:23 2002
@@ -30,5 +30,5 @@
 
 	timer_irq.handler = timer_interrupt;
 
-	setup_arm_irq(IRQ_TIMER, &timer_irq);
+	setup_irq(IRQ_TIMER, &timer_irq);
 }
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-sa1100/assabet.h linux-2.5.6-pre2/include/asm-arm/arch-sa1100/assabet.h
--- linux-2.5.6-pre1/include/asm-arm/arch-sa1100/assabet.h	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-sa1100/assabet.h	Thu Feb 28 13:34:23 2002
@@ -62,7 +62,7 @@
 #ifdef CONFIG_SA1100_ASSABET
 extern void ASSABET_BCR_frob(unsigned int mask, unsigned int set);
 #else
-#define ASSABET_BCR_frob(x)	do { } while (0)
+#define ASSABET_BCR_frob(x,y)	do { } while (0)
 #endif
 
 #define ASSABET_BCR_set(x)	ASSABET_BCR_frob((x), (x))
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-sa1100/badge4.h linux-2.5.6-pre2/include/asm-arm/arch-sa1100/badge4.h
--- linux-2.5.6-pre1/include/asm-arm/arch-sa1100/badge4.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/include/asm-arm/arch-sa1100/badge4.h	Thu Feb 28 13:34:23 2002
@@ -0,0 +1,74 @@
+/*
+ * linux/include/asm-arm/arch-sa1100/badge4.h
+ *
+ *   Tim Connors <connors@hpl.hp.com>
+ *   Christopher Hoover <ch@hpl.hp.com>
+ *
+ * Copyright (C) 2002 Hewlett-Packard Company
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#error "include <asm/hardware.h> instead"
+#endif
+
+#define BADGE4_SA1111_BASE		(0x48000000)
+
+/* GPIOs on the BadgePAD 4 */
+#define BADGE4_GPIO_INT_1111		GPIO_GPIO0   /* SA-1111 IRQ */
+
+#define BADGE4_GPIO_INT_VID		GPIO_GPIO1   /* Video expansion */
+#define BADGE4_GPIO_LGP2		GPIO_GPIO2   /* GPIO_LDD8 */
+#define BADGE4_GPIO_LGP3		GPIO_GPIO3   /* GPIO_LDD9 */
+#define BADGE4_GPIO_LGP4		GPIO_GPIO4   /* GPIO_LDD10 */
+#define BADGE4_GPIO_LGP5		GPIO_GPIO5   /* GPIO_LDD11 */
+#define BADGE4_GPIO_LGP6		GPIO_GPIO6   /* GPIO_LDD12 */
+#define BADGE4_GPIO_LGP7		GPIO_GPIO7   /* GPIO_LDD13 */
+#define BADGE4_GPIO_LGP8		GPIO_GPIO8   /* GPIO_LDD14 */
+#define BADGE4_GPIO_LGP9		GPIO_GPIO9   /* GPIO_LDD15 */
+#define BADGE4_GPIO_GPA_VID		GPIO_GPIO10  /* Video expansion */
+#define BADGE4_GPIO_GPB_VID		GPIO_GPIO11  /* Video expansion */
+#define BADGE4_GPIO_GPC_VID		GPIO_GPIO12  /* Video expansion */
+
+#define BADGE4_GPIO_UART_HS1		GPIO_GPIO13
+#define BADGE4_GPIO_UART_HS2		GPIO_GPIO14
+
+#define BADGE4_GPIO_MUXSEL0		GPIO_GPIO15
+#define BADGE4_GPIO_TESTPT_J7		GPIO_GPIO16
+
+#define BADGE4_GPIO_SDSDA		GPIO_GPIO17  /* SDRAM SPD Data */
+#define BADGE4_GPIO_SDSCL		GPIO_GPIO18  /* SDRAM SPD Clock */
+#define BADGE4_GPIO_SDTYP0		GPIO_GPIO19  /* SDRAM Type Control */
+#define BADGE4_GPIO_SDTYP1		GPIO_GPIO20  /* SDRAM Type Control */
+
+#define BADGE4_GPIO_BGNT_1111		GPIO_GPIO21  /* GPIO_MBGNT */
+#define BADGE4_GPIO_BREQ_1111		GPIO_GPIO22  /* GPIO_TREQA */
+
+#define BADGE4_GPIO_TESTPT_J6		GPIO_GPIO23
+
+#define BADGE4_GPIO_PCMEN5V		GPIO_GPIO24  /* 5V power */
+
+#define BADGE4_GPIO_SA1111_NRST		GPIO_GPIO25  /* SA-1111 nRESET */
+
+#define BADGE4_GPIO_TESTPT_J5		GPIO_GPIO26
+
+#define BADGE4_GPIO_CLK_1111		GPIO_GPIO27  /* GPIO_32_768kHz */
+
+/* Interrupts on the BadgePAD 4 */
+#define BADGE4_IRQ_GPIO_SA1111		IRQ_GPIO0    /* SA-1111 interrupt */
+
+
+/* PCM5ENV Usage tracking */
+
+#define BADGE4_5V_PCMCIA_SOCK0		(1<<0)
+#define BADGE4_5V_PCMCIA_SOCK1		(1<<1)
+#define BADGE4_5V_PCMCIA_SOCK(n)	(1<<(n))
+#define BADGE4_5V_USB			(1<<2)
+
+#ifndef __ASSEMBLY__
+extern void badge4_set_5V(unsigned subsystem, int on);
+#endif
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-sa1100/hardware.h linux-2.5.6-pre2/include/asm-arm/arch-sa1100/hardware.h
--- linux-2.5.6-pre1/include/asm-arm/arch-sa1100/hardware.h	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-sa1100/hardware.h	Thu Feb 28 13:34:23 2002
@@ -87,22 +87,6 @@
 
 #include "SA-1100.h"
 
-
-/*
- * SA1100 GPIO edge detection for IRQs:
- * IRQs are generated on Falling-Edge, Rising-Edge, or both.
- * This must be called *before* the corresponding IRQ is registered.
- * Use this instead of directly setting GRER/GFER.
- */
-#define GPIO_NO_EDGES		0
-#define GPIO_FALLING_EDGE       1
-#define GPIO_RISING_EDGE        2
-#define GPIO_BOTH_EDGES         3
-#ifndef __ASSEMBLY__
-extern void set_GPIO_IRQ_edge( int gpio_mask, int edge_mask );
-#endif
-
-
 /*
  * Implementation specifics.
  *
@@ -112,6 +96,8 @@
  * ifdefs, and lots of other preprocessor gunk elsewhere.
  */
 
+#include "badge4.h"
+
 #ifdef CONFIG_SA1100_PANGOLIN
 #include "pangolin.h"
 #endif
@@ -179,6 +165,8 @@
 #include "adsbitsy.h"
 #endif
 
+#include "stork.h"
+
 #include "system3.h"
 
 #ifdef CONFIG_SA1101
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-sa1100/ide.h linux-2.5.6-pre2/include/asm-arm/arch-sa1100/ide.h
--- linux-2.5.6-pre1/include/asm-arm/arch-sa1100/ide.h	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-sa1100/ide.h	Thu Feb 28 13:34:23 2002
@@ -113,7 +113,7 @@
 
         /* Enable GPIO as interrupt line */
         GPDR &= ~LART_GPIO_IDE;
-        set_GPIO_IRQ_edge(LART_GPIO_IDE, GPIO_RISING_EDGE);
+	set_irq_type(LART_IRQ_IDE, IRQT_RISING);
         
         /* set PCMCIA interface timing */
         MECR = 0x00060006;
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-sa1100/irq.h linux-2.5.6-pre2/include/asm-arm/arch-sa1100/irq.h
--- linux-2.5.6-pre1/include/asm-arm/arch-sa1100/irq.h	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-sa1100/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,13 +0,0 @@
-/*
- * linux/include/asm-arm/arch-sa1100/irq.h
- * 
- * Author: Nicolas Pitre
- */
-
-#define fixup_irq(x)	(x)
-
-/*
- * This prototype is required for cascading of multiplexed interrupts.
- * Since it doesn't exist elsewhere, we'll put it here for now.
- */
-extern void do_IRQ(int irq, struct pt_regs *regs);
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-sa1100/irqs.h linux-2.5.6-pre2/include/asm-arm/arch-sa1100/irqs.h
--- linux-2.5.6-pre1/include/asm-arm/arch-sa1100/irqs.h	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-sa1100/irqs.h	Thu Feb 28 13:34:23 2002
@@ -148,6 +148,7 @@
  */
 #define IRQ_NEPONSET_SMC9196	(IRQ_BOARD_START + 0)
 #define IRQ_NEPONSET_USAR	(IRQ_BOARD_START + 1)
+#define IRQ_NEPONSET_SA1111	(IRQ_BOARD_START + 2)
 
 /* PT Digital Board Interrupts (CONFIG_SA1100_PT_SYSTEM3) */
 #define IRQ_SYSTEM3_SMC9196	(IRQ_BOARD_START + 0)
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-sa1100/stork.h linux-2.5.6-pre2/include/asm-arm/arch-sa1100/stork.h
--- linux-2.5.6-pre1/include/asm-arm/arch-sa1100/stork.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/include/asm-arm/arch-sa1100/stork.h	Thu Feb 28 13:34:23 2002
@@ -0,0 +1,164 @@
+/*
+	stork.h
+
+*/
+
+#ifndef STORK_SA1100_H
+#define STORK_SA1100_H
+
+/* ugly - this will make sure we build sa1100fb for the Nec display not the Kyocera */
+#define STORK_TFT	1
+
+
+#define GPIO_STORK_SWITCH_1		(1 << 0)    /* Switch 1 - input */
+#define GPIO_STORK_SWITCH_2		(1 << 1)    /* Switch 2 - input */
+#define GPIO_STORK_TOUCH_SCREEN_BUSY	(1 << 10)   /* TOUCH_SCREEN_BUSY - input */
+#define GPIO_STORK_TOUCH_SCREEN_DATA	(1 << 11)   /* TOUCH_SCREEN_DATA - input */
+#define GPIO_STORK_CODEC_AGCSTAT	(1 << 12)   /* CODEC_AGCSTAT -input */
+#define GPIO_STORK_RS232_ON		(1 << 13)   /* enable RS232 (UART1) */
+#define GPIO_STORK_TEST_POINT		(1 << 14)   /* to test point */
+#define GPIO_STORK_L3_I2C_SDA		(1 << 15)   /* L3_I2C_SDA - bidirectional */
+#define GPIO_STORK_PSU_SYNC_MODE	(1 << 16)   /* PSU_SYNC_MODE - output */
+#define GPIO_STORK_L3_MODE		(1 << 17)   /* L3 mode - output (??) */
+#define GPIO_STORK_L3_I2C_SCL		(1 << 18)   /* L3_I2C_SCL - bidirectional */
+#define GPIO_STORK_AUDIO_CLK		(1 << 19)   /* SSP external clock (Audio clock) - input */
+#define GPIO_STORK_PCMCIA_A_CARD_DETECT	(1 << 20)   /* PCMCIA_A_CARD_DETECT - input */
+#define GPIO_STORK_PCMCIA_B_CARD_DETECT	(1 << 21)   /* PCMCIA_B_CARD_DETECT - input */
+#define GPIO_STORK_PCMCIA_A_RDY		(1 << 22)   /* PCMCIA_A_RDY - input */
+#define GPIO_STORK_PCMCIA_B_RDY		(1 << 23)   /* PCMCIA_B_RDY - input */
+#define GPIO_STORK_SWITCH_EXTRA_IRQ	(1 << 24)   /* Extra IRQ from switch detect logic - input  */
+#define GPIO_STORK_SWITCH_IRQ		(1 << 25)   /* Sitch irq - input */
+#define GPIO_STORK_BATTERY_LOW_IRQ	(1 << 26)   /* BATTERY_LOW_IRQ - input */
+#define GPIO_STORK_TOUCH_SCREEN_PEN_IRQ	(1 << 27)   /* TOUCH_SCREEN_PEN_IRQ -input */
+
+#define IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT	IRQ_GPIO20   /* PCMCIA_A_CARD_DETECT - input */
+#define IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT	IRQ_GPIO21   /* PCMCIA_B_CARD_DETECT - input */
+
+#define IRQ_GPIO_STORK_SWITCH_1			IRQ_GPIO0    /* Switch 1 - input - active low */
+#define IRQ_GPIO_STORK_SWITCH_2			IRQ_GPIO1    /* Switch 2 - input - active low */
+#define IRQ_GPIO_STORK_SWITCH_EXTRA_IRQ		IRQ_GPIO24   /* Extra IRQ from switch detect logic - input - active low  */
+#define IRQ_GPIO_STORK_SWITCH_IRQ		IRQ_GPIO25   /* Switch irq - input- active low  */
+#define IRQ_GPIO_STORK_BATTERY_LOW_IRQ		IRQ_GPIO26   /* BATTERY_LOW_IRQ - input - active low */
+#define IRQ_GPIO_STORK_TOUCH_SCREEN_PEN_IRQ	IRQ_GPIO27   /* TOUCH_SCREEN_PEN_IRQ -input - goes low when it happens */
+
+/* this may be bogus - no it's not the RDY line becomes the IRQ line when we're up as an IO device */
+#define IRQ_GPIO_STORK_PCMCIA_A_RDY		IRQ_GPIO22   /* PCMCIA_A_RDY - input */
+#define IRQ_GPIO_STORK_PCMCIA_B_RDY		IRQ_GPIO23   /* PCMCIA_B_RDY - input */
+
+/* the default outputs, others are optional - I'll set these in the bootldr for now */
+#define GPIO_STORK_OUTPUT_BITS (GPIO_STORK_RS232_ON | GPIO_STORK_PSU_SYNC_MODE | GPIO_STORK_L3_MODE)
+
+#define STORK_LATCH_A_ADDR		0x08000000  /* cs1 A5 = 0 */
+#define STORK_LATCH_B_ADDR		0x08000020  /* cs1 A5 = 1 */
+
+#define STORK_LCDCPLD_BASE_ADDR		0x10000000  /* cs2 A5 = 0 */
+
+/* bit defs for latch A - these are write only and will need to be mirrored!  */
+
+#define STORK_TEMP_IC_POWER_ON		(1 << 0)
+#define STORK_SED1386_POWER_ON		(1 << 1)
+#define STORK_LCD_3V3_POWER_ON		(1 << 2)
+#define STORK_LCD_5V_POWER_ON		(1 << 3)
+#define STORK_LCD_BACKLIGHT_INVERTER_ON	(1 << 4)
+#define STORK_PCMCIA_PULL_UPS_POWER_ON	(1 << 5)
+#define STORK_PCMCIA_A_POWER_ON		(1 << 6)
+#define STORK_PCMCIA_B_POWER_ON		(1 << 7)
+#define STORK_AUDIO_POWER_ON		(1 << 8)
+#define STORK_AUDIO_AMP_ON		(1 << 9)
+#define STORK_BAR_CODE_POWER_ON		(1 << 10)
+#define STORK_BATTERY_CHARGER_ON	(1 << 11)
+#define STORK_SED1386_RESET		(1 << 12)
+#define STORK_IRDA_FREQUENCY_SELECT	(1 << 13)
+#define STORK_IRDA_MODE_0		(1 << 14)
+#define STORK_IRDA_MODE_1		(1 << 15)
+
+/* and for B */
+
+#define STORK_AUX_AD_SEL_0		(1 << 0)
+#define STORK_AUX_AD_SEL_1		(1 << 1)
+#define STORK_TOUCH_SCREEN_DCLK		(1 << 2)
+#define STORK_TOUCH_SCREEN_DIN		(1 << 3)
+#define STORK_TOUCH_SCREEN_CS		(1 << 4)
+#define STORK_DA_CS			(1 << 5)
+#define STORK_DA_LD			(1 << 6)
+#define STORK_RED_LED			(1 << 7)	/* active LOW */
+#define STORK_GREEN_LED			(1 << 8)	/* active LOW */
+#define STORK_YELLOW_LED		(1 << 9)	/* active LOW */
+#define STORK_PCMCIA_B_RESET		(1 << 10)
+#define STORK_PCMCIA_A_RESET		(1 << 11)
+#define STORK_AUDIO_CODEC_RESET		(1 << 12)
+#define STORK_CODEC_QMUTE		(1 << 13)
+#define STORK_AUDIO_CLOCK_SEL0		(1 << 14)
+#define STORK_AUDIO_CLOCK_SEL1		(1 << 15)
+
+
+/*
+
+    There are 8 control bits in the touch screen controller (AD7873)
+
+    S A2 A1 A0 MODE SER/DFR# PD1 PD0
+
+    S 		Start bit, always one.
+    A2 - A0	Channel select bits
+    MODE	0 => 12 bit resolution, 1 => 8 bit
+    SER/DFR#	Single ender/Differential Reference Select bit
+    PD1, PD0	Power management bits (usually 10)
+
+
+From Table 1.
+
+	A2-A0
+
+  	0 Temp0 (SER must be 1)
+	1 X+ (is this a typo? - is this X- really?)
+	2 VBAT,
+	3 read X+ (Z1),
+	4 read Y- (Z2), 5 => read Y+,
+
+*/
+
+#define AD7873_START		0x80		/* all commands need this to be set */
+#define AD7873_ADDR_BITS	4		/* ie shift by this */
+#define AD7873_8BITMODE		0x08		/* 0 => 12 bit convertions */
+#define AD7873_SER_DFR		0x04
+#define AD7873_PD1		0x02
+#define AD7873_PD0		0x01
+
+#define AD7873_TEMP0		AD7873_SER_DFR
+#define AD7873_X		(1 << AD7873_ADDR_BITS)
+#define AD7873_VBAT		((2 << AD7873_ADDR_BITS) | AD7873_SER_DFR)
+#define AD7873_X_Z1		(3 << AD7873_ADDR_BITS)
+#define AD7873_Y_Z2		(4 << AD7873_ADDR_BITS)
+#define AD7873_Y		(5 << AD7873_ADDR_BITS)
+#define AD7873_AUX		((6 << AD7873_ADDR_BITS) | AD7873_SER_DFR)
+#define AD7873_TEMP1		((7 << AD7873_ADDR_BITS) | AD7873_SER_DFR)
+
+#ifndef __ASSEMBLY__
+
+extern int storkSetLatchA(int bits);
+extern int storkClearLatchA(int bits);
+
+extern int storkSetLatchB(int bits);
+extern int storkClearLatchB(int bits);
+
+extern int storkSetLCDCPLD(int which, int bits);
+extern int storkClearLCDCPLD(int which, int bits);
+
+extern void storkSetGPIO(int bits);
+extern void storkClearGPIO(int bits);
+
+extern int storkGetGPIO(void);
+
+extern void storkClockShortToDtoA(int word);
+extern int storkClockByteToTS(int byte);
+
+
+/* this will return the current state of the hardware ANDED with the given bits
+   so NE => at least one bit was set, but maybe not all of them! */
+
+extern int storkTestGPIO(int bits);
+
+
+#endif
+
+#endif
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-sa1100/time.h linux-2.5.6-pre2/include/asm-arm/arch-sa1100/time.h
--- linux-2.5.6-pre1/include/asm-arm/arch-sa1100/time.h	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-sa1100/time.h	Thu Feb 28 13:34:23 2002
@@ -98,7 +98,7 @@
 	timer_irq.handler = sa1100_timer_interrupt;
 	OSMR0 = 0;		/* set initial match at 0 */
 	OSSR = 0xf;		/* clear status on all timers */
-	setup_arm_irq(IRQ_OST0, &timer_irq);
+	setup_irq(IRQ_OST0, &timer_irq);
 	OIER |= OIER_E0;	/* enable match on timer 0 to cause interrupts */
 	OSCR = 0;		/* initialize free-running timer, force first match */
 }
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-shark/hardware.h linux-2.5.6-pre2/include/asm-arm/arch-shark/hardware.h
--- linux-2.5.6-pre1/include/asm-arm/arch-shark/hardware.h	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-shark/hardware.h	Thu Feb 28 13:34:23 2002
@@ -38,7 +38,8 @@
 
 
 /* defines for the Framebuffer */
-#define FB_START                0x06000000
+#define FB_START		0x06000000
+#define FB_SIZE			0x01000000
 
 #define UNCACHEABLE_ADDR        0xdf010000
 
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-shark/irq.h linux-2.5.6-pre2/include/asm-arm/arch-shark/irq.h
--- linux-2.5.6-pre1/include/asm-arm/arch-shark/irq.h	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-shark/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,10 +0,0 @@
-/*
- * linux/include/asm-arm/arch-shark/irq.h
- *
- * by Alexander Schulz
- *
- * derived from linux/arch/ppc/kernel/i8259.c and:
- * include/asm-arm/arch-ebsa110/irq.h
- * Copyright (C) 1996-1998 Russell King
- */
-#define fixup_irq(x) (x)
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-shark/keyboard.h linux-2.5.6-pre2/include/asm-arm/arch-shark/keyboard.h
--- linux-2.5.6-pre1/include/asm-arm/arch-shark/keyboard.h	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-shark/keyboard.h	Thu Feb 28 13:34:23 2002
@@ -29,7 +29,6 @@
 
 static inline void kbd_init_hw(void)
 {
-	if (have_isa_bridge) {
 		k_setkeycode    = pckbd_setkeycode;
 		k_getkeycode    = pckbd_getkeycode;
 		k_translate     = pckbd_translate;
@@ -40,7 +39,6 @@
 		k_sysrq_xlate   = pckbd_sysrq_xlate;
 #endif
 		pckbd_init_hw();
-	}
 }
 
 /*
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-shark/param.h linux-2.5.6-pre2/include/asm-arm/arch-shark/param.h
--- linux-2.5.6-pre1/include/asm-arm/arch-shark/param.h	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-shark/param.h	Thu Feb 28 13:34:23 2002
@@ -4,9 +4,5 @@
  * by Alexander Schulz
  */
 
-/* This must be a power of 2 because the RTC
- * can't use anything else.
- */
-#define HZ 64
+#define HZ 100
 
-#define hz_to_std(a) ((a * HZ)/100)
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-shark/time.h linux-2.5.6-pre2/include/asm-arm/arch-shark/time.h
--- linux-2.5.6-pre1/include/asm-arm/arch-shark/time.h	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-shark/time.h	Thu Feb 28 13:34:23 2002
@@ -3,44 +3,21 @@
  *
  * by Alexander Schulz
  *
- * Uses the real time clock because you can't run
- * the timer with level triggered interrupts and
- * you can't run the shark with edge triggered
- * inetrrupts (loses ints and hangs).
- *
- * derived from linux/drivers/char/rtc.c and:
- * linux/include/asm-arm/arch-ebsa110/time.h
+ * derived from include/asm-arm/arch-ebsa110/time.h
  * Copyright (c) 1996,1997,1998 Russell King.
  */
 
 #include <asm/leds.h>
-#include <linux/mc146818rtc.h>
-
-#define IRQ_TIMER 8
+#include <asm/param.h>
 
-extern void get_rtc_time(struct rtc_time *rtc_tm);
-extern void set_rtc_irq_bit(unsigned char bit);
-extern unsigned long epoch;
+#define IRQ_TIMER 0
+#define HZ_TIME ((1193180 + HZ/2) / HZ)
 
 static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-
-	CMOS_READ(RTC_INTR_FLAGS);	
-
 	do_leds();
-
-	{
-#ifdef DIVISOR
-		static unsigned int divisor;
-
-		if (divisor-- == 0) {
-			divisor = DIVISOR - 1;
-#else
-		{
-#endif
-			do_timer(regs);
-		}
-	}
+	do_timer(regs);
+	do_profile(regs);
 }
 
 /*
@@ -48,38 +25,15 @@
  */
 void __init time_init(void)
 {
-        struct rtc_time r_time;
         unsigned long flags;
-	int tmp = 0;
-	unsigned char val;
 
-        /*
-	 * Set the clock to 128 Hz, we already have a valid
-	 * vector now:
-	 */
-
-	while (HZ > (1<<tmp))
-	  tmp++;
-
-	/*
-	 * Check that the input was really a power of 2.
-	 */
-	if (HZ != (1<<tmp))
-	  panic("Please set HZ to a power of 2!");
-
-	save_flags(flags);
-	cli();
-	val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
-	val |= (16 - tmp);
-	CMOS_WRITE(val, RTC_FREQ_SELECT);
-	restore_flags(flags);
-	set_rtc_irq_bit(RTC_PIE);
-
-	get_rtc_time(&r_time);
-	xtime.tv_sec = mktime(r_time.tm_year+epoch, r_time.tm_mon+1, r_time.tm_mday,
-			      r_time.tm_hour, r_time.tm_min, r_time.tm_sec);
+	outb(0x34, 0x43);               /* binary, mode 0, LSB/MSB, Ch 0 */
+	outb(HZ_TIME & 0xff, 0x40);     /* LSB of count */
+	outb(HZ_TIME >> 8, 0x40);
+
+	xtime.tv_sec = 0;
 
 	timer_irq.handler = timer_interrupt;
 	timer_irq.flags = SA_INTERRUPT; /* FIXME: really? */
-	setup_arm_irq(IRQ_TIMER, &timer_irq);
+	setup_irq(IRQ_TIMER, &timer_irq);
 }
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-tbox/irq.h linux-2.5.6-pre2/include/asm-arm/arch-tbox/irq.h
--- linux-2.5.6-pre1/include/asm-arm/arch-tbox/irq.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-tbox/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,13 +0,0 @@
-/*
- * include/asm-arm/arch-tbox/irq.h
- *
- * Copyright (C) 1998, 1999, 2000 Philip Blundell
- */
-
-/*
- * 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.
- */
-#define fixup_irq(x) (x)
diff -urN linux-2.5.6-pre1/include/asm-arm/arch-tbox/time.h linux-2.5.6-pre2/include/asm-arm/arch-tbox/time.h
--- linux-2.5.6-pre1/include/asm-arm/arch-tbox/time.h	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/include/asm-arm/arch-tbox/time.h	Thu Feb 28 13:34:23 2002
@@ -32,5 +32,5 @@
 void __init time_init(void)
 {
 	timer_irq.handler = timer_interrupt;
-	setup_arm_irq(IRQ_TIMER, &timer_irq);
+	setup_irq(IRQ_TIMER, &timer_irq);
 }
diff -urN linux-2.5.6-pre1/include/asm-arm/bitops.h linux-2.5.6-pre2/include/asm-arm/bitops.h
--- linux-2.5.6-pre1/include/asm-arm/bitops.h	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/include/asm-arm/bitops.h	Thu Feb 28 13:34:23 2002
@@ -327,6 +327,23 @@
 #define ffs(x) generic_ffs(x)
 
 /*
+ * Find first bit set in a 168-bit bitmap, where the first
+ * 128 bits are unlikely to be set.
+ */
+static inline int sched_find_first_bit(unsigned long *b)
+{
+	if (unlikely(b[0]))
+		return __ffs(b[0]);
+	if (unlikely(b[1]))
+		return __ffs(b[1]) + 32;
+	if (unlikely(b[2]))
+		return __ffs(b[2]) + 64;
+	if (b[3])
+		return __ffs(b[3]) + 96;
+	return __ffs(b[4]) + 128;
+}
+
+/*
  * hweightN: returns the hamming weight (i.e. the number
  * of bits set) of a N-bit word
  */
diff -urN linux-2.5.6-pre1/include/asm-arm/cpu-multi32.h linux-2.5.6-pre2/include/asm-arm/cpu-multi32.h
--- linux-2.5.6-pre1/include/asm-arm/cpu-multi32.h	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/include/asm-arm/cpu-multi32.h	Thu Feb 28 13:34:23 2002
@@ -93,21 +93,6 @@
 		void (*invalidate_page)(void *virt_page);
 	} icache;
 
-	struct {	/* TLB */
-		/*
-		 * flush all TLBs
-		 */
-		void (*invalidate_all)(void);
-		/*
-		 * flush a specific TLB
-		 */
-		void (*invalidate_range)(unsigned long address, unsigned long end);
-		/*
-		 * flush a specific TLB
-		 */
-		void (*invalidate_page)(unsigned long address, int flags);
-	} tlb;
-
 	struct {	/* PageTable */
 		/*
 		 * Set the page table
@@ -152,10 +137,6 @@
 #define cpu_icache_invalidate_range(s,e)	processor.icache.invalidate_range(s,e)
 #define cpu_icache_invalidate_page(vp)		processor.icache.invalidate_page(vp)
 
-#define cpu_tlb_invalidate_all()		processor.tlb.invalidate_all()
-#define cpu_tlb_invalidate_range(s,e)		processor.tlb.invalidate_range(s,e)
-#define cpu_tlb_invalidate_page(vp,f)		processor.tlb.invalidate_page(vp,f)
-
 #define cpu_set_pgd(pgd)			processor.pgtable.set_pgd(pgd)
 #define cpu_set_pmd(pmdp, pmd)			processor.pgtable.set_pmd(pmdp, pmd)
 #define cpu_set_pte(ptep, pte)			processor.pgtable.set_pte(ptep, pte)
diff -urN linux-2.5.6-pre1/include/asm-arm/cpu-single.h linux-2.5.6-pre2/include/asm-arm/cpu-single.h
--- linux-2.5.6-pre1/include/asm-arm/cpu-single.h	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/include/asm-arm/cpu-single.h	Thu Feb 28 13:34:23 2002
@@ -37,9 +37,6 @@
 #define cpu_dcache_clean_entry		__cpu_fn(CPU_NAME,_dcache_clean_entry)
 #define cpu_icache_invalidate_range	__cpu_fn(CPU_NAME,_icache_invalidate_range)
 #define cpu_icache_invalidate_page	__cpu_fn(CPU_NAME,_icache_invalidate_page)
-#define cpu_tlb_invalidate_all		__cpu_fn(CPU_NAME,_tlb_invalidate_all)
-#define cpu_tlb_invalidate_range	__cpu_fn(CPU_NAME,_tlb_invalidate_range)
-#define cpu_tlb_invalidate_page		__cpu_fn(CPU_NAME,_tlb_invalidate_page)
 #define cpu_set_pgd			__cpu_fn(CPU_NAME,_set_pgd)
 #define cpu_set_pmd			__cpu_fn(CPU_NAME,_set_pmd)
 #define cpu_set_pte			__cpu_fn(CPU_NAME,_set_pte)
@@ -73,10 +70,6 @@
 extern void cpu_icache_invalidate_range(unsigned long start, unsigned long end);
 extern void cpu_icache_invalidate_page(void *virt_page);
 
-extern void cpu_tlb_invalidate_all(void);
-extern void cpu_tlb_invalidate_range(unsigned long address, unsigned long end);
-extern void cpu_tlb_invalidate_page(unsigned long address, int flags);
-
 extern void cpu_set_pgd(unsigned long pgd_phys);
 extern void cpu_set_pmd(pmd_t *pmdp, pmd_t pmd);
 extern void cpu_set_pte(pte_t *ptep, pte_t pte);
diff -urN linux-2.5.6-pre1/include/asm-arm/glue.h linux-2.5.6-pre2/include/asm-arm/glue.h
--- linux-2.5.6-pre1/include/asm-arm/glue.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6-pre2/include/asm-arm/glue.h	Thu Feb 28 13:34:23 2002
@@ -0,0 +1,78 @@
+/*
+ *  linux/include/asm-arm/glue.h
+ *
+ *  Copyright (C) 1997-1999 Russell King
+ *  Copyright (C) 2000-2002 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  This file provides the glue to stick the processor-specific bits
+ *  into the kernel in an efficient manner.  The idea is to use branches
+ *  when we're only targetting one class of TLB, or indirect calls
+ *  when we're targetting multiple classes of TLBs.
+ */
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+
+#ifdef __STDC__
+#define ____glue(name,fn)	name##fn
+#else
+#define ____glue(name,fn)	name/**/fn
+#endif
+#define __glue(name,fn)		____glue(name,fn)
+
+/*
+ * Select MMU TLB handling.
+ */
+
+/*
+ * ARMv3 MMU
+ */
+#undef _TLB
+#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
+# ifdef _TLB
+#  define MULTI_TLB 1
+# else
+#  define _TLB v3
+# endif
+#endif
+
+/*
+ * ARMv4 MMU without write buffer
+ */
+#if defined(CONFIG_CPU_ARM720T)
+# ifdef _TLB
+#  define MULTI_TLB 1
+# else
+#  define _TLB v4
+# endif
+#endif
+
+/*
+ * ARMv4 MMU with write buffer, with invalidate I TLB entry instruction
+ */
+#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \
+    defined(CONFIG_CPU_ARM926T) || defined(CONFIG_CPU_ARM1020) || \
+    defined(CONFIG_CPU_XSCALE)
+# ifdef _TLB
+#  define MULTI_TLB 1
+# else
+#  define _TLB v4wbi
+# endif
+#endif
+
+/*
+ * ARMv4 MMU with write buffer, without invalidate I TLB entry instruction
+ */
+#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100)
+# ifdef _TLB
+#  define MULTI_TLB 1
+# else
+#  define _TLB v4wb
+# endif
+#endif
+
+#endif
diff -urN linux-2.5.6-pre1/include/asm-arm/io.h linux-2.5.6-pre2/include/asm-arm/io.h
--- linux-2.5.6-pre1/include/asm-arm/io.h	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/include/asm-arm/io.h	Thu Feb 28 13:34:23 2002
@@ -31,9 +31,9 @@
  * Generic IO read/write.  These perform native-endian accesses.  Note
  * that some architectures will want to re-define __raw_{read,write}w.
  */
-extern void __raw_writesb(unsigned int addr, void *data, int bytelen);
-extern void __raw_writesw(unsigned int addr, void *data, int wordlen);
-extern void __raw_writesl(unsigned int addr, void *data, int longlen);
+extern void __raw_writesb(unsigned int addr, const void *data, int bytelen);
+extern void __raw_writesw(unsigned int addr, const void *data, int wordlen);
+extern void __raw_writesl(unsigned int addr, const void *data, int longlen);
 
 extern void __raw_readsb(unsigned int addr, void *data, int bytelen);
 extern void __raw_readsw(unsigned int addr, void *data, int wordlen);
diff -urN linux-2.5.6-pre1/include/asm-arm/irq.h linux-2.5.6-pre2/include/asm-arm/irq.h
--- linux-2.5.6-pre1/include/asm-arm/irq.h	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/include/asm-arm/irq.h	Thu Feb 28 13:34:23 2002
@@ -24,5 +24,19 @@
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
 
+#define __IRQT_FALEDGE	(1 << 0)
+#define __IRQT_RISEDGE	(1 << 1)
+#define __IRQT_LOWLVL	(1 << 2)
+#define __IRQT_HIGHLVL	(1 << 3)
+
+#define IRQT_NOEDGE	(0)
+#define IRQT_RISING	(__IRQT_RISEDGE)
+#define IRQT_FALLING	(__IRQT_FALEDGE)
+#define IRQT_BOTHEDGE	(__IRQT_RISEDGE|__IRQT_FALEDGE)
+#define IRQT_LOW	(__IRQT_LOWLVL)
+#define IRQT_HIGH	(__IRQT_HIGHLVL)
+
+int set_irq_type(unsigned int irq, unsigned int type);
+
 #endif
 
diff -urN linux-2.5.6-pre1/include/asm-arm/mach/irq.h linux-2.5.6-pre2/include/asm-arm/mach/irq.h
--- linux-2.5.6-pre1/include/asm-arm/mach/irq.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/include/asm-arm/mach/irq.h	Thu Feb 28 13:34:23 2002
@@ -10,32 +10,110 @@
 #ifndef __ASM_ARM_MACH_IRQ_H
 #define __ASM_ARM_MACH_IRQ_H
 
+struct irqdesc;
+struct pt_regs;
+struct seq_file;
+
+typedef void (*irq_handler_t)(unsigned int, struct irqdesc *, struct pt_regs *);
+typedef void (*irq_control_t)(unsigned int);
+
+struct irqchip {
+	/*
+	 * Acknowledge the IRQ.
+	 * If this is a level-based IRQ, then it is expected to mask the IRQ
+	 * as well.
+	 */
+	void (*ack)(unsigned int);
+	/*
+	 * Mask the IRQ in hardware.
+	 */
+	void (*mask)(unsigned int);
+	/*
+	 * Unmask the IRQ in hardware.
+	 */
+	void (*unmask)(unsigned int);
+	/*
+	 * Re-run the IRQ
+	 */
+	void (*rerun)(unsigned int);
+	/*
+	 * Set the type of the IRQ.
+	 */
+	int (*type)(unsigned int, unsigned int);
+};
+
 struct irqdesc {
-	unsigned int	 nomask   : 1;		/* IRQ does not mask in IRQ   */
-	unsigned int	 enabled  : 1;		/* IRQ is currently enabled   */
-	unsigned int	 triggered: 1;		/* IRQ has occurred	      */
-	unsigned int	 probing  : 1;		/* IRQ in use for a probe     */
-	unsigned int	 probe_ok : 1;		/* IRQ can be used for probe  */
-	unsigned int	 valid    : 1;		/* IRQ claimable	      */
-	unsigned int	 noautoenable : 1;	/* don't automatically enable IRQ */
-	unsigned int	 unused   :25;
-	void (*mask_ack)(unsigned int irq);	/* Mask and acknowledge IRQ   */
-	void (*mask)(unsigned int irq);		/* Mask IRQ		      */
-	void (*unmask)(unsigned int irq);	/* Unmask IRQ		      */
+	irq_handler_t	handle;
+	struct irqchip	*chip;
 	struct irqaction *action;
+
+	unsigned int	enabled  : 1;		/* IRQ is currently enabled   */
+	unsigned int	triggered: 1;		/* IRQ has occurred	      */
+	unsigned int	running  : 1;		/* IRQ is running             */
+	unsigned int	pending  : 1;		/* IRQ is pending	      */
+	unsigned int	probing  : 1;		/* IRQ in use for a probe     */
+	unsigned int	probe_ok : 1;		/* IRQ can be used for probe  */
+	unsigned int	valid    : 1;		/* IRQ claimable	      */
+	unsigned int	noautoenable : 1;	/* don't automatically enable IRQ */
+	unsigned int	unused   :23;
+	unsigned int	depth;			/* disable depth	      */
+
 	/*
 	 * IRQ lock detection
 	 */
-	unsigned int	 lck_cnt;
-	unsigned int	 lck_pc;
-	unsigned int	 lck_jif;
+	unsigned int	lck_cnt;
+	unsigned int	lck_pc;
+	unsigned int	lck_jif;
 };
 
 extern struct irqdesc irq_desc[];
 
+/*
+ * This is internal.  Do not use it.
+ */
 extern void (*init_arch_irq)(void);
-extern int setup_arm_irq(int, struct irqaction *);
-extern int show_fiq_list(struct seq_file *, void *);
 extern void init_FIQ(void);
+extern int show_fiq_list(struct seq_file *, void *);
+void __set_irq_handler(unsigned int irq, irq_handler_t, int);
+int setup_irq(unsigned int, struct irqaction *);
+
+/*
+ * External stuff.
+ */
+#define set_irq_handler(irq,handler)		__set_irq_handler(irq,handler,0)
+#define set_irq_chained_handler(irq,handler)	__set_irq_handler(irq,handler,1)
+
+void set_irq_chip(unsigned int irq, struct irqchip *);
+void set_irq_flags(unsigned int irq, unsigned int flags);
+
+#ifdef not_yet
+/*
+ * This is to be used by the top-level machine IRQ decoder only.
+ */
+static inline void call_irq(struct pt_regs *regs, unsigned int irq)
+{
+	struct irqdesc *desc = irq_desc + irq;
+
+	spin_lock(&irq_controller_lock);
+	desc->handle(irq, desc, regs);
+	spin_unlock(&irq_controller_lock);
+
+	if (softirq_pending(smp_processor_id()))
+		do_softirq();
+}
+#endif
+
+#define IRQF_VALID	(1 << 0)
+#define IRQF_PROBE	(1 << 1)
+#define IRQF_NOAUTOEN	(1 << 2)
+
+/*
+ * Built-in IRQ handlers.
+ */
+void do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs);
+void do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs);
+void do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs);
+void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs);
+void dummy_mask_unmask_irq(unsigned int irq);
 
 #endif
diff -urN linux-2.5.6-pre1/include/asm-arm/mmu.h linux-2.5.6-pre2/include/asm-arm/mmu.h
--- linux-2.5.6-pre1/include/asm-arm/mmu.h	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/include/asm-arm/mmu.h	Thu Feb 28 13:34:23 2002
@@ -1,7 +1,9 @@
 #ifndef __ARM_MMU_H
 #define __ARM_MMU_H
 
-/* The ARM doesn't have a mmu context */
+/*
+ * The ARM doesn't have a mmu context
+ */
 typedef struct { } mm_context_t;
 
 #endif
diff -urN linux-2.5.6-pre1/include/asm-arm/mmu_context.h linux-2.5.6-pre2/include/asm-arm/mmu_context.h
--- linux-2.5.6-pre1/include/asm-arm/mmu_context.h	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/include/asm-arm/mmu_context.h	Thu Feb 28 13:34:23 2002
@@ -49,27 +49,4 @@
 #define activate_mm(prev, next) \
 	switch_mm((prev),(next),NULL,smp_processor_id())
 
-/*
- * Find first bit set in a 168-bit bitmap, where the first
- * 128 bits are unlikely to be set.
- */
-static inline int sched_find_first_bit(unsigned long *b)
-{
-#if MAX_RT_PRIO != 128 || MAX_PRIO != 168
-#error update this function
-#endif
-
-	if (unlikely(b[0]))
-		return __ffs(b[0]);
-	if (unlikely(b[1]))
-		return __ffs(b[1]) + 32;
-	if (unlikely(b[2]))
-		return __ffs(b[2]) + 64;
-	if (unlikely(b[3]))
-		return __ffs(b[3]) + 96;
-	if (b[4])
-		return __ffs(b[4]) + MAX_RT_PRIO;
-	return __ffs(b[5]) + 32 + MAX_RT_PRIO;
-}
-
 #endif
diff -urN linux-2.5.6-pre1/include/asm-arm/page.h linux-2.5.6-pre2/include/asm-arm/page.h
--- linux-2.5.6-pre1/include/asm-arm/page.h	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/include/asm-arm/page.h	Thu Feb 28 13:34:23 2002
@@ -14,8 +14,19 @@
 #define clear_page(page)	memzero((void *)(page), PAGE_SIZE)
 extern void copy_page(void *to, void *from);
 
-#define clear_user_page(page, vaddr)	cpu_clear_user_page(page,vaddr)
-#define copy_user_page(to, from, vaddr)	cpu_copy_user_page(to,from,vaddr)
+#define clear_user_page(addr,vaddr)			\
+	do {						\
+		preempt_disable();			\
+		cpu_clear_user_page(addr, vaddr);	\
+		preempt_enable();			\
+	} while (0)
+
+#define copy_user_page(to,from,vaddr)			\
+	do {						\
+		preempt_disable();			\
+		cpu_copy_user_page(to, from, vaddr);	\
+		preempt_enable();			\
+	} while (0)
 
 #ifdef STRICT_MM_TYPECHECKS
 /*
diff -urN linux-2.5.6-pre1/include/asm-arm/pci.h linux-2.5.6-pre2/include/asm-arm/pci.h
--- linux-2.5.6-pre1/include/asm-arm/pci.h	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/include/asm-arm/pci.h	Thu Feb 28 13:34:23 2002
@@ -2,7 +2,7 @@
 #define ASMARM_PCI_H
 
 #ifdef __KERNEL__
-
+#include <linux/config.h>
 #include <linux/mm.h> /* bah! */
 
 #include <asm/arch/hardware.h>
@@ -142,18 +142,9 @@
 
 	for (i = 0; i < nents; i++, sg++) {
 		char *virt;
-		if (sg->address && sg->page)
-			BUG();
-		else if (!sg->address && !sg->page)
-			BUG();
-
-		if (sg->address) {
-			sg->dma_address = virt_to_bus(sg->address);
-			virt = sg->address;
-		} else {
-			sg->dma_address = page_to_bus(sg->page) + sg->offset;
-			virt = page_address(sg->page) + sg->offset;
-		}
+
+		sg->dma_address = page_to_bus(sg->page) + sg->offset;
+		virt = page_address(sg->page) + sg->offset;
 		consistent_sync(virt, sg->length, direction);
 	}
 
@@ -197,12 +188,7 @@
 	int i;
 
 	for (i = 0; i < nelems; i++, sg++) {
-		char *virt;
-
-		if (sg->address)
-			virt = sg->address;
-		else
-			virt = page_address(sg->page) + sg->offset;
+		char *virt = page_address(sg->page) + sg->offset;
 		consistent_sync(virt, sg->length, direction);
 	}
 }
diff -urN linux-2.5.6-pre1/include/asm-arm/proc-armv/cache.h linux-2.5.6-pre2/include/asm-arm/proc-armv/cache.h
--- linux-2.5.6-pre1/include/asm-arm/proc-armv/cache.h	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6-pre2/include/asm-arm/proc-armv/cache.h	Thu Feb 28 13:34:23 2002
@@ -8,6 +8,7 @@
  * published by the Free Software Foundation.
  */
 #include <asm/mman.h>
+#include <asm/glue.h>
 
 /*
  * This flag is used to indicate that the page pointed to by a pte
@@ -200,69 +201,93 @@
 	} while (0)
 
 /*
- * Old ARM MEMC stuff.  This supports the reversed mapping handling that
- * we have on the older 26-bit machines.  We don't have a MEMC chip, so...
- */
-#define memc_update_all()		do { } while (0)
-#define memc_update_mm(mm)		do { } while (0)
-#define memc_update_addr(mm,pte,log)	do { } while (0)
-#define memc_clear(mm,physaddr)		do { } while (0)
-
-/*
- * TLB flushing.
+ *	TLB Management
+ *	==============
+ *
+ *	The arch/arm/mm/tlb-*.S files implement this methods.
+ *
+ *	The TLB specific code is expected to perform whatever tests it
+ *	needs to determine if it should invalidate the TLB for each
+ *	call.  Start addresses are inclusive and end addresses are
+ *	exclusive; it is safe to round these addresses down.
+ *
+ *	flush_tlb_all()
+ *
+ *		Invalidate the entire TLB.
  *
- *  - flush_tlb_all()			flushes all processes TLBs
- *  - flush_tlb_mm(mm)			flushes the specified mm context TLB's
- *  - flush_tlb_page(vma, vmaddr)	flushes TLB for specified page
- *  - flush_tlb_range(vma, start, end)	flushes TLB for specified range of pages
+ *	flush_tlb_mm(mm)
  *
- * We drain the write buffer in here to ensure that the page tables in ram
- * are really up to date.  It is more efficient to do this here...
+ *		Invalidate all TLB entries in a particular address
+ *		space.
+ *		- mm	- mm_struct describing address space
+ *
+ *	flush_tlb_range(mm,start,end)
+ *
+ *		Invalidate a range of TLB entries in the specified
+ *		address space.
+ *		- mm	- mm_struct describing address space
+ *		- start - start address (may not be aligned)
+ *		- end	- end address (exclusive, may not be aligned)
+ *
+ *	flush_tlb_page(vaddr,vma)
+ *
+ *		Invalidate the specified page in the specified address range.
+ *		- vaddr - virtual address (may not be aligned)
+ *		- vma	- vma_struct describing address range
+ *
+ *	flush_kern_tlb_page(kaddr)
+ *
+ *		Invalidate the TLB entry for the specified page.  The address
+ *		will be in the kernels virtual memory space.  Current uses
+ *		only require the D-TLB to be invalidated.
+ *		- kaddr - Kernel virtual memory address
  */
 
-/*
- * Notes:
- *  current->active_mm is the currently active memory description.
- *  current->mm == NULL iff we are lazy.
- */
-#define flush_tlb_all()							\
-	do {								\
-		cpu_tlb_invalidate_all();				\
-	} while (0)
+struct cpu_tlb_fns {
+	void (*flush_kern_all)(void);
+	void (*flush_user_mm)(struct mm_struct *);
+	void (*flush_user_range)(unsigned long, unsigned long, struct vm_area_struct *);
+	void (*flush_user_page)(unsigned long, struct vm_area_struct *);
+	void (*flush_kern_page)(unsigned long);
+};
 
 /*
- * Flush all user virtual address space translations described by `_mm'.
- *
- * Currently, this is always called for current->mm, which should be
- * the same as current->active_mm.  This is currently not be called for
- * the lazy TLB case.
+ * Convert calls to our calling convention.
  */
-#define flush_tlb_mm(_mm)						\
-	do {								\
-		if ((_mm) == current->active_mm)			\
-			cpu_tlb_invalidate_all();			\
-	} while (0)
+#define flush_tlb_all()			__cpu_flush_kern_tlb_all()
+#define flush_tlb_mm(mm)		__cpu_flush_user_tlb_mm(mm)
+#define flush_tlb_range(vma,start,end)	__cpu_flush_user_tlb_range(start,end,vma)
+#define flush_tlb_page(vma,vaddr)	__cpu_flush_user_tlb_page(vaddr,vma)
+#define flush_kern_tlb_page(kaddr)	__cpu_flush_kern_tlb_page(kaddr)
 
 /*
- * Flush the specified range of user virtual address space translations.
- *
- * _mm may not be current->active_mm, but may not be NULL.
+ * Now select the calling method
  */
-#define flush_tlb_range(_vma,_start,_end)				\
-	do {								\
-		if ((_mm)->vm_mm == current->active_mm)			\
-			cpu_tlb_invalidate_range((_start), (_end));	\
-	} while (0)
+#ifdef MULTI_TLB
 
-/*
- * Flush the specified user virtual address space translation.
- */
-#define flush_tlb_page(_vma,_page)					\
-	do {								\
-		if ((_vma)->vm_mm == current->active_mm)		\
-			cpu_tlb_invalidate_page((_page),		\
-				 ((_vma)->vm_flags & VM_EXEC));		\
-	} while (0)
+extern struct cpu_tlb_fns cpu_tlb;
+
+#define __cpu_flush_kern_tlb_all	cpu_tlb.flush_kern_all
+#define __cpu_flush_user_tlb_mm		cpu_tlb.flush_user_mm
+#define __cpu_flush_user_tlb_range	cpu_tlb.flush_user_range
+#define __cpu_flush_user_tlb_page	cpu_tlb.flush_user_page
+#define __cpu_flush_kern_tlb_page	cpu_tlb.flush_kern_page
+
+#else
+
+#define __cpu_flush_kern_tlb_all	__glue(_TLB,_flush_kern_tlb_all)
+#define __cpu_flush_user_tlb_mm		__glue(_TLB,_flush_user_tlb_mm)
+#define __cpu_flush_user_tlb_range	__glue(_TLB,_flush_user_tlb_range)
+#define __cpu_flush_user_tlb_page	__glue(_TLB,_flush_user_tlb_page)
+#define __cpu_flush_kern_tlb_page	__glue(_TLB,_flush_kern_tlb_page)
+
+extern void __cpu_flush_kern_tlb_all(void);
+extern void __cpu_flush_user_tlb_mm(struct mm_struct *);
+extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
+extern void __cpu_flush_user_tlb_page(unsigned long, struct vm_area_struct *);
+extern void __cpu_flush_kern_tlb_page(unsigned long);
+
+#endif
 
 /*
  * if PG_dcache_dirty is set for the page, we need to ensure that any
@@ -270,3 +295,12 @@
  * back to the page.
  */
 extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte);
+
+/*
+ * Old ARM MEMC stuff.  This supports the reversed mapping handling that
+ * we have on the older 26-bit machines.  We don't have a MEMC chip, so...
+ */
+#define memc_update_all()		do { } while (0)
+#define memc_update_mm(mm)		do { } while (0)
+#define memc_update_addr(mm,pte,log)	do { } while (0)
+#define memc_clear(mm,physaddr)		do { } while (0)
diff -urN linux-2.5.6-pre1/include/asm-arm/procinfo.h linux-2.5.6-pre2/include/asm-arm/procinfo.h
--- linux-2.5.6-pre1/include/asm-arm/procinfo.h	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/include/asm-arm/procinfo.h	Thu Feb 28 13:34:23 2002
@@ -14,6 +14,9 @@
 
 #include <asm/proc-fns.h>
 
+struct cpu_tlb_fns;
+struct processor;
+
 struct proc_info_item {
 	const char	 *manufacturer;
 	const char	 *cpu_name;
@@ -37,15 +40,14 @@
 	const char	 *elf_name;
 	unsigned int	 elf_hwcap;
 	struct proc_info_item *info;
-#ifdef MULTI_CPU
 	struct processor *proc;
-#else
-	void		 *unused;
-#endif
+	struct cpu_tlb_fns *tlb;
 };
 
 #endif	/* __ASSEMBLY__ */
 
+#define PROC_INFO_SZ	40
+
 #define HWCAP_SWP	 1
 #define HWCAP_HALF	 2
 #define HWCAP_THUMB	 4
diff -urN linux-2.5.6-pre1/include/asm-arm/system.h linux-2.5.6-pre2/include/asm-arm/system.h
--- linux-2.5.6-pre1/include/asm-arm/system.h	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/include/asm-arm/system.h	Thu Feb 28 13:34:23 2002
@@ -53,9 +53,9 @@
 struct thread_info;
 extern struct task_struct *__switch_to(struct thread_info *, struct thread_info *);
 
-#define switch_to(prev,next,last)					\
+#define switch_to(prev,next)						\
 	do {			 					\
-		last = __switch_to(prev->thread_info,next->thread_info); \
+		__switch_to(prev->thread_info,next->thread_info);	\
 		mb();							\
 	} while (0)
 
diff -urN linux-2.5.6-pre1/include/asm-x86_64/bitops.h linux-2.5.6-pre2/include/asm-x86_64/bitops.h
--- linux-2.5.6-pre1/include/asm-x86_64/bitops.h	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/include/asm-x86_64/bitops.h	Thu Feb 28 13:34:23 2002
@@ -413,6 +413,16 @@
 
 #ifdef __KERNEL__
 
+static inline int sched_find_first_bit(unsigned long *b)
+{
+	if (b[0])
+		return __ffs(b[0]);
+	if (b[1])
+		return __ffs(b[1]) + 64;
+	if (b[2])
+		return __ffs(b[2]) + 128;
+}
+
 /**
  * ffs - find first bit set
  * @x: the word to search
diff -urN linux-2.5.6-pre1/include/asm-x86_64/mmu_context.h linux-2.5.6-pre2/include/asm-x86_64/mmu_context.h
--- linux-2.5.6-pre1/include/asm-x86_64/mmu_context.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/include/asm-x86_64/mmu_context.h	Thu Feb 28 13:34:23 2002
@@ -7,33 +7,6 @@
 #include <asm/pgalloc.h>
 
 /*
- * Every architecture must define this function. It's the fastest
- * way of searching a 168-bit bitmap where the first 128 bits are
- * unlikely to be set. It's guaranteed that at least one of the 168
- * bits is cleared.
- */
-#if MAX_RT_PRIO != 128 || MAX_PRIO != 168
-# error update this function.
-#endif
-
-static inline int __sched_find_first_bit(unsigned long *b)
-{
-	if (b[0])
-		return __ffs(b[0]);
-	if (b[1])
-		return __ffs(b[1]) + 64;
-	if (b[2])
-		return __ffs(b[2]) + 128;
-}
-
-static inline int sched_find_first_bit(unsigned long *b)
-{ 
-	int n = __sched_find_first_bit(b);
-	BUG_ON((unsigned)n > 167);
-	return n; 
-} 
-
-/*
  * possibly do the LDT unload here?
  */
 #define destroy_context(mm)		do { } while(0)
diff -urN linux-2.5.6-pre1/include/asm-x86_64/page.h linux-2.5.6-pre2/include/asm-x86_64/page.h
--- linux-2.5.6-pre1/include/asm-x86_64/page.h	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/include/asm-x86_64/page.h	Thu Feb 28 13:34:23 2002
@@ -112,6 +112,8 @@
 #define virt_to_page(kaddr)	(mem_map + (__pa(kaddr) >> PAGE_SHIFT))
 #define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
 
+#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
+                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #endif /* __KERNEL__ */
 
diff -urN linux-2.5.6-pre1/include/asm-x86_64/pda.h linux-2.5.6-pre2/include/asm-x86_64/pda.h
--- linux-2.5.6-pre1/include/asm-x86_64/pda.h	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/include/asm-x86_64/pda.h	Thu Feb 28 13:34:23 2002
@@ -19,11 +19,6 @@
 	struct task_struct *pcurrent;	/* Current process */
         int irqcount;		    /* Irq nesting counter. Starts with -1 */  	
 	int cpunumber;		    /* Logical CPU number */
-	/* XXX: could be a single list */
-	unsigned long *pgd_quick;
-	unsigned long *pmd_quick;
-	unsigned long *pte_quick;
-	unsigned long pgtable_cache_sz;
 	char *irqstackptr;	  
 	unsigned int __softirq_pending;
 	unsigned int __local_irq_count;
diff -urN linux-2.5.6-pre1/include/asm-x86_64/pgalloc.h linux-2.5.6-pre2/include/asm-x86_64/pgalloc.h
--- linux-2.5.6-pre1/include/asm-x86_64/pgalloc.h	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/include/asm-x86_64/pgalloc.h	Thu Feb 28 13:34:23 2002
@@ -8,173 +8,74 @@
 #include <linux/threads.h>
 #include <linux/mm.h>
 
-#define inc_pgcache_size() add_pda(pgtable_cache_sz,1UL)
-#define dec_pgcache_size() sub_pda(pgtable_cache_sz,1UL)
-
-#define pmd_populate(mm, pmd, pte) \
+#define pmd_populate_kernel(mm, pmd, pte) \
 		set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte)))
 #define pgd_populate(mm, pgd, pmd) \
 		set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pmd)))
 
-extern __inline__ pmd_t *get_pmd_slow(void)
+static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte)
 {
-	pmd_t *ret = (pmd_t *)__get_free_page(GFP_KERNEL);
-
-	if (ret)
-		memset(ret, 0, PAGE_SIZE);
-	return ret;
-}
-
-extern __inline__ pmd_t *get_pmd_fast(void)
-{
-	unsigned long *ret;
-
-	preempt_disable(); 
-	ret = read_pda(pmd_quick);
-	if (ret) {
-		write_pda(pmd_quick, (unsigned long *)(*ret));
-		ret[0] = 0;
-		dec_pgcache_size();
-	}
-	preempt_enable(); 
-	if (!ret)
-		ret = (unsigned long *)get_pmd_slow();
-	return (pmd_t *)ret;
+	set_pmd(pmd, __pmd(_PAGE_TABLE | 
+			   ((u64)(pte - mem_map) << PAGE_SHIFT))); 
 }
 
-extern __inline__ void pmd_free(pmd_t *pmd)
+extern __inline__ pmd_t *get_pmd(void)
 {
-	preempt_disable(); 
-	*(unsigned long *)pmd = (unsigned long) read_pda(pmd_quick);
-	write_pda(pmd_quick,(unsigned long *) pmd);
-	inc_pgcache_size();
-	preempt_enable(); 
+	return (pmd_t *)get_zeroed_page(GFP_KERNEL);
 }
 
-extern __inline__ void pmd_free_slow(pmd_t *pmd)
+extern __inline__ void pmd_free(pmd_t *pmd)
 {
 	if ((unsigned long)pmd & (PAGE_SIZE-1)) 
 		BUG(); 
 	free_page((unsigned long)pmd);
 }
 
-static inline pmd_t *pmd_alloc_one_fast (struct mm_struct *mm, unsigned long addr)
-{
-	unsigned long *ret;
-
-	preempt_disable(); 
-	ret = (unsigned long *)read_pda(pmd_quick);
-
-	if (__builtin_expect(ret != NULL, 1)) {
-		write_pda(pmd_quick, (unsigned long *)(*ret));
-		ret[0] = 0;
-		dec_pgcache_size();
-	}
-	preempt_enable(); 
-	return (pmd_t *)ret;
-}
-
 static inline pmd_t *pmd_alloc_one (struct mm_struct *mm, unsigned long addr)
 {
-	pmd_t *pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
-
-	if (__builtin_expect(pmd != NULL, 1))
-		clear_page(pmd);
-	return pmd;
-}
-
-
-static inline pgd_t *pgd_alloc_one_fast (void)
-{
-	unsigned long *ret;
-
-	preempt_disable(); 
-	ret = read_pda(pgd_quick);
-	if (likely(ret != NULL)) {
-		write_pda(pgd_quick,(unsigned long *)(*ret));
-		ret[0] = 0;
-		dec_pgcache_size();
-	}
-	preempt_enable(); 
-	return (pgd_t *) ret;
+	return (pmd_t *) get_zeroed_page(GFP_KERNEL); 
 }
 
 static inline pgd_t *pgd_alloc (struct mm_struct *mm)
 {
-	/* the VM system never calls pgd_alloc_one_fast(), so we do it here. */
-	pgd_t *pgd = pgd_alloc_one_fast();
-
-	if (pgd == NULL) {
-		pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
-		if (__builtin_expect(pgd != NULL, 1))
-			clear_page(pgd);
-	}
-	return pgd;
+	return (pgd_t *)get_zeroed_page(GFP_KERNEL);
 }
 
 static inline void pgd_free (pgd_t *pgd)
 {
-	preempt_disable();
-	*(unsigned long *)pgd = (unsigned long) read_pda(pgd_quick);
-	write_pda(pgd_quick,(unsigned long *) pgd);
-	inc_pgcache_size();
-	preempt_enable();
-}
-
-
-static inline void pgd_free_slow (pgd_t *pgd)
-{
 	if ((unsigned long)pgd & (PAGE_SIZE-1)) 
 		BUG(); 
 	free_page((unsigned long)pgd);
 }
 
-
-static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
-	pte_t *pte;
-
-	pte = (pte_t *) __get_free_page(GFP_KERNEL);
-	if (pte)
-		clear_page(pte);
-	return pte;
+	return (pte_t *) get_zeroed_page(GFP_KERNEL);
 }
 
-extern __inline__ pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-	unsigned long *ret;
-
-	preempt_disable(); 
-	if(__builtin_expect((ret = read_pda(pte_quick)) != NULL, !0)) {  
-		write_pda(pte_quick, (unsigned long *)(*ret));
-		ret[0] = ret[1];
-		dec_pgcache_size();
-	}
-	preempt_enable(); 
-	return (pte_t *)ret;
+	void *p = (void *)get_zeroed_page(GFP_KERNEL); 
+	if (!p)
+		return NULL;
+	return virt_to_page(p);
 }
 
-/* Should really implement gc for free page table pages. This could be done with 
-   a reference count in struct page. */
+/* Should really implement gc for free page table pages. This could be
+   done with a reference count in struct page. */
 
-extern __inline__ void pte_free(pte_t *pte)
-{	
-	preempt_disable();
-	*(unsigned long *)pte = (unsigned long) read_pda(pte_quick);
-	write_pda(pte_quick, (unsigned long *) pte); 
-	inc_pgcache_size();
-	preempt_enable();
-}
-
-extern __inline__ void pte_free_slow(pte_t *pte)
+extern __inline__ void pte_free_kernel(pte_t *pte)
 {
 	if ((unsigned long)pte & (PAGE_SIZE-1))
 		BUG();
 	free_page((unsigned long)pte); 
 }
 
+extern inline void pte_free(struct page *pte)
+{
+	__free_page(pte);
+} 
 
-extern int do_check_pgt_cache(int, int);
 
 /*
  * TLB flushing:
diff -urN linux-2.5.6-pre1/include/asm-x86_64/pgtable.h linux-2.5.6-pre2/include/asm-x86_64/pgtable.h
--- linux-2.5.6-pre1/include/asm-x86_64/pgtable.h	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/include/asm-x86_64/pgtable.h	Thu Feb 28 13:34:23 2002
@@ -26,7 +26,7 @@
 extern pmd_t level2_kernel_pgt[512];
 extern void paging_init(void);
 
-/* Caches aren't brain-dead on the intel. */
+/* Caches aren't brain-dead. */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(vma, start, end)	do { } while (0)
@@ -35,6 +35,7 @@
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_icache_range(start, end)		do { } while (0)
 #define flush_icache_page(vma,pg)		do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)       do { } while (0)
 
 #define __flush_tlb()							\
 	do {								\
@@ -341,8 +342,10 @@
 
 #define page_pte(page) page_pte_prot(page, __pgprot(0))
 
-#define pmd_page(pmd) \
+#define pmd_page_kernel(pmd) \
 ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+#define pmd_page(pmd) \
+       (mem_map + (pmd_val(pmd) >> PAGE_SHIFT))
 
 /* to find an entry in a page-table-directory. */
 #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
@@ -360,9 +363,15 @@
 /* Find an entry in the third-level page table.. */
 #define __pte_offset(address) \
 		((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
-#define pte_offset(dir, address) ((pte_t *) pmd_page(*(dir)) + \
+#define pte_offset_kernel(dir, address) ((pte_t *) pmd_page_kernel(*(dir)) + \
 			__pte_offset(address))
 
+#define pte_offset_map(dir,address) pte_offset_kernel(dir,address)
+#define pte_offset_map_nested(dir,address) pte_offset_kernel(dir,address)
+#define pte_unmap(pte) /* NOP */
+#define pte_unmap_nested(pte) /* NOP */ 
+
+
 /* never use these in the common code */
 #define level4_page(level4) ((unsigned long) __va(level4_val(level4) & PAGE_MASK))
 #define level4_index(address) ((address >> LEVEL4_SHIFT) & (PTRS_PER_LEVEL4-1))
diff -urN linux-2.5.6-pre1/include/asm-x86_64/system.h linux-2.5.6-pre2/include/asm-x86_64/system.h
--- linux-2.5.6-pre1/include/asm-x86_64/system.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/include/asm-x86_64/system.h	Thu Feb 28 13:34:23 2002
@@ -18,7 +18,7 @@
 
 #define prepare_to_switch()	do { } while(0)
 
-#define switch_to(prev,next,last) do {					\
+#define switch_to(prev,next) do {					\
 	asm volatile("pushq %%rbp\n\t"					\
 		     "pushq %%rbx\n\t"					\
 		     "pushq %%r8\n\t"					\
@@ -30,10 +30,10 @@
 		     "pushq %%r14\n\t"					\
 		     "pushq %%r15\n\t"					\
 		     "movq %%rsp,%0\n\t"	/* save RSP */		\
-		     "movq %3,%%rsp\n\t"	/* restore RSP */	\
+		     "movq %2,%%rsp\n\t"	/* restore RSP */	\
 		     "leaq 1f(%%rip),%%rbp\n\t"				\
 		     "movq %%rbp,%1\n\t"	/* save RIP */		\
-		     "pushq %4\n\t"		/* setup new RIP */	\
+		     "pushq %3\n\t"		/* setup new RIP */	\
 		     "jmp __switch_to\n\t"		\
 		     "1:\t"		\
 		     "popq %%r15\n\t"				\
@@ -46,8 +46,7 @@
 		     "popq %%r8\n\t"					\
 		     "popq %%rbx\n\t"					\
 		     "popq %%rbp\n\t"					\
-		     :"=m" (prev->thread.rsp),"=m" (prev->thread.rip),	\
-		      "=b" (last)					\
+		     :"=m" (prev->thread.rsp),"=m" (prev->thread.rip)	\
 		     :"m" (next->thread.rsp),"m" (next->thread.rip),	\
 		      "b" (prev), "S" (next), "D" (prev));		\
 } while (0)
diff -urN linux-2.5.6-pre1/include/linux/blk.h linux-2.5.6-pre2/include/linux/blk.h
--- linux-2.5.6-pre1/include/linux/blk.h	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/include/linux/blk.h	Thu Feb 28 13:34:23 2002
@@ -8,11 +8,6 @@
 #include <linux/spinlock.h>
 #include <linux/compiler.h>
 
-/*
- * get rid of this next...
- */
-extern int ide_init(void);
-
 extern void set_device_ro(kdev_t dev,int flag);
 extern void add_blkdev_randomness(int major);
 
diff -urN linux-2.5.6-pre1/include/linux/fs.h linux-2.5.6-pre2/include/linux/fs.h
--- linux-2.5.6-pre1/include/linux/fs.h	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/include/linux/fs.h	Thu Feb 28 13:34:24 2002
@@ -1212,12 +1212,12 @@
 #define destroy_buffers(dev)	__invalidate_buffers((dev), 1)
 extern void invalidate_bdev(struct block_device *, int);
 extern void __invalidate_buffers(kdev_t dev, int);
-extern void sync_inodes(kdev_t);
+extern void sync_inodes(void);
 extern void sync_unlocked_inodes(void);
 extern void write_inode_now(struct inode *, int);
-extern int sync_buffers(kdev_t, int);
-extern void sync_dev(kdev_t);
+extern int sync_buffers(struct block_device *, int);
 extern int fsync_dev(kdev_t);
+extern int fsync_bdev(struct block_device *);
 extern int fsync_super(struct super_block *);
 extern int fsync_no_super(struct block_device *);
 extern void sync_inodes_sb(struct super_block *);
@@ -1234,7 +1234,7 @@
 extern int inode_has_buffers(struct inode *);
 extern int filemap_fdatasync(struct address_space *);
 extern int filemap_fdatawait(struct address_space *);
-extern void sync_supers(kdev_t);
+extern void sync_supers(void);
 extern int bmap(struct inode *, int);
 extern int notify_change(struct dentry *, struct iattr *);
 extern int permission(struct inode *, int);
diff -urN linux-2.5.6-pre1/include/linux/ide.h linux-2.5.6-pre2/include/linux/ide.h
--- linux-2.5.6-pre1/include/linux/ide.h	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6-pre2/include/linux/ide.h	Thu Feb 28 13:34:24 2002
@@ -1,9 +1,7 @@
 #ifndef _IDE_H
 #define _IDE_H
 /*
- *  linux/include/linux/ide.h
- *
- *  Copyright (C) 1994-1998  Linus Torvalds & authors
+ *  Copyright (C) 1994-2002  Linus Torvalds & authors
  */
 
 #include <linux/config.h>
@@ -13,6 +11,7 @@
 #include <linux/hdsmart.h>
 #include <linux/blkdev.h>
 #include <linux/proc_fs.h>
+#include <linux/device.h>
 #include <linux/devfs_fs_kernel.h>
 #include <asm/hdreg.h>
 
@@ -349,12 +348,13 @@
  * Now for the data we need to maintain per-drive:  ide_drive_t
  */
 
-#define ide_scsi	0x21
-#define ide_disk	0x20
-#define ide_optical	0x7
-#define ide_cdrom	0x5
-#define ide_tape	0x1
-#define ide_floppy	0x0
+#define ATA_DISK        0x20
+#define ATA_TAPE        0x01
+#define ATA_ROM         0x05	/* CD-ROM */
+#define ATA_MOD		0x07    /* optical */
+#define ATA_FLOPPY	0x00
+#define ATA_SCSI	0x21
+#define ATA_NO_LUN      0x7f
 
 typedef union {
 	unsigned all			: 8;	/* all of the bits together */
@@ -370,7 +370,14 @@
 struct ide_settings_s;
 
 typedef struct ide_drive_s {
-	request_queue_t		 queue;	/* request queue */
+	char type; /* distingiush different devices: disk, cdrom, tape, floppy, ... */
+
+	/* NOTE: If we had proper separation between channel and host chip, we
+	 * could move this to the chanell and many sync problems would
+	 * magically just go away.
+	 */
+	request_queue_t		 queue;	/* per device request queue */
+
 	struct ide_drive_s	*next;	/* circular list of hwgroup drives */
 	unsigned long sleep;		/* sleep until this time */
 	unsigned long service_start;	/* time we started last request */
@@ -405,7 +412,6 @@
 	unsigned ata_flash	: 1;	/* 1=present, 0=default */
 	unsigned	addressing;	/* : 2; 0=28-bit, 1=48-bit, 2=64-bit */
 	byte		scsi;		/* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
-	byte		media;		/* disk, cdrom, tape, floppy, ... */
 	select_t	select;		/* basic drive/head select reg value */
 	byte		ctl;		/* "normal" value for IDE_CONTROL_REG */
 	byte		ready_stat;	/* min status value for drive ready */
@@ -426,12 +432,12 @@
 	unsigned long	capacity;	/* total number of sectors */
 	unsigned long long capacity48;	/* total number of sectors */
 	unsigned int	drive_data;	/* for use by tuneproc/selectproc as needed */
-	struct hwif_s   *hwif;		/* actually (ide_hwif_t *) */
+	struct hwif_s   *hwif;		/* parent pointer to the interface we are attached to  */
 	wait_queue_head_t wqueue;	/* used to wait for drive in open() */
 	struct hd_driveid *id;		/* drive model identification info */
 	struct hd_struct  *part;	/* drive partition table */
 	char		name[4];	/* drive name, such as "hda" */
-	struct ide_driver_s *driver;	/* (ide_driver_t *) */
+	struct ata_operations *driver;
 	void		*driver_data;	/* extra driver data */
 	devfs_handle_t	de;		/* directory for device */
 	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
@@ -450,6 +456,7 @@
 	byte		acoustic;	/* acoustic management */
 	unsigned int	failures;	/* current failure count */
 	unsigned int	max_failures;	/* maximum allowed failure count */
+	struct device	device;		/* global device tree handle */
 } ide_drive_t;
 
 /*
@@ -519,16 +526,6 @@
  */
 typedef int (ide_busproc_t) (ide_drive_t *, int);
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
-typedef struct ide_pci_devid_s {
-	unsigned short	vid;
-	unsigned short	did;
-} ide_pci_devid_t;
-
-#define IDE_PCI_DEVID_NULL	((ide_pci_devid_t){0,0})
-#define IDE_PCI_DEVID_EQ(a,b)	(a.vid == b.vid && a.did == b.did)
-#endif /* CONFIG_BLK_DEV_IDEPCI */
-
 typedef struct hwif_s {
 	struct hwif_s	*next;		/* for linked-list in ide_hwgroup_t */
 	struct hwgroup_s *hwgroup;	/* actually (ide_hwgroup_t *) */
@@ -559,7 +556,7 @@
 	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
 	int		irq;		/* our irq number */
 	byte		major;		/* our major number */
-	char 		name[6];	/* name of interface, eg. "ide0" */
+	char 		name[80];	/* name of interface */
 	byte		index;		/* 0 for ide0; 1 for ide1; ... */
 	hwif_chipset_t	chipset;	/* sub-module for tuning.. */
 	unsigned	noprobe    : 1;	/* don't probe for this interface */
@@ -573,15 +570,14 @@
 	byte		channel;	/* for dual-port chips: 0=primary, 1=secondary */
 #ifdef CONFIG_BLK_DEV_IDEPCI
 	struct pci_dev	*pci_dev;	/* for pci chipsets */
-	ide_pci_devid_t	pci_devid;	/* for pci chipsets: {VID,DID} */
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 #if (DISK_RECOVERY_TIME > 0)
 	unsigned long	last_time;	/* time when previous rq was done */
 #endif
 	byte		straight8;	/* Alan's straight 8 check */
-	void		*hwif_data;	/* extra hwif data */
 	ide_busproc_t	*busproc;	/* driver soft-power interface */
 	byte		bus_state;	/* power state of the IDE bus */
+	struct device	device;		/* global device tree handle */
 } ide_hwif_t;
 
 /*
@@ -671,8 +667,6 @@
 #ifdef CONFIG_PROC_FS
 void proc_ide_create(void);
 void proc_ide_destroy(void);
-void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *);
-void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *);
 void destroy_proc_ide_drives(ide_hwif_t *);
 void create_proc_ide_interfaces(void);
 void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
@@ -700,37 +694,54 @@
 #endif
 
 /*
- * Subdrivers support.
+ * This structure describes the operations possible on a particular device type
+ * (CD-ROM, tape, DISK and so on).
+ *
+ * This is the main hook for device type support submodules.
  */
-typedef struct ide_driver_s {
-	const char			*name;
-	byte				media;
-	unsigned busy			: 1;
-	unsigned supports_dma		: 1;
-	unsigned supports_dsc_overlap	: 1;
+
+struct ata_operations {
+	struct module *owner;
+	unsigned busy: 1; /* FIXME: this will go soon away... */
 	int (*cleanup)(ide_drive_t *);
 	int (*standby)(ide_drive_t *);
 	int (*flushcache)(ide_drive_t *);
 	ide_startstop_t	(*do_request)(ide_drive_t *, struct request *, unsigned long);
 	int (*end_request)(ide_drive_t *drive, int uptodate);
+
 	int (*ioctl)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
 	int (*open)(struct inode *, struct file *, ide_drive_t *);
 	void (*release)(struct inode *, struct file *, ide_drive_t *);
 	int (*media_change)(ide_drive_t *);
 	void (*revalidate)(ide_drive_t *);
+
 	void (*pre_reset)(ide_drive_t *);
 	unsigned long (*capacity)(ide_drive_t *);
 	ide_startstop_t	(*special)(ide_drive_t *);
 	ide_proc_entry_t		*proc;
-	int (*driver_init)(void);
 	int (*driver_reinit)(ide_drive_t *);
+};
 
-	/* FIXME: Single linked list of drivers for iteration.
-	 */
-	struct ide_driver_s *next;
-} ide_driver_t;
+/* Alas, no aliases. Too much hassle with bringing module.h everywhere */
+#define ata_get(ata) \
+	(((ata) && (ata)->owner)	\
+		? ( try_inc_mod_count((ata)->owner) ? (ata) : NULL ) \
+		: (ata))
+
+#define ata_put(ata) \
+do {	\
+	if ((ata) && (ata)->owner) \
+		__MOD_DEC_USE_COUNT((ata)->owner);	\
+} while(0)
+
+
+/* FIXME: Actually implement and use them as soon as possible!  to make the
+ * ide_scan_devices() go away! */
 
-#define DRIVER(drive)		((drive)->driver)
+extern int unregister_ata_driver(unsigned int type, struct ata_operations *driver);
+extern int register_ata_driver(unsigned int type, struct ata_operations *driver);
+
+#define ata_ops(drive)		((drive)->driver)
 
 /*
  * ide_hwifs[] is the master data structure used to keep track
@@ -740,10 +751,7 @@
  * structure directly (the allocation/layout may change!).
  *
  */
-#ifndef _IDE_C
 extern struct hwif_s ide_hwifs[];		/* master data repository */
-extern struct ide_driver_s *ide_drivers;
-#endif
 extern int noautodma;
 
 /*
@@ -818,7 +826,7 @@
 /*
  * Revalidate (read partition tables)
  */
-void ide_revalidate_drive (ide_drive_t *drive);
+extern void ide_revalidate_drive (ide_drive_t *drive);
 
 /*
  * Start a reset operation for an IDE interface.
@@ -855,34 +863,6 @@
 #define task_rq_offset(rq) \
 	(((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE)
 
-extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
-{
-	return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
-}
-
-extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
-{
-	bio_kunmap_irq(buffer, flags);
-}
-
-/*
- * for now, taskfile requests are special :/
- */
-extern inline char *ide_map_rq(struct request *rq, unsigned long *flags)
-{
-	if (rq->bio)
-		return ide_map_buffer(rq, flags);
-	else
-		return rq->buffer + task_rq_offset(rq);
-}
-
-extern inline void ide_unmap_rq(struct request *rq, char *buf,
-				unsigned long *flags)
-{
-	if (rq->bio)
-		ide_unmap_buffer(buf, flags);
-}
-
 /*
  * This function issues a special IDE device request
  * onto the request queue.
@@ -959,7 +939,6 @@
 /*
  * Special Flagged Register Validation Caller
  */
-// ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task);
 
 ide_startstop_t set_multmode_intr (ide_drive_t *drive);
 ide_startstop_t set_geometry_intr (ide_drive_t *drive);
@@ -990,7 +969,6 @@
 #endif /* CONFIG_PKT_TASK_IOCTL */
 
 void ide_delay_50ms (void);
-int system_bus_clock(void);
 
 byte ide_auto_reduce_xfer (ide_drive_t *drive);
 int ide_driveid_update (ide_drive_t *drive);
@@ -999,13 +977,7 @@
 byte eighty_ninty_three (ide_drive_t *drive);
 int set_transfer (ide_drive_t *drive, ide_task_t *args);
 
-/*
- * ide_system_bus_speed() returns what we think is the system VESA/PCI
- * bus speed (in MHz).  This is used for calculating interface PIO timings.
- * The default is 40 for known PCI systems, 50 otherwise.
- * The "idebus=xx" parameter can be used to override this value.
- */
-int ide_system_bus_speed (void);
+extern int system_bus_speed;
 
 /*
  * idedisk_input_data() is a wrapper around ide_input_data() which copes
@@ -1037,47 +1009,33 @@
 void do_ide_request (request_queue_t * q);
 void ide_init_subdrivers (void);
 
-#ifndef _IDE_C
 extern struct block_device_operations ide_fops[];
 extern ide_proc_entry_t generic_subdriver_entries[];
-#endif
-
-int ide_reinit_drive (ide_drive_t *drive);
 
-#ifdef _IDE_C
-# ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_BLK_DEV_IDE
 /* Probe for devices attached to the systems host controllers.
  */
 extern int ideprobe_init (void);
-# endif
+#endif
 #ifdef CONFIG_BLK_DEV_IDEDISK
-int idedisk_reinit (ide_drive_t *drive);
-int idedisk_init (void);
-#endif /* CONFIG_BLK_DEV_IDEDISK */
+extern int idedisk_init (void);
+#endif
 #ifdef CONFIG_BLK_DEV_IDECD
-int ide_cdrom_reinit (ide_drive_t *drive);
-int ide_cdrom_init (void);
-#endif /* CONFIG_BLK_DEV_IDECD */
+extern int ide_cdrom_init (void);
+#endif
 #ifdef CONFIG_BLK_DEV_IDETAPE
-int idetape_reinit (ide_drive_t *drive);
-int idetape_init (void);
-#endif /* CONFIG_BLK_DEV_IDETAPE */
+extern int idetape_init (void);
+#endif
 #ifdef CONFIG_BLK_DEV_IDEFLOPPY
-int idefloppy_reinit (ide_drive_t *drive);
-int idefloppy_init (void);
-#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
+extern int idefloppy_init (void);
+#endif
 #ifdef CONFIG_BLK_DEV_IDESCSI
-int idescsi_reinit (ide_drive_t *drive);
-int idescsi_init (void);
-#endif /* CONFIG_BLK_DEV_IDESCSI */
-#endif /* _IDE_C */
-
-extern int ide_register_module (struct ide_driver_s *d);
-extern void ide_unregister_module (struct ide_driver_s *d);
-ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n);
-extern int ide_register_subdriver(ide_drive_t *drive, ide_driver_t *driver);
+extern int idescsi_init (void);
+#endif
+
+ide_drive_t *ide_scan_devices (byte media, const char *name, struct ata_operations *driver, int n);
+extern int ide_register_subdriver(ide_drive_t *drive, struct ata_operations *driver);
 extern int ide_unregister_subdriver(ide_drive_t *drive);
-extern int ide_replace_subdriver(ide_drive_t *drive, const char *driver);
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
 #define ON_BOARD		1
@@ -1088,7 +1046,7 @@
 #  define OFF_BOARD		NEVER_BOARD
 #endif /* CONFIG_BLK_DEV_OFFBOARD */
 
-void ide_scan_pcibus (int scan_direction) __init;
+void __init ide_scan_pcibus(int scan_direction);
 #endif
 #ifdef CONFIG_BLK_DEV_IDEDMA
 #define BAD_DMA_DRIVE		0
@@ -1108,5 +1066,6 @@
 extern spinlock_t ide_lock;
 
 extern int drive_is_ready(ide_drive_t *drive);
+extern void revalidate_drives(void);
 
 #endif /* _IDE_H */
diff -urN linux-2.5.6-pre1/include/linux/intermezzo_fs.h linux-2.5.6-pre2/include/linux/intermezzo_fs.h
--- linux-2.5.6-pre1/include/linux/intermezzo_fs.h	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/include/linux/intermezzo_fs.h	Thu Feb 28 13:34:24 2002
@@ -68,7 +68,7 @@
 };
 
 /* super.c */
-struct presto_cache *presto_find_cache(kdev_t dev) ;
+struct presto_cache *presto_find_cache(struct super_block *sb) ;
 extern struct file_system_type presto_fs_type;
 extern int init_intermezzo_fs(void);
 
@@ -89,7 +89,6 @@
         int   cache_flags;
         char *cache_root_fileset;  /* fileset mounted on cache "/"  */
 
-        kdev_t cache_dev;            /* underlying block device */
 	struct super_block *cache_sb;
         struct dentry *cache_mtde;  /* unix mtpt of cache XXX NOT VALID XXX */
         char *cache_mtpt;           /*  again */
diff -urN linux-2.5.6-pre1/include/linux/irq_cpustat.h linux-2.5.6-pre2/include/linux/irq_cpustat.h
--- linux-2.5.6-pre1/include/linux/irq_cpustat.h	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/include/linux/irq_cpustat.h	Thu Feb 28 13:34:24 2002
@@ -19,11 +19,13 @@
 
 extern irq_cpustat_t irq_stat[];			/* defined in asm/hardirq.h */
 
+#ifndef __ARCH_IRQ_STAT /* Some architectures can do this more efficiently */ 
 #ifdef CONFIG_SMP
 #define __IRQ_STAT(cpu, member)	(irq_stat[cpu].member)
 #else
 #define __IRQ_STAT(cpu, member)	((void)(cpu), irq_stat[0].member)
 #endif	
+#endif
 
   /* arch independent irq_stat fields */
 #define softirq_pending(cpu)	__IRQ_STAT((cpu), __softirq_pending)
diff -urN linux-2.5.6-pre1/include/linux/jffs2.h linux-2.5.6-pre2/include/linux/jffs2.h
--- linux-2.5.6-pre1/include/linux/jffs2.h	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6-pre2/include/linux/jffs2.h	Thu Feb 28 13:34:24 2002
@@ -31,7 +31,7 @@
  * provisions above, a recipient may use your version of this file
  * under either the RHEPL or the GPL.
  *
- * $Id: jffs2.h,v 1.18 2001/03/25 22:36:12 dwmw2 Exp $
+ * $Id: jffs2.h,v 1.19 2001/10/09 13:20:23 dwmw2 Exp $
  *
  */
 
@@ -103,7 +103,7 @@
 	__u16 nodetype;
 	__u32 totlen; /* So we can skip over nodes we don't grok */
 	__u32 hdr_crc;
-};
+} __attribute__((packed));
 
 struct jffs2_raw_dirent
 {
@@ -121,7 +121,7 @@
 	__u32 node_crc;
 	__u32 name_crc;
 	__u8 name[0];
-};
+} __attribute__((packed));
 
 /* The JFFS2 raw inode structure: Used for storage on physical media.  */
 /* The uid, gid, atime, mtime and ctime members could be longer, but 
@@ -153,7 +153,7 @@
 	__u32 data_crc;   /* CRC for the (compressed) data.  */
 	__u32 node_crc;   /* CRC for the raw inode (excluding data)  */
 //	__u8 data[dsize];
-};
+} __attribute__((packed));
 
 union jffs2_node_union {
 	struct jffs2_raw_inode i;
diff -urN linux-2.5.6-pre1/include/linux/jffs2_fs_sb.h linux-2.5.6-pre2/include/linux/jffs2_fs_sb.h
--- linux-2.5.6-pre1/include/linux/jffs2_fs_sb.h	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6-pre2/include/linux/jffs2_fs_sb.h	Thu Feb 28 13:34:24 2002
@@ -1,4 +1,4 @@
-/* $Id: jffs2_fs_sb.h,v 1.16 2001/09/18 20:15:18 dwmw2 Exp $ */
+/* $Id: jffs2_fs_sb.h,v 1.16.2.1 2002/02/23 14:13:34 dwmw2 Exp $ */
 
 #ifndef _JFFS2_FS_SB
 #define _JFFS2_FS_SB
@@ -12,6 +12,7 @@
 #define INOCACHE_HASHSIZE 1
 
 #define JFFS2_SB_FLAG_RO 1
+#define JFFS2_SB_FLAG_MOUNTING 2
 
 /* A struct for the overall file system control.  Pointers to
    jffs2_sb_info structs are named `c' in the source code.  
diff -urN linux-2.5.6-pre1/include/linux/nfsd/export.h linux-2.5.6-pre2/include/linux/nfsd/export.h
--- linux-2.5.6-pre1/include/linux/nfsd/export.h	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/include/linux/nfsd/export.h	Thu Feb 28 13:34:24 2002
@@ -87,8 +87,7 @@
 void			nfsd_export_init(void);
 void			nfsd_export_shutdown(void);
 void			exp_readlock(void);
-int			exp_writelock(void);
-void			exp_unlock(void);
+void			exp_readunlock(void);
 struct svc_client *	exp_getclient(struct sockaddr_in *sin);
 void			exp_putclient(struct svc_client *clp);
 struct svc_export *	exp_get(struct svc_client *clp, kdev_t dev, ino_t ino);
diff -urN linux-2.5.6-pre1/include/linux/nfsd/interface.h linux-2.5.6-pre2/include/linux/nfsd/interface.h
--- linux-2.5.6-pre1/include/linux/nfsd/interface.h	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/include/linux/nfsd/interface.h	Thu Feb 28 13:34:24 2002
@@ -12,7 +12,8 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_NFSD_MODULE
+#ifndef CONFIG_NFSD
+#ifdef CONFIG_MODULES
 
 extern struct nfsd_linkage {
 	long (*do_nfsservctl)(int cmd, void *argp, void *resp);
@@ -20,5 +21,6 @@
 } * nfsd_linkage;
 
 #endif
+#endif
 
 #endif /* LINUX_NFSD_INTERFACE_H */
diff -urN linux-2.5.6-pre1/include/linux/parport.h linux-2.5.6-pre2/include/linux/parport.h
--- linux-2.5.6-pre1/include/linux/parport.h	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/include/linux/parport.h	Thu Feb 28 13:34:24 2002
@@ -459,7 +459,10 @@
 extern int parport_negotiate (struct parport *, int mode);
 extern ssize_t parport_write (struct parport *, const void *buf, size_t len);
 extern ssize_t parport_read (struct parport *, void *buf, size_t len);
+
+#define PARPORT_INACTIVITY_O_NONBLOCK 1
 extern long parport_set_timeout (struct pardevice *, long inactivity);
+
 extern int parport_wait_event (struct parport *, long timeout);
 extern int parport_wait_peripheral (struct parport *port,
 				    unsigned char mask,
diff -urN linux-2.5.6-pre1/include/linux/sunrpc/sched.h linux-2.5.6-pre2/include/linux/sunrpc/sched.h
--- linux-2.5.6-pre1/include/linux/sunrpc/sched.h	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/include/linux/sunrpc/sched.h	Thu Feb 28 13:34:24 2002
@@ -34,13 +34,11 @@
  * This is the RPC task struct
  */
 struct rpc_task {
-	struct rpc_task *	tk_prev;	/* wait queue links */
-	struct rpc_task *	tk_next;
+	struct list_head	tk_list;	/* wait queue links */
 #ifdef RPC_DEBUG
 	unsigned long		tk_magic;	/* 0xf00baa */
 #endif
-	struct rpc_task *	tk_next_task;	/* global list of tasks */
-	struct rpc_task *	tk_prev_task;	/* global list of tasks */
+	struct list_head	tk_task;	/* global list of tasks */
 	struct rpc_clnt *	tk_client;	/* RPC client */
 	struct rpc_rqst *	tk_rqstp;	/* RPC request */
 	int			tk_status;	/* result of last operation */
@@ -88,6 +86,20 @@
 #define tk_auth			tk_client->cl_auth
 #define tk_xprt			tk_client->cl_xprt
 
+/* support walking a list of tasks on a wait queue */
+#define	task_for_each(task, pos, head) \
+	list_for_each(pos, head) \
+		if ((task=list_entry(pos, struct rpc_task, tk_list)),1)
+
+#define	task_for_first(task, head) \
+	if (!list_empty(head) &&  \
+	    ((task=list_entry((head)->next, struct rpc_task, tk_list)),1))
+
+/* .. and walking list of all tasks */
+#define	alltask_for_each(task, pos, head) \
+	list_for_each(pos, head) \
+		if ((task=list_entry(pos, struct rpc_task, tk_task)),1)
+
 typedef void			(*rpc_action)(struct rpc_task *);
 
 /*
@@ -133,16 +145,24 @@
  * RPC synchronization objects
  */
 struct rpc_wait_queue {
-	struct rpc_task *	task;
+	struct list_head	tasks;
 #ifdef RPC_DEBUG
 	char *			name;
 #endif
 };
 
 #ifndef RPC_DEBUG
-# define RPC_INIT_WAITQ(name)	((struct rpc_wait_queue) { NULL })
+# define RPC_WAITQ_INIT(var,qname) ((struct rpc_wait_queue) {LIST_HEAD_INIT(var)})
+# define RPC_WAITQ(var,qname)      struct rpc_wait_queue var = RPC_WAITQ_INIT(var.tasks,qname)
+# define INIT_RPC_WAITQ(ptr,qname) do { \
+	INIT_LIST_HEAD(&(ptr)->tasks); \
+	} while(0)
 #else
-# define RPC_INIT_WAITQ(name)	((struct rpc_wait_queue) { NULL, name })
+# define RPC_WAITQ_INIT(var,qname) ((struct rpc_wait_queue) {LIST_HEAD_INIT(var.tasks), qname})
+# define RPC_WAITQ(var,qname)      struct rpc_wait_queue var = RPC_WAITQ_INIT(var,qname)
+# define INIT_RPC_WAITQ(ptr,qname) do { \
+	INIT_LIST_HEAD(&(ptr)->tasks); (ptr)->name = qname; \
+	} while(0)
 #endif
 
 /*
diff -urN linux-2.5.6-pre1/include/linux/sunrpc/svc.h linux-2.5.6-pre2/include/linux/sunrpc/svc.h
--- linux-2.5.6-pre1/include/linux/sunrpc/svc.h	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/include/linux/sunrpc/svc.h	Thu Feb 28 13:34:24 2002
@@ -27,8 +27,8 @@
  * We currently do not support more than one RPC program per daemon.
  */
 struct svc_serv {
-	struct svc_rqst *	sv_threads;	/* idle server threads */
-	struct svc_sock *	sv_sockets;	/* pending sockets */
+	struct list_head	sv_threads;	/* idle server threads */
+	struct list_head	sv_sockets;	/* pending sockets */
 	struct svc_program *	sv_program;	/* RPC program */
 	struct svc_stat *	sv_stats;	/* RPC statistics */
 	spinlock_t		sv_lock;
@@ -36,7 +36,9 @@
 	unsigned int		sv_bufsz;	/* datagram buffer size */
 	unsigned int		sv_xdrsize;	/* XDR buffer size */
 
-	struct svc_sock *	sv_allsocks;	/* all sockets */
+	struct list_head	sv_permsocks;	/* all permanent sockets */
+	struct list_head	sv_tempsocks;	/* all temporary sockets */
+	int			sv_tmpcnt;	/* count of temporary sockets */
 
 	char *			sv_name;	/* service name */
 };
@@ -89,8 +91,7 @@
  * NOTE: First two items must be prev/next.
  */
 struct svc_rqst {
-	struct svc_rqst *	rq_prev;	/* idle list */
-	struct svc_rqst *	rq_next;
+	struct list_head	rq_list;	/* idle list */
 	struct svc_sock *	rq_sock;	/* socket */
 	struct sockaddr_in	rq_addr;	/* peer address */
 	int			rq_addrlen;
@@ -115,6 +116,10 @@
 	void *			rq_argp;	/* decoded arguments */
 	void *			rq_resp;	/* xdr'd results */
 
+	int			rq_reserved;	/* space on socket outq
+						 * reserved for this request
+						 */
+
 	/* Catering to nfsd */
 	struct svc_client *	rq_client;	/* RPC peer info */
 	struct svc_cacherep *	rq_cacherep;	/* cache info */
@@ -163,6 +168,7 @@
 	unsigned int		pc_ressize;	/* result struct size */
 	unsigned int		pc_count;	/* call count */
 	unsigned int		pc_cachetype;	/* cache info (NFS) */
+	unsigned int		pc_xdrressize;	/* maximum size of XDR reply */
 };
 
 /*
@@ -180,5 +186,6 @@
 int		   svc_process(struct svc_serv *, struct svc_rqst *);
 int		   svc_register(struct svc_serv *, int, unsigned short);
 void		   svc_wake_up(struct svc_serv *);
+void		   svc_reserve(struct svc_rqst *rqstp, int space);
 
 #endif /* SUNRPC_SVC_H */
diff -urN linux-2.5.6-pre1/include/linux/sunrpc/svcsock.h linux-2.5.6-pre2/include/linux/sunrpc/svcsock.h
--- linux-2.5.6-pre1/include/linux/sunrpc/svcsock.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/include/linux/sunrpc/svcsock.h	Thu Feb 28 13:34:24 2002
@@ -13,38 +13,38 @@
 
 /*
  * RPC server socket.
- * NOTE: First two items must be prev/next.
  */
 struct svc_sock {
-	struct svc_sock *	sk_prev;	/* list of ready sockets */
-	struct svc_sock *	sk_next;
-	struct svc_sock *	sk_list;	/* list of all sockets */
+	struct list_head	sk_ready;	/* list of ready sockets */
+	struct list_head	sk_list;	/* list of all sockets */
 	struct socket *		sk_sock;	/* berkeley socket layer */
 	struct sock *		sk_sk;		/* INET layer */
-	spinlock_t		sk_lock;
 
 	struct svc_serv *	sk_server;	/* service for this socket */
 	unsigned char		sk_inuse;	/* use count */
-	unsigned char		sk_busy;	/* enqueued/receiving */
-	unsigned char		sk_conn;	/* conn pending */
-	unsigned char		sk_close;	/* dead or dying */
-	int			sk_data;	/* data pending */
-	unsigned int		sk_temp : 1,	/* temp socket */
-				sk_qued : 1,	/* on serv->sk_sockets */
-				sk_dead : 1;	/* socket closed */
+	unsigned int		sk_flags;
+#define	SK_BUSY		0			/* enqueued/receiving */
+#define	SK_CONN		1			/* conn pending */
+#define	SK_CLOSE	2			/* dead or dying */
+#define	SK_DATA		3			/* data pending */
+#define	SK_TEMP		4			/* temp (TCP) socket */
+#define	SK_QUED		5			/* on serv->sk_sockets */
+#define	SK_DEAD		6			/* socket closed */
+
+	int			sk_reserved;	/* space on outq that is reserved */
+
 	int			(*sk_recvfrom)(struct svc_rqst *rqstp);
 	int			(*sk_sendto)(struct svc_rqst *rqstp);
 
 	/* We keep the old state_change and data_ready CB's here */
 	void			(*sk_ostate)(struct sock *);
 	void			(*sk_odata)(struct sock *, int bytes);
+	void			(*sk_owspace)(struct sock *);
 
 	/* private TCP part */
 	int			sk_reclen;	/* length of record */
 	int			sk_tcplen;	/* current read length */
-
-	/* Debugging */
-	struct svc_rqst *	sk_rqstp;
+	time_t			sk_lastrecv;	/* time of last received request */
 };
 
 /*
@@ -55,5 +55,6 @@
 int		svc_recv(struct svc_serv *, struct svc_rqst *, long);
 int		svc_send(struct svc_rqst *);
 void		svc_drop(struct svc_rqst *);
+void		svc_sock_update_bufs(struct svc_serv *serv);
 
 #endif /* SUNRPC_SVCSOCK_H */
diff -urN linux-2.5.6-pre1/include/linux/sunrpc/types.h linux-2.5.6-pre2/include/linux/sunrpc/types.h
--- linux-2.5.6-pre1/include/linux/sunrpc/types.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6-pre2/include/linux/sunrpc/types.h	Thu Feb 28 13:34:25 2002
@@ -12,60 +12,7 @@
 #include <linux/timer.h>
 #include <linux/tqueue.h>
 #include <linux/sunrpc/debug.h>
-
-/*
- * These are the RPC list manipulation primitives used everywhere.
- */
-struct rpc_listitem	{
-	struct rpc_listitem *	prev;
-	struct rpc_listitem *	next;
-};
-
-static __inline__ void
-__rpc_append_list(struct rpc_listitem **q, struct rpc_listitem *item)
-{
-	struct rpc_listitem	*next, *prev;
-
-	if (!(next = *q)) {
-		*q = item->next = item->prev = item;
-	} else {
-		prev = next->prev;
-		prev->next = item;
-		next->prev = item;
-		item->next = next;
-		item->prev = prev;
-	}
-}
-
-static __inline__ void
-__rpc_insert_list(struct rpc_listitem **q, struct rpc_listitem *item)
-{
-	__rpc_append_list(q, item);
-	*q = item;
-}
-
-static __inline__ void
-__rpc_remove_list(struct rpc_listitem **q, struct rpc_listitem *item)
-{
-	struct rpc_listitem	*prev = item->prev,
-				*next = item->next;
-
-	if (item != prev) {
-		next->prev = prev;
-		prev->next = next;
-	} else {
-		next = NULL;
-	}
-	if (*q == item)
-		*q = next;
-}
-
-#define rpc_insert_list(q, i) \
-      __rpc_insert_list((struct rpc_listitem **) q, (struct rpc_listitem *) i)
-#define rpc_append_list(q, i) \
-      __rpc_append_list((struct rpc_listitem **) q, (struct rpc_listitem *) i)
-#define rpc_remove_list(q, i) \
-      __rpc_remove_list((struct rpc_listitem **) q, (struct rpc_listitem *) i)
+#include <linux/list.h>
 
 /*
  * Shorthands
diff -urN linux-2.5.6-pre1/include/linux/usb.h linux-2.5.6-pre2/include/linux/usb.h
--- linux-2.5.6-pre1/include/linux/usb.h	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6-pre2/include/linux/usb.h	Thu Feb 28 13:34:25 2002
@@ -44,8 +44,8 @@
 /*
  * USB directions
  */
-#define USB_DIR_OUT			0
-#define USB_DIR_IN			0x80
+#define USB_DIR_OUT			0		/* to device */
+#define USB_DIR_IN			0x80		/* to host */
 
 /*
  * Endpoints
@@ -148,12 +148,6 @@
 	unsigned long devicemap[128 / (8*sizeof(unsigned long))];
 };
 
-#define USB_MAXBUS		64
-
-struct usb_busmap {
-	unsigned long busmap[USB_MAXBUS / (8*sizeof(unsigned long))];
-};
-
 struct usb_device;
 
 /*-------------------------------------------------------------------------*/
@@ -516,7 +510,8 @@
  * work to connect to a device should be done when the device is opened,
  * and undone at the last close.  The disconnect code needs to address
  * concurrency issues with respect to open() and close() methods, as
- * well as cancel any I/O requests that are still pending.
+ * well as forcing all pending I/O requests to complete (by unlinking
+ * them as necessary, and blocking until the unlinks complete).
  */
 struct usb_driver {
 	struct module *owner;
@@ -905,13 +900,7 @@
 
 /* Host Controller Driver (HCD) support */
 
-struct usb_operations {
-	int (*allocate)(struct usb_device *);
-	int (*deallocate)(struct usb_device *);
-	int (*get_frame_number) (struct usb_device *usb_dev);
-	int (*submit_urb) (struct urb *urb, int mem_flags);
-	int (*unlink_urb) (struct urb *urb);
-};
+struct usb_operations;
 
 #define DEVNUM_ROUND_ROBIN	/***** OPTION *****/
 
@@ -944,41 +933,12 @@
 	atomic_t refcnt;
 };
 
-extern struct usb_bus *usb_alloc_bus(struct usb_operations *);
-extern void usb_free_bus(struct usb_bus *);
-extern void usb_register_bus(struct usb_bus *);
-extern void usb_deregister_bus(struct usb_bus *);
-extern int usb_register_root_hub(struct usb_device *usb_dev, struct device *parent_dev);
-
-extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
-extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb,
-		int bustime, int isoc);
-extern void usb_release_bandwidth(struct usb_device *dev, struct urb *urb,
-		int isoc);
+// FIXME:  root_hub_string vanishes when "usb_hcd" conversion is done,
+// along with pre-hcd versions of the OHCI and UHCI drivers.
 extern int usb_root_hub_string(int id, int serial,
 		char *type, __u8 *data, int len);
 
 /*
- * Some USB 1.1 bandwidth allocation constants.
- */
-#define BW_HOST_DELAY	1000L		/* nanoseconds */
-#define BW_HUB_LS_SETUP	333L		/* nanoseconds */
-                        /* 4 full-speed bit times (est.) */
-
-#define FRAME_TIME_BITS         12000L		/* frame = 1 millisecond */
-#define FRAME_TIME_MAX_BITS_ALLOC	(90L * FRAME_TIME_BITS / 100L)
-#define FRAME_TIME_USECS	1000L
-#define FRAME_TIME_MAX_USECS_ALLOC	(90L * FRAME_TIME_USECS / 100L)
-
-#define BitTime(bytecount)  (7 * 8 * bytecount / 6)  /* with integer truncation */
-		/* Trying not to use worst-case bit-stuffing
-                   of (7/6 * 8 * bytecount) = 9.33 * bytecount */
-		/* bytecount = data payload byte count */
-
-#define NS_TO_US(ns)	((ns + 500L) / 1000L)
-			/* convert & round nanoseconds to microseconds */
-
-/*
  * As of USB 2.0, full/low speed devices are segregated into trees.
  * One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
  * The other type grows from high speed hubs when they connect to
@@ -1209,13 +1169,11 @@
 /* -------------------------------------------------------------------------- */
 
 /*
- * bus and driver list
+ * driver list
  * exported only for usbfs (not visible outside usbcore)
  */
 
 extern struct list_head usb_driver_list;
-extern struct list_head usb_bus_list;
-extern struct semaphore usb_bus_list_lock;
 
 /*
  * USB device fs stuff
diff -urN linux-2.5.6-pre1/init/main.c linux-2.5.6-pre2/init/main.c
--- linux-2.5.6-pre1/init/main.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/init/main.c	Thu Feb 28 13:34:25 2002
@@ -460,6 +460,8 @@
 
 static int init(void * unused)
 {
+	static char * argv_sh[] = { "sh", NULL, };
+
 	lock_kernel();
 	do_basic_setup();
 
@@ -491,6 +493,6 @@
 	execve("/sbin/init",argv_init,envp_init);
 	execve("/etc/init",argv_init,envp_init);
 	execve("/bin/init",argv_init,envp_init);
-	execve("/bin/sh",argv_init,envp_init);
+	execve("/bin/sh",argv_sh,envp_init);
 	panic("No init found.  Try passing init= option to kernel.");
 }
diff -urN linux-2.5.6-pre1/kernel/info.c linux-2.5.6-pre2/kernel/info.c
--- linux-2.5.6-pre1/kernel/info.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/kernel/info.c	Thu Feb 28 13:34:25 2002
@@ -26,7 +26,7 @@
 	val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
 	val.loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT);
 
-	val.procs = nr_threads-1;
+	val.procs = nr_threads;
 	sti();
 
 	si_meminfo(&val);
diff -urN linux-2.5.6-pre1/kernel/ksyms.c linux-2.5.6-pre2/kernel/ksyms.c
--- linux-2.5.6-pre1/kernel/ksyms.c	Thu Feb 28 13:34:17 2002
+++ linux-2.5.6-pre2/kernel/ksyms.c	Thu Feb 28 13:34:25 2002
@@ -181,6 +181,7 @@
 EXPORT_SYMBOL(invalidate_inode_pages);
 EXPORT_SYMBOL(truncate_inode_pages);
 EXPORT_SYMBOL(fsync_dev);
+EXPORT_SYMBOL(fsync_bdev);
 EXPORT_SYMBOL(fsync_no_super);
 EXPORT_SYMBOL(permission);
 EXPORT_SYMBOL(vfs_permission);
@@ -311,7 +312,6 @@
 EXPORT_SYMBOL(is_read_only);
 EXPORT_SYMBOL(set_device_ro);
 EXPORT_SYMBOL(bmap);
-EXPORT_SYMBOL(sync_dev);
 EXPORT_SYMBOL(devfs_register_partitions);
 EXPORT_SYMBOL(blkdev_open);
 EXPORT_SYMBOL(blkdev_get);
diff -urN linux-2.5.6-pre1/mm/vmscan.c linux-2.5.6-pre2/mm/vmscan.c
--- linux-2.5.6-pre1/mm/vmscan.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/mm/vmscan.c	Thu Feb 28 13:34:25 2002
@@ -578,7 +578,9 @@
 		return 0;
 
 	shrink_dcache_memory(priority, gfp_mask);
-	shrink_icache_memory(priority, gfp_mask);
+
+	/* After shrinking the dcache, get rid of unused inodes too .. */
+	shrink_icache_memory(1, gfp_mask);
 #ifdef CONFIG_QUOTA
 	shrink_dqcache_memory(DEF_PRIORITY, gfp_mask);
 #endif
diff -urN linux-2.5.6-pre1/net/sunrpc/clnt.c linux-2.5.6-pre2/net/sunrpc/clnt.c
--- linux-2.5.6-pre1/net/sunrpc/clnt.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6-pre2/net/sunrpc/clnt.c	Thu Feb 28 13:34:25 2002
@@ -78,10 +78,6 @@
 	dprintk("RPC: creating %s client for %s (xprt %p)\n",
 		program->name, servname, xprt);
 
-#ifdef RPC_DEBUG
-	rpc_register_sysctl();
-#endif
-
 	if (!xprt)
 		goto out;
 	if (vers >= program->nrvers || !(version = program->version[vers]))
@@ -103,7 +99,7 @@
 	clnt->cl_vers     = version->number;
 	clnt->cl_prot     = xprt->prot;
 	clnt->cl_stats    = program->stats;
-	clnt->cl_bindwait = RPC_INIT_WAITQ("bindwait");
+	INIT_RPC_WAITQ(&clnt->cl_bindwait, "bindwait");
 
 	if (!clnt->cl_port)
 		clnt->cl_autobind = 1;
diff -urN linux-2.5.6-pre1/net/sunrpc/sched.c linux-2.5.6-pre2/net/sunrpc/sched.c
--- linux-2.5.6-pre1/net/sunrpc/sched.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6-pre2/net/sunrpc/sched.c	Thu Feb 28 13:34:25 2002
@@ -41,23 +41,23 @@
  * handler, or while executing another RPC task, it is put on
  * schedq, and rpciod is woken up.
  */
-static struct rpc_wait_queue	schedq = RPC_INIT_WAITQ("schedq");
+static RPC_WAITQ(schedq, "schedq");
 
 /*
  * RPC tasks that create another task (e.g. for contacting the portmapper)
  * will wait on this queue for their child's completion
  */
-static struct rpc_wait_queue	childq = RPC_INIT_WAITQ("childq");
+static RPC_WAITQ(childq, "childq");
 
 /*
  * RPC tasks sit here while waiting for conditions to improve.
  */
-static struct rpc_wait_queue	delay_queue = RPC_INIT_WAITQ("delayq");
+static RPC_WAITQ(delay_queue, "delayq");
 
 /*
  * All RPC tasks are linked into this list
  */
-static struct rpc_task *	all_tasks;
+static LIST_HEAD(all_tasks);
 
 /*
  * rpciod-related stuff
@@ -194,9 +194,9 @@
 		return -EWOULDBLOCK;
 	}
 	if (RPC_IS_SWAPPER(task))
-		rpc_insert_list(&queue->task, task);
+		list_add(&task->tk_list, &queue->tasks);
 	else
-		rpc_append_list(&queue->task, task);
+		list_add_tail(&task->tk_list, &queue->tasks);
 	task->tk_rpcwait = queue;
 
 	dprintk("RPC: %4d added to queue %p \"%s\"\n",
@@ -228,7 +228,7 @@
 	if (!queue)
 		return;
 
-	rpc_remove_list(&queue->task, task);
+	list_del(&task->tk_list);
 	task->tk_rpcwait = NULL;
 
 	dprintk("RPC: %4d removed from queue %p \"%s\"\n",
@@ -450,11 +450,11 @@
 struct rpc_task *
 rpc_wake_up_next(struct rpc_wait_queue *queue)
 {
-	struct rpc_task	*task;
+	struct rpc_task	*task = NULL;
 
 	dprintk("RPC:      wake_up_next(%p \"%s\")\n", queue, rpc_qname(queue));
 	spin_lock_bh(&rpc_queue_lock);
-	if ((task = queue->task) != 0)
+	task_for_first(task, &queue->tasks)
 		__rpc_wake_up_task(task);
 	spin_unlock_bh(&rpc_queue_lock);
 
@@ -470,9 +470,12 @@
 void
 rpc_wake_up(struct rpc_wait_queue *queue)
 {
+	struct rpc_task *task;
+
 	spin_lock_bh(&rpc_queue_lock);
-	while (queue->task)
-		__rpc_wake_up_task(queue->task);
+	while (!list_empty(&queue->tasks))
+		task_for_first(task, &queue->tasks)
+			__rpc_wake_up_task(task);
 	spin_unlock_bh(&rpc_queue_lock);
 }
 
@@ -486,12 +489,14 @@
 void
 rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
 {
-	struct rpc_task	*task;
+	struct rpc_task *task;
 
 	spin_lock_bh(&rpc_queue_lock);
-	while ((task = queue->task) != NULL) {
-		task->tk_status = status;
-		__rpc_wake_up_task(task);
+	while (!list_empty(&queue->tasks)) {
+		task_for_first(task, &queue->tasks) {
+			task->tk_status = status;
+			__rpc_wake_up_task(task);
+		}
 	}
 	spin_unlock_bh(&rpc_queue_lock);
 }
@@ -703,23 +708,25 @@
 		rpciod_tcp_dispatcher();
 
 		spin_lock_bh(&rpc_queue_lock);
-		if (!(task = schedq.task)) {
-			spin_unlock_bh(&rpc_queue_lock);
-			break;
-		}
-		if (task->tk_lock) {
-			spin_unlock_bh(&rpc_queue_lock);
-			printk(KERN_ERR "RPC: Locked task was scheduled !!!!\n");
+
+		task_for_first(task, &schedq.tasks) {
+			if (task->tk_lock) {
+				spin_unlock_bh(&rpc_queue_lock);
+				printk(KERN_ERR "RPC: Locked task was scheduled !!!!\n");
 #ifdef RPC_DEBUG			
-			rpc_debug = ~0;
-			rpc_show_tasks();
+				rpc_debug = ~0;
+				rpc_show_tasks();
 #endif			
+				break;
+			}
+			__rpc_remove_wait_queue(task);
+			spin_unlock_bh(&rpc_queue_lock);
+
+			__rpc_execute(task);
+		} else {
+			spin_unlock_bh(&rpc_queue_lock);
 			break;
 		}
-		__rpc_remove_wait_queue(task);
-		spin_unlock_bh(&rpc_queue_lock);
-
-		__rpc_execute(task);
 
 		if (++count >= 200 || need_resched()) {
 			count = 0;
@@ -814,11 +821,7 @@
 
 	/* Add to global list of all tasks */
 	spin_lock(&rpc_sched_lock);
-	task->tk_next_task = all_tasks;
-	task->tk_prev_task = NULL;
-	if (all_tasks)
-		all_tasks->tk_prev_task = task;
-	all_tasks = task;
+	list_add(&task->tk_task, &all_tasks);
 	spin_unlock(&rpc_sched_lock);
 
 	if (clnt)
@@ -877,8 +880,6 @@
 void
 rpc_release_task(struct rpc_task *task)
 {
-	struct rpc_task	*next, *prev;
-
 	dprintk("RPC: %4d release task\n", task->tk_pid);
 
 #ifdef RPC_DEBUG
@@ -892,15 +893,7 @@
 
 	/* Remove from global task list */
 	spin_lock(&rpc_sched_lock);
-	prev = task->tk_prev_task;
-	next = task->tk_next_task;
-	if (next)
-		next->tk_prev_task = prev;
-	if (prev)
-		prev->tk_next_task = next;
-	else
-		all_tasks = next;
-	task->tk_next_task = task->tk_prev_task = NULL;
+	list_del(&task->tk_task);
 	spin_unlock(&rpc_sched_lock);
 
 	/* Protect the execution below. */
@@ -954,14 +947,13 @@
 rpc_find_parent(struct rpc_task *child)
 {
 	struct rpc_task	*task, *parent;
+	struct list_head *le;
 
 	parent = (struct rpc_task *) child->tk_calldata;
-	if ((task = childq.task) != NULL) {
-		do {
-			if (task == parent)
-				return parent;
-		} while ((task = task->tk_next) != childq.task);
-	}
+	task_for_each(task, le, &childq.tasks)
+		if (task == parent)
+			return parent;
+
 	return NULL;
 }
 
@@ -1015,7 +1007,8 @@
 void
 rpc_killall_tasks(struct rpc_clnt *clnt)
 {
-	struct rpc_task	**q, *rovr;
+	struct rpc_task	*rovr;
+	struct list_head *le;
 
 	dprintk("RPC:      killing all tasks for client %p\n", clnt);
 
@@ -1023,13 +1016,12 @@
 	 * Spin lock all_tasks to prevent changes...
 	 */
 	spin_lock(&rpc_sched_lock);
-	for (q = &all_tasks; (rovr = *q); q = &rovr->tk_next_task) {
+	alltask_for_each(rovr, le, &all_tasks)
 		if (!clnt || rovr->tk_client == clnt) {
 			rovr->tk_flags |= RPC_TASK_KILLED;
 			rpc_exit(rovr, -EIO);
 			rpc_wake_up_task(rovr);
 		}
-	}
 	spin_unlock(&rpc_sched_lock);
 }
 
@@ -1038,7 +1030,7 @@
 static inline int
 rpciod_task_pending(void)
 {
-	return schedq.task != NULL || xprt_tcp_pending();
+	return !list_empty(&schedq.tasks) || xprt_tcp_pending();
 }
 
 
@@ -1090,7 +1082,7 @@
 	}
 
 	dprintk("RPC: rpciod shutdown commences\n");
-	if (all_tasks) {
+	if (!list_empty(&all_tasks)) {
 		printk(KERN_ERR "rpciod: active tasks at shutdown?!\n");
 		rpciod_killall();
 	}
@@ -1108,11 +1100,11 @@
 {
 	unsigned long flags;
 
-	while (all_tasks) {
+	while (!list_empty(&all_tasks)) {
 		clear_thread_flag(TIF_SIGPENDING);
 		rpc_killall_tasks(NULL);
 		__rpc_schedule();
-		if (all_tasks) {
+		if (!list_empty(&all_tasks)) {
 			dprintk("rpciod_killall: waiting for tasks to exit\n");
 			yield();
 		}
@@ -1207,25 +1199,23 @@
 #ifdef RPC_DEBUG
 void rpc_show_tasks(void)
 {
-	struct rpc_task *t = all_tasks, *next;
+	struct list_head *le;
+	struct rpc_task *t;
 
 	spin_lock(&rpc_sched_lock);
-	t = all_tasks;
-	if (!t) {
+	if (list_empty(&all_tasks)) {
 		spin_unlock(&rpc_sched_lock);
 		return;
 	}
 	printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout "
 		"-rpcwait -action- --exit--\n");
-	for (; t; t = next) {
-		next = t->tk_next_task;
+	alltask_for_each(t, le, &all_tasks)
 		printk("%05d %04d %04x %06d %8p %6d %8p %08ld %8s %8p %8p\n",
 			t->tk_pid, t->tk_msg.rpc_proc, t->tk_flags, t->tk_status,
 			t->tk_client, t->tk_client->cl_prog,
 			t->tk_rqstp, t->tk_timeout,
 			t->tk_rpcwait ? rpc_qname(t->tk_rpcwait) : " <NULL> ",
 			t->tk_action, t->tk_exit);
-	}
 	spin_unlock(&rpc_sched_lock);
 }
 #endif
diff -urN linux-2.5.6-pre1/net/sunrpc/stats.c linux-2.5.6-pre2/net/sunrpc/stats.c
--- linux-2.5.6-pre1/net/sunrpc/stats.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6-pre2/net/sunrpc/stats.c	Thu Feb 28 13:34:25 2002
@@ -15,6 +15,7 @@
 #define __NO_VERSION__
 #include <linux/module.h>
 
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
@@ -181,10 +182,9 @@
 	}
 }
 
-#ifdef MODULE
 
-int
-init_module(void)
+static int __init
+init_sunrpc(void)
 {
 #ifdef RPC_DEBUG
 	rpc_register_sysctl();
@@ -193,13 +193,14 @@
 	return 0;
 }
 
-void
-cleanup_module(void)
+static void __exit
+cleanup_sunrpc(void)
 {
 #ifdef RPC_DEBUG
 	rpc_unregister_sysctl();
 #endif
 	rpc_proc_exit();
 }
-#endif
 MODULE_LICENSE("GPL");
+module_init(init_sunrpc);
+module_exit(cleanup_sunrpc);
diff -urN linux-2.5.6-pre1/net/sunrpc/svc.c linux-2.5.6-pre2/net/sunrpc/svc.c
--- linux-2.5.6-pre1/net/sunrpc/svc.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6-pre2/net/sunrpc/svc.c	Thu Feb 28 13:34:25 2002
@@ -31,10 +31,6 @@
 {
 	struct svc_serv	*serv;
 
-#ifdef RPC_DEBUG
-	rpc_register_sysctl();
-#endif
-
 	if (!(serv = (struct svc_serv *) kmalloc(sizeof(*serv), GFP_KERNEL)))
 		return NULL;
 
@@ -44,6 +40,10 @@
 	serv->sv_stats     = prog->pg_stats;
 	serv->sv_bufsz	   = bufsize? bufsize : 4096;
 	serv->sv_xdrsize   = xdrsize;
+	INIT_LIST_HEAD(&serv->sv_threads);
+	INIT_LIST_HEAD(&serv->sv_sockets);
+	INIT_LIST_HEAD(&serv->sv_tempsocks);
+	INIT_LIST_HEAD(&serv->sv_permsocks);
 	spin_lock_init(&serv->sv_lock);
 
 	serv->sv_name      = prog->pg_name;
@@ -67,13 +67,25 @@
 				serv->sv_nrthreads);
 
 	if (serv->sv_nrthreads) {
-		if (--(serv->sv_nrthreads) != 0)
+		if (--(serv->sv_nrthreads) != 0) {
+			svc_sock_update_bufs(serv);
 			return;
+		}
 	} else
 		printk("svc_destroy: no threads for serv=%p!\n", serv);
 
-	while ((svsk = serv->sv_allsocks) != NULL)
+	while (!list_empty(&serv->sv_tempsocks)) {
+		svsk = list_entry(serv->sv_tempsocks.next,
+				  struct svc_sock,
+				  sk_list);
+		svc_delete_socket(svsk);
+	}
+	while (!list_empty(&serv->sv_permsocks)) {
+		svsk = list_entry(serv->sv_permsocks.next,
+				  struct svc_sock,
+				  sk_list);
 		svc_delete_socket(svsk);
+	}
 
 	/* Unregister service with the portmapper */
 	svc_register(serv, 0, 0);
@@ -138,6 +150,7 @@
 	error = kernel_thread((int (*)(void *)) func, rqstp, 0);
 	if (error < 0)
 		goto out_thread;
+	svc_sock_update_bufs(serv);
 	error = 0;
 out:
 	return error;
@@ -296,6 +309,12 @@
 	memset(rqstp->rq_argp, 0, procp->pc_argsize);
 	memset(rqstp->rq_resp, 0, procp->pc_ressize);
 
+	/* un-reserve some of the out-queue now that we have a 
+	 * better idea of reply size
+	 */
+	if (procp->pc_xdrressize)
+		svc_reserve(rqstp, procp->pc_xdrressize<<2);
+
 	/* Call the function that processes the request. */
 	if (!versp->vs_dispatch) {
 		/* Decode arguments */
diff -urN linux-2.5.6-pre1/net/sunrpc/svcsock.c linux-2.5.6-pre2/net/sunrpc/svcsock.c
--- linux-2.5.6-pre1/net/sunrpc/svcsock.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6-pre2/net/sunrpc/svcsock.c	Thu Feb 28 13:34:25 2002
@@ -45,10 +45,19 @@
 
 /* SMP locking strategy:
  *
- * 	svc_sock->sk_lock and svc_serv->sv_lock protect their
- *	respective structures.
+ * 	svc_serv->sv_lock protects most stuff for that service.
+ *
+ *	Some flags can be set to certain values at any time
+ *	providing that certain rules are followed:
+ *
+ *	SK_BUSY  can be set to 0 at any time.  
+ *		svc_sock_enqueue must be called afterwards
+ *	SK_CONN, SK_DATA, can be set or cleared at any time.
+ *		after a set, svc_sock_enqueue must be called.	
+ *		after a clear, the socket must be read/accepted
+ *		 if this succeeds, it must be set again.
+ *	SK_CLOSE can set at any time. It is never cleared.
  *
- *	Antideadlock ordering is sk_lock --> sv_lock.
  */
 
 #define RPCDBG_FACILITY	RPCDBG_SVCSOCK
@@ -63,11 +72,14 @@
 
 /*
  * Queue up an idle server thread.  Must have serv->sv_lock held.
+ * Note: this is really a stack rather than a queue, so that we only
+ * use as many different threads as we need, and the rest don't polute
+ * the cache.
  */
 static inline void
 svc_serv_enqueue(struct svc_serv *serv, struct svc_rqst *rqstp)
 {
-	rpc_append_list(&serv->sv_threads, rqstp);
+	list_add(&rqstp->rq_list, &serv->sv_threads);
 }
 
 /*
@@ -76,7 +88,7 @@
 static inline void
 svc_serv_dequeue(struct svc_serv *serv, struct svc_rqst *rqstp)
 {
-	rpc_remove_list(&serv->sv_threads, rqstp);
+	list_del(&rqstp->rq_list);
 }
 
 /*
@@ -99,7 +111,6 @@
  * Queue up a socket with data pending. If there are idle nfsd
  * processes, wake 'em up.
  *
- * This must be called with svsk->sk_lock held.
  */
 static void
 svc_sock_enqueue(struct svc_sock *svsk)
@@ -107,26 +118,44 @@
 	struct svc_serv	*serv = svsk->sk_server;
 	struct svc_rqst	*rqstp;
 
-	/* NOTE: Local BH is already disabled by our caller. */
-	spin_lock(&serv->sv_lock);
+	if (!(svsk->sk_flags &
+	      ( (1<<SK_CONN)|(1<<SK_DATA)|(1<<SK_CLOSE)) ))
+		return;
+
+	spin_lock_bh(&serv->sv_lock);
 
-	if (serv->sv_threads && serv->sv_sockets)
+	if (!list_empty(&serv->sv_threads) && 
+	    !list_empty(&serv->sv_sockets))
 		printk(KERN_ERR
 			"svc_sock_enqueue: threads and sockets both waiting??\n");
 
-	if (svsk->sk_busy) {
+	if (test_bit(SK_BUSY, &svsk->sk_flags)) {
 		/* Don't enqueue socket while daemon is receiving */
 		dprintk("svc: socket %p busy, not enqueued\n", svsk->sk_sk);
 		goto out_unlock;
 	}
 
+	if (((svsk->sk_reserved + serv->sv_bufsz)*2
+	     > sock_wspace(svsk->sk_sk))
+	    && !test_bit(SK_CLOSE, &svsk->sk_flags)
+	    && !test_bit(SK_CONN, &svsk->sk_flags)) {
+		/* Don't enqueue while not enough space for reply */
+		dprintk("svc: socket %p  no space, %d > %ld, not enqueued\n",
+			svsk->sk_sk, svsk->sk_reserved+serv->sv_bufsz,
+			sock_wspace(svsk->sk_sk));
+		goto out_unlock;
+	}
+
 	/* Mark socket as busy. It will remain in this state until the
 	 * server has processed all pending data and put the socket back
 	 * on the idle list.
 	 */
-	svsk->sk_busy = 1;
+	set_bit(SK_BUSY, &svsk->sk_flags);
 
-	if ((rqstp = serv->sv_threads) != NULL) {
+	if (!list_empty(&serv->sv_threads)) {
+		rqstp = list_entry(serv->sv_threads.next,
+				   struct svc_rqst,
+				   rq_list);
 		dprintk("svc: socket %p served by daemon %p\n",
 			svsk->sk_sk, rqstp);
 		svc_serv_dequeue(serv, rqstp);
@@ -136,15 +165,17 @@
 				rqstp, rqstp->rq_sock);
 		rqstp->rq_sock = svsk;
 		svsk->sk_inuse++;
+		rqstp->rq_reserved = serv->sv_bufsz;
+		svsk->sk_reserved += rqstp->rq_reserved;
 		wake_up(&rqstp->rq_wait);
 	} else {
 		dprintk("svc: socket %p put into queue\n", svsk->sk_sk);
-		rpc_append_list(&serv->sv_sockets, svsk);
-		svsk->sk_qued = 1;
+		list_add_tail(&svsk->sk_ready, &serv->sv_sockets);
+		set_bit(SK_QUED, &svsk->sk_flags);
 	}
 
 out_unlock:
-	spin_unlock(&serv->sv_lock);
+	spin_unlock_bh(&serv->sv_lock);
 }
 
 /*
@@ -155,71 +186,69 @@
 {
 	struct svc_sock	*svsk;
 
-	if ((svsk = serv->sv_sockets) != NULL)
-		rpc_remove_list(&serv->sv_sockets, svsk);
+	if (list_empty(&serv->sv_sockets))
+		return NULL;
 
-	if (svsk) {
-		dprintk("svc: socket %p dequeued, inuse=%d\n",
-			svsk->sk_sk, svsk->sk_inuse);
-		svsk->sk_qued = 0;
-	}
+	svsk = list_entry(serv->sv_sockets.next,
+			  struct svc_sock, sk_ready);
+	list_del(&svsk->sk_ready);
+
+	dprintk("svc: socket %p dequeued, inuse=%d\n",
+		svsk->sk_sk, svsk->sk_inuse);
+	clear_bit(SK_QUED, &svsk->sk_flags);
 
 	return svsk;
 }
 
 /*
- * Having read count bytes from a socket, check whether it
+ * Having read something from a socket, check whether it
  * needs to be re-enqueued.
+ * Note: SK_DATA only gets cleared when a read-attempt finds
+ * no (or insufficient) data.
  */
 static inline void
-svc_sock_received(struct svc_sock *svsk, int count)
+svc_sock_received(struct svc_sock *svsk)
 {
-	spin_lock_bh(&svsk->sk_lock);
-	if ((svsk->sk_data -= count) < 0) {
-		printk(KERN_NOTICE "svc: sk_data negative!\n");
-		svsk->sk_data = 0;
-	}
-	svsk->sk_rqstp = NULL; /* XXX */
-	svsk->sk_busy = 0;
-	if (svsk->sk_conn || svsk->sk_data || svsk->sk_close) {
-		dprintk("svc: socket %p re-enqueued after receive\n",
-						svsk->sk_sk);
-		svc_sock_enqueue(svsk);
-	}
-	spin_unlock_bh(&svsk->sk_lock);
+	clear_bit(SK_BUSY, &svsk->sk_flags);
+	svc_sock_enqueue(svsk);
 }
 
-/*
- * Dequeue a new connection.
+
+/**
+ * svc_reserve - change the space reserved for the reply to a request.
+ * @rqstp:  The request in question
+ * @space: new max space to reserve
+ *
+ * Each request reserves some space on the output queue of the socket
+ * to make sure the reply fits.  This function reduces that reserved
+ * space to be the amount of space used already, plus @space.
+ *
  */
-static inline void
-svc_sock_accepted(struct svc_sock *svsk)
+void svc_reserve(struct svc_rqst *rqstp, int space)
 {
-	spin_lock_bh(&svsk->sk_lock);
-        svsk->sk_busy = 0;
-        svsk->sk_conn--;
-        if (svsk->sk_conn || svsk->sk_data || svsk->sk_close) {
-                dprintk("svc: socket %p re-enqueued after accept\n",
-						svsk->sk_sk);
-                svc_sock_enqueue(svsk);
-        }
-	spin_unlock_bh(&svsk->sk_lock);
+	space += rqstp->rq_resbuf.len<<2;
+
+	if (space < rqstp->rq_reserved) {
+		struct svc_sock *svsk = rqstp->rq_sock;
+		spin_lock_bh(&svsk->sk_server->sv_lock);
+		svsk->sk_reserved -= (rqstp->rq_reserved - space);
+		rqstp->rq_reserved = space;
+		spin_unlock_bh(&svsk->sk_server->sv_lock);
+
+		svc_sock_enqueue(svsk);
+	}
 }
 
 /*
  * Release a socket after use.
  */
 static inline void
-svc_sock_release(struct svc_rqst *rqstp)
+svc_sock_put(struct svc_sock *svsk)
 {
-	struct svc_sock	*svsk = rqstp->rq_sock;
-	struct svc_serv	*serv = svsk->sk_server;
-
-	svc_release_skb(rqstp);
-	rqstp->rq_sock = NULL;
+	struct svc_serv *serv = svsk->sk_server;
 
 	spin_lock_bh(&serv->sv_lock);
-	if (!--(svsk->sk_inuse) && svsk->sk_dead) {
+	if (!--(svsk->sk_inuse) && test_bit(SK_DEAD, &svsk->sk_flags)) {
 		spin_unlock_bh(&serv->sv_lock);
 		dprintk("svc: releasing dead socket\n");
 		sock_release(svsk->sk_sock);
@@ -229,6 +258,31 @@
 		spin_unlock_bh(&serv->sv_lock);
 }
 
+static void
+svc_sock_release(struct svc_rqst *rqstp)
+{
+	struct svc_sock	*svsk = rqstp->rq_sock;
+
+	svc_release_skb(rqstp);
+
+	/* Reset response buffer and release
+	 * the reservation.
+	 * But first, check that enough space was reserved
+	 * for the reply, otherwise we have a bug!
+	 */
+	if ((rqstp->rq_resbuf.len<<2) >  rqstp->rq_reserved)
+		printk(KERN_ERR "RPC request reserved %d but used %d\n",
+		       rqstp->rq_reserved,
+		       rqstp->rq_resbuf.len<<2);
+
+	rqstp->rq_resbuf.buf = rqstp->rq_resbuf.base;
+	rqstp->rq_resbuf.len = 0;
+	svc_reserve(rqstp, 0);
+	rqstp->rq_sock = NULL;
+
+	svc_sock_put(svsk);
+}
+
 /*
  * External function to wake up a server waiting for data
  */
@@ -238,7 +292,10 @@
 	struct svc_rqst	*rqstp;
 
 	spin_lock_bh(&serv->sv_lock);
-	if ((rqstp = serv->sv_threads) != NULL) {
+	if (!list_empty(&serv->sv_threads)) {
+		rqstp = list_entry(serv->sv_threads.next,
+				   struct svc_rqst,
+				   rq_list);
 		dprintk("svc: daemon %p woken up.\n", rqstp);
 		/*
 		svc_serv_dequeue(serv, rqstp);
@@ -271,7 +328,13 @@
 	msg.msg_control = NULL;
 	msg.msg_controllen = 0;
 
-	msg.msg_flags	= MSG_DONTWAIT;
+	/* This was MSG_DONTWAIT, but I now want it to wait.
+	 * The only thing that it would wait for is memory and
+	 * if we are fairly low on memory, then we aren't likely
+	 * to make much progress anyway.
+	 * sk->sndtimeo is set to 30seconds just in case.
+	 */
+	msg.msg_flags	= 0;
 
 	oldfs = get_fs(); set_fs(KERNEL_DS);
 	len = sock_sendmsg(sock, &msg, buflen);
@@ -341,6 +404,32 @@
 }
 
 /*
+ * Set socket snd and rcv buffer lengths
+ */
+static inline void
+svc_sock_setbufsize(struct socket *sock, unsigned int snd, unsigned int rcv)
+{
+#if 0
+	mm_segment_t	oldfs;
+	oldfs = get_fs(); set_fs(KERNEL_DS);
+	sock_setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
+			(char*)&snd, sizeof(snd));
+	sock_setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+			(char*)&rcv, sizeof(rcv));
+#else
+	/* sock_setsockopt limits use to sysctl_?mem_max,
+	 * which isn't acceptable.  Until that is made conditional
+	 * on not having CAP_SYS_RESOURCE or similar, we go direct...
+	 * DaveM said I could!
+	 */
+	lock_sock(sock->sk);
+	sock->sk->sndbuf = snd * 2;
+	sock->sk->rcvbuf = rcv * 2;
+	sock->sk->userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK;
+	release_sock(sock->sk);
+#endif
+}
+/*
  * INET callback when data has been received on the socket.
  */
 static void
@@ -351,17 +440,36 @@
 	if (!svsk)
 		goto out;
 	dprintk("svc: socket %p(inet %p), count=%d, busy=%d\n",
-		svsk, sk, count, svsk->sk_busy);
-	spin_lock_bh(&svsk->sk_lock);
-	svsk->sk_data = 1;
+		svsk, sk, count, test_bit(SK_BUSY, &svsk->sk_flags));
+	set_bit(SK_DATA, &svsk->sk_flags);
 	svc_sock_enqueue(svsk);
-	spin_unlock_bh(&svsk->sk_lock);
  out:
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible(sk->sleep);
 }
 
 /*
+ * INET callback when space is newly available on the socket.
+ */
+static void
+svc_write_space(struct sock *sk)
+{
+	struct svc_sock	*svsk = (struct svc_sock *)(sk->user_data);
+
+	if (svsk) {
+		dprintk("svc: socket %p(inet %p), write_space busy=%d\n",
+			svsk, sk, test_bit(SK_BUSY, &svsk->sk_flags));
+		svc_sock_enqueue(svsk);
+	}
+
+	if (sk->sleep && waitqueue_active(sk->sleep)) {
+		printk(KERN_WARNING "RPC svc_write_space: some sleeping on %p\n",
+		       svsk);
+		wake_up_interruptible(sk->sleep);
+	}
+}
+
+/*
  * Receive a datagram from a UDP socket.
  */
 static int
@@ -373,20 +481,21 @@
 	u32		*data;
 	int		err, len;
 
-	svsk->sk_data = 0;
+	clear_bit(SK_DATA, &svsk->sk_flags);
 	while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) {
-		svc_sock_received(svsk, 0);
+		svc_sock_received(svsk);
 		if (err == -EAGAIN)
 			return err;
 		/* possibly an icmp error */
 		dprintk("svc: recvfrom returned error %d\n", -err);
 	}
+	set_bit(SK_DATA, &svsk->sk_flags); /* there may be more data... */
 
 	/* Sorry. */
 	if (skb_is_nonlinear(skb)) {
 		if (skb_linearize(skb, GFP_KERNEL) != 0) {
 			kfree_skb(skb);
-			svc_sock_received(svsk, 0);
+			svc_sock_received(svsk);
 			return 0;
 		}
 	}
@@ -394,13 +503,11 @@
 	if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
 		if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) {
 			skb_free_datagram(svsk->sk_sk, skb);
-			svc_sock_received(svsk, 0);
+			svc_sock_received(svsk);
 			return 0;
 		}
 	}
 
-	/* There may be more data */
-	svsk->sk_data = 1;
 
 	len  = skb->len - sizeof(struct udphdr);
 	data = (u32 *) (skb->data + sizeof(struct udphdr));
@@ -422,7 +529,7 @@
 
 	/* One down, maybe more to go... */
 	svsk->sk_sk->stamp = skb->stamp;
-	svc_sock_received(svsk, 0);
+	svc_sock_received(svsk);
 
 	return len;
 }
@@ -445,9 +552,6 @@
 	if (error == -ECONNREFUSED)
 		/* ICMP error on earlier request. */
 		error = svc_sendto(rqstp, bufp->iov, bufp->nriov);
-	else if (error == -EAGAIN)
-		/* Ignore and wait for re-xmit */
-		error = 0;
 
 	return error;
 }
@@ -456,6 +560,7 @@
 svc_udp_init(struct svc_sock *svsk)
 {
 	svsk->sk_sk->data_ready = svc_udp_data_ready;
+	svsk->sk_sk->write_space = svc_write_space;
 	svsk->sk_recvfrom = svc_udp_recvfrom;
 	svsk->sk_sendto = svc_udp_sendto;
 
@@ -482,10 +587,8 @@
 		printk("svc: socket %p: no user data\n", sk);
 		goto out;
 	}
-	spin_lock_bh(&svsk->sk_lock);
-	svsk->sk_conn++;
+	set_bit(SK_CONN, &svsk->sk_flags);
 	svc_sock_enqueue(svsk);
-	spin_unlock_bh(&svsk->sk_lock);
  out:
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible_all(sk->sleep);
@@ -506,10 +609,8 @@
 		printk("svc: socket %p: no user data\n", sk);
 		goto out;
 	}
-	spin_lock_bh(&svsk->sk_lock);
-	svsk->sk_close = 1;
+	set_bit(SK_CLOSE, &svsk->sk_flags);
 	svc_sock_enqueue(svsk);
-	spin_unlock_bh(&svsk->sk_lock);
  out:
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible_all(sk->sleep);
@@ -524,10 +625,8 @@
 			sk, sk->user_data);
 	if (!(svsk = (struct svc_sock *)(sk->user_data)))
 		goto out;
-	spin_lock_bh(&svsk->sk_lock);
-	svsk->sk_data++;
+	set_bit(SK_DATA, &svsk->sk_flags);
 	svc_sock_enqueue(svsk);
-	spin_unlock_bh(&svsk->sk_lock);
  out:
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible(sk->sleep);
@@ -560,13 +659,14 @@
 	newsock->type = sock->type;
 	newsock->ops = ops = sock->ops;
 
+	clear_bit(SK_CONN, &svsk->sk_flags);
 	if ((err = ops->accept(sock, newsock, O_NONBLOCK)) < 0) {
-		if (net_ratelimit())
+		if (err != -EAGAIN && net_ratelimit())
 			printk(KERN_WARNING "%s: accept failed (err %d)!\n",
 				   serv->sv_name, -err);
 		goto failed;		/* aborted connection or whatever */
 	}
-
+	set_bit(SK_CONN, &svsk->sk_flags);
 	slen = sizeof(sin);
 	err = ops->getname(newsock, (struct sockaddr *) &sin, &slen, 1);
 	if (err < 0) {
@@ -594,14 +694,45 @@
 	if (!(newsvsk = svc_setup_socket(serv, newsock, &err, 0)))
 		goto failed;
 
+	/* make sure that a write doesn't block forever when
+	 * low on memory
+	 */
+	newsock->sk->sndtimeo = HZ*30;
+
 	/* Precharge. Data may have arrived on the socket before we
 	 * installed the data_ready callback. 
 	 */
-	spin_lock_bh(&newsvsk->sk_lock);
-	newsvsk->sk_data = 1;
-	newsvsk->sk_temp = 1;
+	set_bit(SK_DATA, &newsvsk->sk_flags);
 	svc_sock_enqueue(newsvsk);
-	spin_unlock_bh(&newsvsk->sk_lock);
+
+	/* make sure that we don't have too many active connections.
+	 * If we have, something must be dropped.
+	 * We randomly choose between newest and oldest (in terms
+	 * of recent activity) and drop it.
+	 */
+	if (serv->sv_tmpcnt > serv->sv_nrthreads*5) {
+		struct svc_sock *svsk = NULL;
+		spin_lock_bh(&serv->sv_lock);
+		if (!list_empty(&serv->sv_tempsocks)) {
+			if (net_random()&1)
+				svsk = list_entry(serv->sv_tempsocks.prev,
+						  struct svc_sock,
+						  sk_list);
+			else
+				svsk = list_entry(serv->sv_tempsocks.next,
+						  struct svc_sock,
+						  sk_list);
+			set_bit(SK_CLOSE, &svsk->sk_flags);
+			svsk->sk_inuse ++;
+		}
+		spin_unlock_bh(&serv->sv_lock);
+
+		if (svsk) {
+			svc_sock_enqueue(svsk);
+			svc_sock_put(svsk);
+		}
+
+	}
 
 	if (serv->sv_stats)
 		serv->sv_stats->nettcpconn++;
@@ -622,23 +753,25 @@
 	struct svc_sock	*svsk = rqstp->rq_sock;
 	struct svc_serv	*serv = svsk->sk_server;
 	struct svc_buf	*bufp = &rqstp->rq_argbuf;
-	int		len, ready, used;
+	int		len;
 
 	dprintk("svc: tcp_recv %p data %d conn %d close %d\n",
-			svsk, svsk->sk_data, svsk->sk_conn, svsk->sk_close);
+		svsk, test_bit(SK_DATA, &svsk->sk_flags),
+		test_bit(SK_CONN, &svsk->sk_flags),
+		test_bit(SK_CLOSE, &svsk->sk_flags));
 
-	if (svsk->sk_close) {
+	if (test_bit(SK_CLOSE, &svsk->sk_flags)) {
 		svc_delete_socket(svsk);
 		return 0;
 	}
 
-	if (svsk->sk_conn) {
+	if (test_bit(SK_CONN, &svsk->sk_flags)) {
 		svc_tcp_accept(svsk);
-		svc_sock_accepted(svsk);
+		svc_sock_received(svsk);
 		return 0;
 	}
 
-	ready = svsk->sk_data;
+	clear_bit(SK_DATA, &svsk->sk_flags);
 
 	/* Receive data. If we haven't got the record length yet, get
 	 * the next four bytes. Otherwise try to gobble up as much as
@@ -661,13 +794,17 @@
 			 *  bit set in the fragment length header.
 			 *  But apparently no known nfs clients send fragmented
 			 *  records. */
-			/* FIXME: shutdown socket */
-			printk(KERN_NOTICE "RPC: bad TCP reclen %08lx",
+			printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx (non-terminal)\n",
 			       (unsigned long) svsk->sk_reclen);
-			return -EIO;
+			goto err_delete;
 		}
 		svsk->sk_reclen &= 0x7fffffff;
 		dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
+		if (svsk->sk_reclen > (bufp->buflen<<2)) {
+			printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx (large)\n",
+			       (unsigned long) svsk->sk_reclen);
+			goto err_delete;
+		}
 	}
 
 	/* Check whether enough data is available */
@@ -676,21 +813,12 @@
 		goto error;
 
 	if (len < svsk->sk_reclen) {
-		/* FIXME: if sk_reclen > window-size, then we will
-		 * never be able to receive the record, so should
-		 * shutdown the connection
-		 */
 		dprintk("svc: incomplete TCP record (%d of %d)\n",
 			len, svsk->sk_reclen);
-		svc_sock_received(svsk, ready);
+		svc_sock_received(svsk);
 		return -EAGAIN;	/* record not complete */
 	}
-	/* if we think there is only one more record to read, but
-	 * it is bigger than we expect, then two records must have arrived
-	 * together, so pretend we aren't using the record.. */
-	if (len > svsk->sk_reclen && ready == 1)
-		used = 0;
-	else	used = 1;
+	set_bit(SK_DATA, &svsk->sk_flags);
 
 	/* Frob argbuf */
 	bufp->iov[0].iov_base += 4;
@@ -717,20 +845,24 @@
 	svsk->sk_reclen = 0;
 	svsk->sk_tcplen = 0;
 
-	svc_sock_received(svsk, used);
+	svc_sock_received(svsk);
 	if (serv->sv_stats)
 		serv->sv_stats->nettcpcnt++;
 
 	return len;
 
-error:
+ err_delete:
+	svc_delete_socket(svsk);
+	return -EAGAIN;
+
+ error:
 	if (len == -EAGAIN) {
 		dprintk("RPC: TCP recvfrom got EAGAIN\n");
-		svc_sock_received(svsk, ready); /* Clear data ready */
+		svc_sock_received(svsk);
 	} else {
 		printk(KERN_NOTICE "%s: recvfrom returned errno %d\n",
 					svsk->sk_server->sv_name, -len);
-		svc_sock_received(svsk, 0);
+		svc_sock_received(svsk);
 	}
 
 	return len;
@@ -738,8 +870,6 @@
 
 /*
  * Send out data on TCP socket.
- * FIXME: Make the sendto call non-blocking in order not to hang
- * a daemon on a dead client. Requires write queue maintenance.
  */
 static int
 svc_tcp_sendto(struct svc_rqst *rqstp)
@@ -760,10 +890,8 @@
 		printk(KERN_NOTICE "rpc-srv/tcp: %s: sent only %d bytes of %d - should shutdown socket\n",
 		       rqstp->rq_sock->sk_server->sv_name,
 		       sent, bufp->len << 2);
-		/* FIXME: should shutdown the socket, or allocate more memort
-		 * or wait and try again or something.  Otherwise
-		 * client will get confused
-		 */
+		svc_delete_socket(rqstp->rq_sock);
+		sent = -EAGAIN;
 	}
 	return sent;
 }
@@ -783,21 +911,77 @@
 		dprintk("setting up TCP socket for reading\n");
 		sk->state_change = svc_tcp_state_change;
 		sk->data_ready = svc_tcp_data_ready;
+		sk->write_space = svc_write_space;
 
 		svsk->sk_reclen = 0;
 		svsk->sk_tcplen = 0;
+
+		/* sndbuf needs to have room for one request
+		 * per thread, otherwise we can stall even when the
+		 * network isn't a bottleneck.
+		 * rcvbuf just needs to be able to hold a few requests.
+		 * Normally they will be removed from the queue 
+		 * as soon a a complete request arrives.
+		 */
+		svc_sock_setbufsize(svsk->sk_sock,
+				    svsk->sk_server->sv_nrthreads *
+				    svsk->sk_server->sv_bufsz,
+				    3 * svsk->sk_server->sv_bufsz);
 	}
 
 	return 0;
 }
 
+void
+svc_sock_update_bufs(struct svc_serv *serv)
+{
+	/*
+	 * The number of server threads has changed. Update
+	 * rcvbuf and sndbuf accordingly on all sockets
+	 */
+	struct list_head *le;
+
+	spin_lock_bh(&serv->sv_lock);
+	list_for_each(le, &serv->sv_permsocks) {
+		struct svc_sock *svsk = 
+			list_entry(le, struct svc_sock, sk_list);
+		struct socket *sock = svsk->sk_sock;
+		if (sock->type == SOCK_DGRAM) {
+			/* udp sockets need large rcvbuf as all pending
+			 * requests are still in that buffer.
+			 * As outgoing requests do not wait for an
+			 * ACK, only a moderate sndbuf is needed
+			 */
+			svc_sock_setbufsize(sock,
+					    5 * serv->sv_bufsz,
+					    (serv->sv_nrthreads+2)* serv->sv_bufsz);
+		} else if (svsk->sk_sk->state != TCP_LISTEN) {
+			printk(KERN_ERR "RPC update_bufs: permanent sock neither UDP or TCP_LISTEN\n");
+		}
+	}
+	list_for_each(le, &serv->sv_tempsocks) {
+		struct svc_sock *svsk =
+			list_entry(le, struct svc_sock, sk_list);
+		struct socket *sock = svsk->sk_sock;
+		if (sock->type == SOCK_STREAM) {
+			/* See svc_tcp_init above for rationale on buffer sizes */
+			svc_sock_setbufsize(sock,
+					    serv->sv_nrthreads *
+					    serv->sv_bufsz,
+					    3 * serv->sv_bufsz);
+		} else 
+			printk(KERN_ERR "RPC update_bufs: temp sock not TCP\n");
+	}
+	spin_unlock_bh(&serv->sv_lock);
+}
+
 /*
  * Receive the next request on any socket.
  */
 int
 svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
 {
-	struct svc_sock		*svsk;
+	struct svc_sock		*svsk =NULL;
 	int			len;
 	DECLARE_WAITQUEUE(wait, current);
 
@@ -821,9 +1005,28 @@
 		return -EINTR;
 
 	spin_lock_bh(&serv->sv_lock);
-	if ((svsk = svc_sock_dequeue(serv)) != NULL) {
+	if (!list_empty(&serv->sv_tempsocks)) {
+		svsk = list_entry(serv->sv_tempsocks.next,
+				  struct svc_sock, sk_list);
+		/* apparently the "standard" is that clients close
+		 * idle connections after 5 minutes, servers after
+		 * 6 minutes
+		 *   http://www.connectathon.org/talks96/nfstcp.pdf 
+		 */
+		if (CURRENT_TIME - svsk->sk_lastrecv < 6*60
+		    || test_bit(SK_BUSY, &svsk->sk_flags))
+			svsk = NULL;
+	}
+	if (svsk) {
+		set_bit(SK_BUSY, &svsk->sk_flags);
+		set_bit(SK_CLOSE, &svsk->sk_flags);
+		rqstp->rq_sock = svsk;
+		svsk->sk_inuse++;
+	} else if ((svsk = svc_sock_dequeue(serv)) != NULL) {
 		rqstp->rq_sock = svsk;
 		svsk->sk_inuse++;
+		rqstp->rq_reserved = serv->sv_bufsz;	
+		svsk->sk_reserved += rqstp->rq_reserved;
 	} else {
 		/* No data pending. Go to sleep */
 		svc_serv_enqueue(serv, rqstp);
@@ -860,6 +1063,14 @@
 		svc_sock_release(rqstp);
 		return -EAGAIN;
 	}
+	svsk->sk_lastrecv = CURRENT_TIME;
+	if (test_bit(SK_TEMP, &svsk->sk_flags)) {
+		/* push active sockets to end of list */
+		spin_lock_bh(&serv->sv_lock);
+		list_del(&svsk->sk_list);
+		list_add_tail(&svsk->sk_list, &serv->sv_tempsocks);
+		spin_unlock_bh(&serv->sv_lock);
+	}
 
 	rqstp->rq_secure  = ntohs(rqstp->rq_addr.sin_port) < 1024;
 	rqstp->rq_userset = 0;
@@ -936,8 +1147,9 @@
 	svsk->sk_sk = inet;
 	svsk->sk_ostate = inet->state_change;
 	svsk->sk_odata = inet->data_ready;
+	svsk->sk_owspace = inet->write_space;
 	svsk->sk_server = serv;
-	spin_lock_init(&svsk->sk_lock);
+	svsk->sk_lastrecv = CURRENT_TIME;
 
 	/* Initialize the socket */
 	if (sock->type == SOCK_DGRAM)
@@ -957,9 +1169,16 @@
 		return NULL;
 	}
 
+
 	spin_lock_bh(&serv->sv_lock);
-	svsk->sk_list = serv->sv_allsocks;
-	serv->sv_allsocks = svsk;
+	if (!pmap_register) {
+		set_bit(SK_TEMP, &svsk->sk_flags);
+		list_add(&svsk->sk_list, &serv->sv_tempsocks);
+		serv->sv_tmpcnt++;
+	} else {
+		clear_bit(SK_TEMP, &svsk->sk_flags);
+		list_add(&svsk->sk_list, &serv->sv_permsocks);
+	}
 	spin_unlock_bh(&serv->sv_lock);
 
 	dprintk("svc: svc_setup_socket created %p (inet %p)\n",
@@ -1020,7 +1239,6 @@
 void
 svc_delete_socket(struct svc_sock *svsk)
 {
-	struct svc_sock	**rsk;
 	struct svc_serv	*serv;
 	struct sock	*sk;
 
@@ -1031,23 +1249,18 @@
 
 	sk->state_change = svsk->sk_ostate;
 	sk->data_ready = svsk->sk_odata;
+	sk->write_space = svsk->sk_owspace;
 
 	spin_lock_bh(&serv->sv_lock);
 
-	for (rsk = &serv->sv_allsocks; *rsk; rsk = &(*rsk)->sk_list) {
-		if (*rsk == svsk)
-			break;
-	}
-	if (!*rsk) {
-		spin_unlock_bh(&serv->sv_lock);
-		return;
-	}
-	*rsk = svsk->sk_list;
-	if (svsk->sk_qued)
-		rpc_remove_list(&serv->sv_sockets, svsk);
+	list_del(&svsk->sk_list);
+	if (test_bit(SK_TEMP, &svsk->sk_flags))
+		serv->sv_tmpcnt--;
+	if (test_bit(SK_QUED, &svsk->sk_flags))
+		list_del(&svsk->sk_ready);
 
 
-	svsk->sk_dead = 1;
+	set_bit(SK_DEAD, &svsk->sk_flags);
 
 	if (!svsk->sk_inuse) {
 		spin_unlock_bh(&serv->sv_lock);
diff -urN linux-2.5.6-pre1/net/sunrpc/xprt.c linux-2.5.6-pre2/net/sunrpc/xprt.c
--- linux-2.5.6-pre1/net/sunrpc/xprt.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6-pre2/net/sunrpc/xprt.c	Thu Feb 28 13:34:25 2002
@@ -542,25 +542,15 @@
 static inline struct rpc_rqst *
 xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid)
 {
-	struct rpc_task	*head, *task;
 	struct rpc_rqst	*req;
-	int		safe = 0;
+	struct list_head *le;
+	struct rpc_task *task;
 
 	spin_lock_bh(&rpc_queue_lock);
-	if ((head = xprt->pending.task) != NULL) {
-		task = head;
-		do {
-			if ((req = task->tk_rqstp) && req->rq_xid == xid)
-				goto out;
-			task = task->tk_next;
-			if (++safe > 100) {
-				printk("xprt_lookup_rqst: loop in Q!\n");
-				goto out_bad;
-			}
-		} while (task != head);
-	}
+	task_for_each(task, le, &xprt->pending.tasks)
+		if ((req = task->tk_rqstp) && req->rq_xid == xid)
+			goto out;
 	dprintk("RPC:      unknown XID %08x in reply.\n", xid);
- out_bad:
 	req = NULL;
  out:
 	if (req && !__rpc_lock_task(req->rq_task))
@@ -1487,9 +1477,9 @@
 	} else
 		xprt_default_timeout(&xprt->timeout, xprt->prot);
 
-	xprt->pending = RPC_INIT_WAITQ("xprt_pending");
-	xprt->sending = RPC_INIT_WAITQ("xprt_sending");
-	xprt->backlog = RPC_INIT_WAITQ("xprt_backlog");
+	INIT_RPC_WAITQ(&xprt->pending, "xprt_pending");
+	INIT_RPC_WAITQ(&xprt->sending, "xprt_sending");
+	INIT_RPC_WAITQ(&xprt->backlog, "xprt_backlog");
 
 	/* initialize free list */
 	for (i = 0, req = xprt->slot; i < RPC_MAXREQS-1; i++, req++)
